UNPKG

1.5 MBJavaScriptView Raw
1(function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3 typeof define === 'function' && define.amd ? define(['exports'], factory) :
4 (factory((global.turf = {})));
5}(this, (function (exports) { 'use strict';
6
7/**
8 * Earth Radius used with the Harvesine formula and approximates using a spherical (non-ellipsoid) Earth.
9 */
10var earthRadius = 6371008.8;
11
12/**
13 * Unit of measurement factors using a spherical (non-ellipsoid) earth radius.
14 */
15var factors = {
16 meters: earthRadius,
17 metres: earthRadius,
18 millimeters: earthRadius * 1000,
19 millimetres: earthRadius * 1000,
20 centimeters: earthRadius * 100,
21 centimetres: earthRadius * 100,
22 kilometers: earthRadius / 1000,
23 kilometres: earthRadius / 1000,
24 miles: earthRadius / 1609.344,
25 nauticalmiles: earthRadius / 1852,
26 inches: earthRadius * 39.370,
27 yards: earthRadius / 1.0936,
28 feet: earthRadius * 3.28084,
29 radians: 1,
30 degrees: earthRadius / 111325,
31};
32
33/**
34 * Units of measurement factors based on 1 meter.
35 */
36var unitsFactors = {
37 meters: 1,
38 metres: 1,
39 millimeters: 1000,
40 millimetres: 1000,
41 centimeters: 100,
42 centimetres: 100,
43 kilometers: 1 / 1000,
44 kilometres: 1 / 1000,
45 miles: 1 / 1609.344,
46 nauticalmiles: 1 / 1852,
47 inches: 39.370,
48 yards: 1 / 1.0936,
49 feet: 3.28084,
50 radians: 1 / earthRadius,
51 degrees: 1 / 111325,
52};
53
54/**
55 * Area of measurement factors based on 1 square meter.
56 */
57var areaFactors = {
58 meters: 1,
59 metres: 1,
60 millimeters: 1000000,
61 millimetres: 1000000,
62 centimeters: 10000,
63 centimetres: 10000,
64 kilometers: 0.000001,
65 kilometres: 0.000001,
66 acres: 0.000247105,
67 miles: 3.86e-7,
68 yards: 1.195990046,
69 feet: 10.763910417,
70 inches: 1550.003100006
71};
72
73/**
74 * Wraps a GeoJSON {@link Geometry} in a GeoJSON {@link Feature}.
75 *
76 * @name feature
77 * @param {Geometry} geometry input geometry
78 * @param {Object} [properties={}] an Object of key-value pairs to add as properties
79 * @param {Object} [options={}] Optional Parameters
80 * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
81 * @param {string|number} [options.id] Identifier associated with the Feature
82 * @returns {Feature} a GeoJSON Feature
83 * @example
84 * var geometry = {
85 * "type": "Point",
86 * "coordinates": [110, 50]
87 * };
88 *
89 * var feature = turf.feature(geometry);
90 *
91 * //=feature
92 */
93function feature(geometry, properties, options) {
94 // Optional Parameters
95 options = options || {};
96 if (!isObject(options)) throw new Error('options is invalid');
97 var bbox = options.bbox;
98 var id = options.id;
99
100 // Validation
101 if (geometry === undefined) throw new Error('geometry is required');
102 if (properties && properties.constructor !== Object) throw new Error('properties must be an Object');
103 if (bbox) validateBBox(bbox);
104 if (id) validateId(id);
105
106 // Main
107 var feat = {type: 'Feature'};
108 if (id) feat.id = id;
109 if (bbox) feat.bbox = bbox;
110 feat.properties = properties || {};
111 feat.geometry = geometry;
112 return feat;
113}
114
115/**
116 * Creates a GeoJSON {@link Geometry} from a Geometry string type & coordinates.
117 * For GeometryCollection type use `helpers.geometryCollection`
118 *
119 * @name geometry
120 * @param {string} type Geometry Type
121 * @param {Array<number>} coordinates Coordinates
122 * @param {Object} [options={}] Optional Parameters
123 * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Geometry
124 * @returns {Geometry} a GeoJSON Geometry
125 * @example
126 * var type = 'Point';
127 * var coordinates = [110, 50];
128 *
129 * var geometry = turf.geometry(type, coordinates);
130 *
131 * //=geometry
132 */
133function geometry(type, coordinates, options) {
134 // Optional Parameters
135 options = options || {};
136 if (!isObject(options)) throw new Error('options is invalid');
137 var bbox = options.bbox;
138
139 // Validation
140 if (!type) throw new Error('type is required');
141 if (!coordinates) throw new Error('coordinates is required');
142 if (!Array.isArray(coordinates)) throw new Error('coordinates must be an Array');
143 if (bbox) validateBBox(bbox);
144
145 // Main
146 var geom;
147 switch (type) {
148 case 'Point': geom = point(coordinates).geometry; break;
149 case 'LineString': geom = lineString(coordinates).geometry; break;
150 case 'Polygon': geom = polygon(coordinates).geometry; break;
151 case 'MultiPoint': geom = multiPoint(coordinates).geometry; break;
152 case 'MultiLineString': geom = multiLineString(coordinates).geometry; break;
153 case 'MultiPolygon': geom = multiPolygon(coordinates).geometry; break;
154 default: throw new Error(type + ' is invalid');
155 }
156 if (bbox) geom.bbox = bbox;
157 return geom;
158}
159
160/**
161 * Creates a {@link Point} {@link Feature} from a Position.
162 *
163 * @name point
164 * @param {Array<number>} coordinates longitude, latitude position (each in decimal degrees)
165 * @param {Object} [properties={}] an Object of key-value pairs to add as properties
166 * @param {Object} [options={}] Optional Parameters
167 * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
168 * @param {string|number} [options.id] Identifier associated with the Feature
169 * @returns {Feature<Point>} a Point feature
170 * @example
171 * var point = turf.point([-75.343, 39.984]);
172 *
173 * //=point
174 */
175function point(coordinates, properties, options) {
176 if (!coordinates) throw new Error('coordinates is required');
177 if (!Array.isArray(coordinates)) throw new Error('coordinates must be an Array');
178 if (coordinates.length < 2) throw new Error('coordinates must be at least 2 numbers long');
179 if (!isNumber(coordinates[0]) || !isNumber(coordinates[1])) throw new Error('coordinates must contain numbers');
180
181 return feature({
182 type: 'Point',
183 coordinates: coordinates
184 }, properties, options);
185}
186
187/**
188 * Creates a {@link Point} {@link FeatureCollection} from an Array of Point coordinates.
189 *
190 * @name points
191 * @param {Array<Array<number>>} coordinates an array of Points
192 * @param {Object} [properties={}] Translate these properties to each Feature
193 * @param {Object} [options={}] Optional Parameters
194 * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the FeatureCollection
195 * @param {string|number} [options.id] Identifier associated with the FeatureCollection
196 * @returns {FeatureCollection<Point>} Point Feature
197 * @example
198 * var points = turf.points([
199 * [-75, 39],
200 * [-80, 45],
201 * [-78, 50]
202 * ]);
203 *
204 * //=points
205 */
206function points(coordinates, properties, options) {
207 if (!coordinates) throw new Error('coordinates is required');
208 if (!Array.isArray(coordinates)) throw new Error('coordinates must be an Array');
209
210 return featureCollection(coordinates.map(function (coords) {
211 return point(coords, properties);
212 }), options);
213}
214
215/**
216 * Creates a {@link Polygon} {@link Feature} from an Array of LinearRings.
217 *
218 * @name polygon
219 * @param {Array<Array<Array<number>>>} coordinates an array of LinearRings
220 * @param {Object} [properties={}] an Object of key-value pairs to add as properties
221 * @param {Object} [options={}] Optional Parameters
222 * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
223 * @param {string|number} [options.id] Identifier associated with the Feature
224 * @returns {Feature<Polygon>} Polygon Feature
225 * @example
226 * var polygon = turf.polygon([[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]], { name: 'poly1' });
227 *
228 * //=polygon
229 */
230function polygon(coordinates, properties, options) {
231 if (!coordinates) throw new Error('coordinates is required');
232
233 for (var i = 0; i < coordinates.length; i++) {
234 var ring = coordinates[i];
235 if (ring.length < 4) {
236 throw new Error('Each LinearRing of a Polygon must have 4 or more Positions.');
237 }
238 for (var j = 0; j < ring[ring.length - 1].length; j++) {
239 // Check if first point of Polygon contains two numbers
240 if (i === 0 && j === 0 && !isNumber(ring[0][0]) || !isNumber(ring[0][1])) throw new Error('coordinates must contain numbers');
241 if (ring[ring.length - 1][j] !== ring[0][j]) {
242 throw new Error('First and last Position are not equivalent.');
243 }
244 }
245 }
246
247 return feature({
248 type: 'Polygon',
249 coordinates: coordinates
250 }, properties, options);
251}
252
253/**
254 * Creates a {@link Polygon} {@link FeatureCollection} from an Array of Polygon coordinates.
255 *
256 * @name polygons
257 * @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygon coordinates
258 * @param {Object} [properties={}] an Object of key-value pairs to add as properties
259 * @param {Object} [options={}] Optional Parameters
260 * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
261 * @param {string|number} [options.id] Identifier associated with the FeatureCollection
262 * @returns {FeatureCollection<Polygon>} Polygon FeatureCollection
263 * @example
264 * var polygons = turf.polygons([
265 * [[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]],
266 * [[[-15, 42], [-14, 46], [-12, 41], [-17, 44], [-15, 42]]],
267 * ]);
268 *
269 * //=polygons
270 */
271function polygons(coordinates, properties, options) {
272 if (!coordinates) throw new Error('coordinates is required');
273 if (!Array.isArray(coordinates)) throw new Error('coordinates must be an Array');
274
275 return featureCollection(coordinates.map(function (coords) {
276 return polygon(coords, properties);
277 }), options);
278}
279
280/**
281 * Creates a {@link LineString} {@link Feature} from an Array of Positions.
282 *
283 * @name lineString
284 * @param {Array<Array<number>>} coordinates an array of Positions
285 * @param {Object} [properties={}] an Object of key-value pairs to add as properties
286 * @param {Object} [options={}] Optional Parameters
287 * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
288 * @param {string|number} [options.id] Identifier associated with the Feature
289 * @returns {Feature<LineString>} LineString Feature
290 * @example
291 * var linestring1 = turf.lineString([[-24, 63], [-23, 60], [-25, 65], [-20, 69]], {name: 'line 1'});
292 * var linestring2 = turf.lineString([[-14, 43], [-13, 40], [-15, 45], [-10, 49]], {name: 'line 2'});
293 *
294 * //=linestring1
295 * //=linestring2
296 */
297function lineString(coordinates, properties, options) {
298 if (!coordinates) throw new Error('coordinates is required');
299 if (coordinates.length < 2) throw new Error('coordinates must be an array of two or more positions');
300 // Check if first point of LineString contains two numbers
301 if (!isNumber(coordinates[0][1]) || !isNumber(coordinates[0][1])) throw new Error('coordinates must contain numbers');
302
303 return feature({
304 type: 'LineString',
305 coordinates: coordinates
306 }, properties, options);
307}
308
309/**
310 * Creates a {@link LineString} {@link FeatureCollection} from an Array of LineString coordinates.
311 *
312 * @name lineStrings
313 * @param {Array<Array<number>>} coordinates an array of LinearRings
314 * @param {Object} [properties={}] an Object of key-value pairs to add as properties
315 * @param {Object} [options={}] Optional Parameters
316 * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the FeatureCollection
317 * @param {string|number} [options.id] Identifier associated with the FeatureCollection
318 * @returns {FeatureCollection<LineString>} LineString FeatureCollection
319 * @example
320 * var linestrings = turf.lineStrings([
321 * [[-24, 63], [-23, 60], [-25, 65], [-20, 69]],
322 * [[-14, 43], [-13, 40], [-15, 45], [-10, 49]]
323 * ]);
324 *
325 * //=linestrings
326 */
327function lineStrings(coordinates, properties, options) {
328 if (!coordinates) throw new Error('coordinates is required');
329 if (!Array.isArray(coordinates)) throw new Error('coordinates must be an Array');
330
331 return featureCollection(coordinates.map(function (coords) {
332 return lineString(coords, properties);
333 }), options);
334}
335
336/**
337 * Takes one or more {@link Feature|Features} and creates a {@link FeatureCollection}.
338 *
339 * @name featureCollection
340 * @param {Feature[]} features input features
341 * @param {Object} [options={}] Optional Parameters
342 * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
343 * @param {string|number} [options.id] Identifier associated with the Feature
344 * @returns {FeatureCollection} FeatureCollection of Features
345 * @example
346 * var locationA = turf.point([-75.343, 39.984], {name: 'Location A'});
347 * var locationB = turf.point([-75.833, 39.284], {name: 'Location B'});
348 * var locationC = turf.point([-75.534, 39.123], {name: 'Location C'});
349 *
350 * var collection = turf.featureCollection([
351 * locationA,
352 * locationB,
353 * locationC
354 * ]);
355 *
356 * //=collection
357 */
358function featureCollection(features, options) {
359 // Optional Parameters
360 options = options || {};
361 if (!isObject(options)) throw new Error('options is invalid');
362 var bbox = options.bbox;
363 var id = options.id;
364
365 // Validation
366 if (!features) throw new Error('No features passed');
367 if (!Array.isArray(features)) throw new Error('features must be an Array');
368 if (bbox) validateBBox(bbox);
369 if (id) validateId(id);
370
371 // Main
372 var fc = {type: 'FeatureCollection'};
373 if (id) fc.id = id;
374 if (bbox) fc.bbox = bbox;
375 fc.features = features;
376 return fc;
377}
378
379/**
380 * Creates a {@link Feature<MultiLineString>} based on a
381 * coordinate array. Properties can be added optionally.
382 *
383 * @name multiLineString
384 * @param {Array<Array<Array<number>>>} coordinates an array of LineStrings
385 * @param {Object} [properties={}] an Object of key-value pairs to add as properties
386 * @param {Object} [options={}] Optional Parameters
387 * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
388 * @param {string|number} [options.id] Identifier associated with the Feature
389 * @returns {Feature<MultiLineString>} a MultiLineString feature
390 * @throws {Error} if no coordinates are passed
391 * @example
392 * var multiLine = turf.multiLineString([[[0,0],[10,10]]]);
393 *
394 * //=multiLine
395 */
396function multiLineString(coordinates, properties, options) {
397 if (!coordinates) throw new Error('coordinates is required');
398
399 return feature({
400 type: 'MultiLineString',
401 coordinates: coordinates
402 }, properties, options);
403}
404
405/**
406 * Creates a {@link Feature<MultiPoint>} based on a
407 * coordinate array. Properties can be added optionally.
408 *
409 * @name multiPoint
410 * @param {Array<Array<number>>} coordinates an array of Positions
411 * @param {Object} [properties={}] an Object of key-value pairs to add as properties
412 * @param {Object} [options={}] Optional Parameters
413 * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
414 * @param {string|number} [options.id] Identifier associated with the Feature
415 * @returns {Feature<MultiPoint>} a MultiPoint feature
416 * @throws {Error} if no coordinates are passed
417 * @example
418 * var multiPt = turf.multiPoint([[0,0],[10,10]]);
419 *
420 * //=multiPt
421 */
422function multiPoint(coordinates, properties, options) {
423 if (!coordinates) throw new Error('coordinates is required');
424
425 return feature({
426 type: 'MultiPoint',
427 coordinates: coordinates
428 }, properties, options);
429}
430
431/**
432 * Creates a {@link Feature<MultiPolygon>} based on a
433 * coordinate array. Properties can be added optionally.
434 *
435 * @name multiPolygon
436 * @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygons
437 * @param {Object} [properties={}] an Object of key-value pairs to add as properties
438 * @param {Object} [options={}] Optional Parameters
439 * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
440 * @param {string|number} [options.id] Identifier associated with the Feature
441 * @returns {Feature<MultiPolygon>} a multipolygon feature
442 * @throws {Error} if no coordinates are passed
443 * @example
444 * var multiPoly = turf.multiPolygon([[[[0,0],[0,10],[10,10],[10,0],[0,0]]]]);
445 *
446 * //=multiPoly
447 *
448 */
449function multiPolygon(coordinates, properties, options) {
450 if (!coordinates) throw new Error('coordinates is required');
451
452 return feature({
453 type: 'MultiPolygon',
454 coordinates: coordinates
455 }, properties, options);
456}
457
458/**
459 * Creates a {@link Feature<GeometryCollection>} based on a
460 * coordinate array. Properties can be added optionally.
461 *
462 * @name geometryCollection
463 * @param {Array<Geometry>} geometries an array of GeoJSON Geometries
464 * @param {Object} [properties={}] an Object of key-value pairs to add as properties
465 * @param {Object} [options={}] Optional Parameters
466 * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
467 * @param {string|number} [options.id] Identifier associated with the Feature
468 * @returns {Feature<GeometryCollection>} a GeoJSON GeometryCollection Feature
469 * @example
470 * var pt = {
471 * "type": "Point",
472 * "coordinates": [100, 0]
473 * };
474 * var line = {
475 * "type": "LineString",
476 * "coordinates": [ [101, 0], [102, 1] ]
477 * };
478 * var collection = turf.geometryCollection([pt, line]);
479 *
480 * //=collection
481 */
482function geometryCollection(geometries, properties, options) {
483 if (!geometries) throw new Error('geometries is required');
484 if (!Array.isArray(geometries)) throw new Error('geometries must be an Array');
485
486 return feature({
487 type: 'GeometryCollection',
488 geometries: geometries
489 }, properties, options);
490}
491
492/**
493 * Round number to precision
494 *
495 * @param {number} num Number
496 * @param {number} [precision=0] Precision
497 * @returns {number} rounded number
498 * @example
499 * turf.round(120.4321)
500 * //=120
501 *
502 * turf.round(120.4321, 2)
503 * //=120.43
504 */
505function round(num, precision) {
506 if (num === undefined || num === null || isNaN(num)) throw new Error('num is required');
507 if (precision && !(precision >= 0)) throw new Error('precision must be a positive number');
508 var multiplier = Math.pow(10, precision || 0);
509 return Math.round(num * multiplier) / multiplier;
510}
511
512/**
513 * Convert a distance measurement (assuming a spherical Earth) from radians to a more friendly unit.
514 * Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
515 *
516 * @name radiansToLength
517 * @param {number} radians in radians across the sphere
518 * @param {string} [units='kilometers'] can be degrees, radians, miles, or kilometers inches, yards, metres, meters, kilometres, kilometers.
519 * @returns {number} distance
520 */
521function radiansToLength(radians, units) {
522 if (radians === undefined || radians === null) throw new Error('radians is required');
523
524 if (units && typeof units !== 'string') throw new Error('units must be a string');
525 var factor = factors[units || 'kilometers'];
526 if (!factor) throw new Error(units + ' units is invalid');
527 return radians * factor;
528}
529
530/**
531 * Convert a distance measurement (assuming a spherical Earth) from a real-world unit into radians
532 * Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
533 *
534 * @name lengthToRadians
535 * @param {number} distance in real units
536 * @param {string} [units='kilometers'] can be degrees, radians, miles, or kilometers inches, yards, metres, meters, kilometres, kilometers.
537 * @returns {number} radians
538 */
539function lengthToRadians(distance, units) {
540 if (distance === undefined || distance === null) throw new Error('distance is required');
541
542 if (units && typeof units !== 'string') throw new Error('units must be a string');
543 var factor = factors[units || 'kilometers'];
544 if (!factor) throw new Error(units + ' units is invalid');
545 return distance / factor;
546}
547
548/**
549 * Convert a distance measurement (assuming a spherical Earth) from a real-world unit into degrees
550 * Valid units: miles, nauticalmiles, inches, yards, meters, metres, centimeters, kilometres, feet
551 *
552 * @name lengthToDegrees
553 * @param {number} distance in real units
554 * @param {string} [units='kilometers'] can be degrees, radians, miles, or kilometers inches, yards, metres, meters, kilometres, kilometers.
555 * @returns {number} degrees
556 */
557function lengthToDegrees(distance, units) {
558 return radiansToDegrees(lengthToRadians(distance, units));
559}
560
561/**
562 * Converts any bearing angle from the north line direction (positive clockwise)
563 * and returns an angle between 0-360 degrees (positive clockwise), 0 being the north line
564 *
565 * @name bearingToAzimuth
566 * @param {number} bearing angle, between -180 and +180 degrees
567 * @returns {number} angle between 0 and 360 degrees
568 */
569function bearingToAzimuth(bearing) {
570 if (bearing === null || bearing === undefined) throw new Error('bearing is required');
571
572 var angle = bearing % 360;
573 if (angle < 0) angle += 360;
574 return angle;
575}
576
577/**
578 * Converts an angle in radians to degrees
579 *
580 * @name radiansToDegrees
581 * @param {number} radians angle in radians
582 * @returns {number} degrees between 0 and 360 degrees
583 */
584function radiansToDegrees(radians) {
585 if (radians === null || radians === undefined) throw new Error('radians is required');
586
587 var degrees = radians % (2 * Math.PI);
588 return degrees * 180 / Math.PI;
589}
590
591/**
592 * Converts an angle in degrees to radians
593 *
594 * @name degreesToRadians
595 * @param {number} degrees angle between 0 and 360 degrees
596 * @returns {number} angle in radians
597 */
598function degreesToRadians(degrees) {
599 if (degrees === null || degrees === undefined) throw new Error('degrees is required');
600
601 var radians = degrees % 360;
602 return radians * Math.PI / 180;
603}
604
605/**
606 * Converts a length to the requested unit.
607 * Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
608 *
609 * @param {number} length to be converted
610 * @param {string} originalUnit of the length
611 * @param {string} [finalUnit='kilometers'] returned unit
612 * @returns {number} the converted length
613 */
614function convertLength(length, originalUnit, finalUnit) {
615 if (length === null || length === undefined) throw new Error('length is required');
616 if (!(length >= 0)) throw new Error('length must be a positive number');
617
618 return radiansToLength(lengthToRadians(length, originalUnit), finalUnit || 'kilometers');
619}
620
621/**
622 * Converts a area to the requested unit.
623 * Valid units: kilometers, kilometres, meters, metres, centimetres, millimeters, acres, miles, yards, feet, inches
624 * @param {number} area to be converted
625 * @param {string} [originalUnit='meters'] of the distance
626 * @param {string} [finalUnit='kilometers'] returned unit
627 * @returns {number} the converted distance
628 */
629function convertArea(area, originalUnit, finalUnit) {
630 if (area === null || area === undefined) throw new Error('area is required');
631 if (!(area >= 0)) throw new Error('area must be a positive number');
632
633 var startFactor = areaFactors[originalUnit || 'meters'];
634 if (!startFactor) throw new Error('invalid original units');
635
636 var finalFactor = areaFactors[finalUnit || 'kilometers'];
637 if (!finalFactor) throw new Error('invalid final units');
638
639 return (area / startFactor) * finalFactor;
640}
641
642/**
643 * isNumber
644 *
645 * @param {*} num Number to validate
646 * @returns {boolean} true/false
647 * @example
648 * turf.isNumber(123)
649 * //=true
650 * turf.isNumber('foo')
651 * //=false
652 */
653function isNumber(num) {
654 return !isNaN(num) && num !== null && !Array.isArray(num);
655}
656
657/**
658 * isObject
659 *
660 * @param {*} input variable to validate
661 * @returns {boolean} true/false
662 * @example
663 * turf.isObject({elevation: 10})
664 * //=true
665 * turf.isObject('foo')
666 * //=false
667 */
668function isObject(input) {
669 return (!!input) && (input.constructor === Object);
670}
671
672/**
673 * Validate BBox
674 *
675 * @private
676 * @param {Array<number>} bbox BBox to validate
677 * @returns {void}
678 * @throws Error if BBox is not valid
679 * @example
680 * validateBBox([-180, -40, 110, 50])
681 * //=OK
682 * validateBBox([-180, -40])
683 * //=Error
684 * validateBBox('Foo')
685 * //=Error
686 * validateBBox(5)
687 * //=Error
688 * validateBBox(null)
689 * //=Error
690 * validateBBox(undefined)
691 * //=Error
692 */
693function validateBBox(bbox) {
694 if (!bbox) throw new Error('bbox is required');
695 if (!Array.isArray(bbox)) throw new Error('bbox must be an Array');
696 if (bbox.length !== 4 && bbox.length !== 6) throw new Error('bbox must be an Array of 4 or 6 numbers');
697 bbox.forEach(function (num) {
698 if (!isNumber(num)) throw new Error('bbox must only contain numbers');
699 });
700}
701
702/**
703 * Validate Id
704 *
705 * @private
706 * @param {string|number} id Id to validate
707 * @returns {void}
708 * @throws Error if Id is not valid
709 * @example
710 * validateId([-180, -40, 110, 50])
711 * //=Error
712 * validateId([-180, -40])
713 * //=Error
714 * validateId('Foo')
715 * //=OK
716 * validateId(5)
717 * //=OK
718 * validateId(null)
719 * //=Error
720 * validateId(undefined)
721 * //=Error
722 */
723function validateId(id) {
724 if (!id) throw new Error('id is required');
725 if (['string', 'number'].indexOf(typeof id) === -1) throw new Error('id must be a number or a string');
726}
727
728// Deprecated methods
729function radians2degrees() {
730 throw new Error('method has been renamed to `radiansToDegrees`');
731}
732
733function degrees2radians() {
734 throw new Error('method has been renamed to `degreesToRadians`');
735}
736
737function distanceToDegrees() {
738 throw new Error('method has been renamed to `lengthToDegrees`');
739}
740
741function distanceToRadians() {
742 throw new Error('method has been renamed to `lengthToRadians`');
743}
744
745function radiansToDistance() {
746 throw new Error('method has been renamed to `radiansToLength`');
747}
748
749function bearingToAngle() {
750 throw new Error('method has been renamed to `bearingToAzimuth`');
751}
752
753function convertDistance() {
754 throw new Error('method has been renamed to `convertLength`');
755}
756
757
758
759
760var main_es$1 = Object.freeze({
761 earthRadius: earthRadius,
762 factors: factors,
763 unitsFactors: unitsFactors,
764 areaFactors: areaFactors,
765 feature: feature,
766 geometry: geometry,
767 point: point,
768 points: points,
769 polygon: polygon,
770 polygons: polygons,
771 lineString: lineString,
772 lineStrings: lineStrings,
773 featureCollection: featureCollection,
774 multiLineString: multiLineString,
775 multiPoint: multiPoint,
776 multiPolygon: multiPolygon,
777 geometryCollection: geometryCollection,
778 round: round,
779 radiansToLength: radiansToLength,
780 lengthToRadians: lengthToRadians,
781 lengthToDegrees: lengthToDegrees,
782 bearingToAzimuth: bearingToAzimuth,
783 radiansToDegrees: radiansToDegrees,
784 degreesToRadians: degreesToRadians,
785 convertLength: convertLength,
786 convertArea: convertArea,
787 isNumber: isNumber,
788 isObject: isObject,
789 validateBBox: validateBBox,
790 validateId: validateId,
791 radians2degrees: radians2degrees,
792 degrees2radians: degrees2radians,
793 distanceToDegrees: distanceToDegrees,
794 distanceToRadians: distanceToRadians,
795 radiansToDistance: radiansToDistance,
796 bearingToAngle: bearingToAngle,
797 convertDistance: convertDistance
798});
799
800/**
801 * Callback for coordEach
802 *
803 * @callback coordEachCallback
804 * @param {Array<number>} currentCoord The current coordinate being processed.
805 * @param {number} coordIndex The current index of the coordinate being processed.
806 * @param {number} featureIndex The current index of the Feature being processed.
807 * @param {number} multiFeatureIndex The current index of the Multi-Feature being processed.
808 * @param {number} geometryIndex The current index of the Geometry being processed.
809 */
810
811/**
812 * Iterate over coordinates in any GeoJSON object, similar to Array.forEach()
813 *
814 * @name coordEach
815 * @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
816 * @param {Function} callback a method that takes (currentCoord, coordIndex, featureIndex, multiFeatureIndex)
817 * @param {boolean} [excludeWrapCoord=false] whether or not to include the final coordinate of LinearRings that wraps the ring in its iteration.
818 * @example
819 * var features = turf.featureCollection([
820 * turf.point([26, 37], {"foo": "bar"}),
821 * turf.point([36, 53], {"hello": "world"})
822 * ]);
823 *
824 * turf.coordEach(features, function (currentCoord, coordIndex, featureIndex, multiFeatureIndex, geometryIndex) {
825 * //=currentCoord
826 * //=coordIndex
827 * //=featureIndex
828 * //=multiFeatureIndex
829 * //=geometryIndex
830 * });
831 */
832function coordEach(geojson, callback, excludeWrapCoord) {
833 // Handles null Geometry -- Skips this GeoJSON
834 if (geojson === null) return;
835 var j, k, l, geometry$$1, stopG, coords,
836 geometryMaybeCollection,
837 wrapShrink = 0,
838 coordIndex = 0,
839 isGeometryCollection,
840 type = geojson.type,
841 isFeatureCollection = type === 'FeatureCollection',
842 isFeature = type === 'Feature',
843 stop = isFeatureCollection ? geojson.features.length : 1;
844
845 // This logic may look a little weird. The reason why it is that way
846 // is because it's trying to be fast. GeoJSON supports multiple kinds
847 // of objects at its root: FeatureCollection, Features, Geometries.
848 // This function has the responsibility of handling all of them, and that
849 // means that some of the `for` loops you see below actually just don't apply
850 // to certain inputs. For instance, if you give this just a
851 // Point geometry, then both loops are short-circuited and all we do
852 // is gradually rename the input until it's called 'geometry'.
853 //
854 // This also aims to allocate as few resources as possible: just a
855 // few numbers and booleans, rather than any temporary arrays as would
856 // be required with the normalization approach.
857 for (var featureIndex = 0; featureIndex < stop; featureIndex++) {
858 geometryMaybeCollection = (isFeatureCollection ? geojson.features[featureIndex].geometry :
859 (isFeature ? geojson.geometry : geojson));
860 isGeometryCollection = (geometryMaybeCollection) ? geometryMaybeCollection.type === 'GeometryCollection' : false;
861 stopG = isGeometryCollection ? geometryMaybeCollection.geometries.length : 1;
862
863 for (var geomIndex = 0; geomIndex < stopG; geomIndex++) {
864 var multiFeatureIndex = 0;
865 var geometryIndex = 0;
866 geometry$$1 = isGeometryCollection ?
867 geometryMaybeCollection.geometries[geomIndex] : geometryMaybeCollection;
868
869 // Handles null Geometry -- Skips this geometry
870 if (geometry$$1 === null) continue;
871 coords = geometry$$1.coordinates;
872 var geomType = geometry$$1.type;
873
874 wrapShrink = (excludeWrapCoord && (geomType === 'Polygon' || geomType === 'MultiPolygon')) ? 1 : 0;
875
876 switch (geomType) {
877 case null:
878 break;
879 case 'Point':
880 callback(coords, coordIndex, featureIndex, multiFeatureIndex, geometryIndex);
881 coordIndex++;
882 multiFeatureIndex++;
883 break;
884 case 'LineString':
885 case 'MultiPoint':
886 for (j = 0; j < coords.length; j++) {
887 callback(coords[j], coordIndex, featureIndex, multiFeatureIndex, geometryIndex);
888 coordIndex++;
889 if (geomType === 'MultiPoint') multiFeatureIndex++;
890 }
891 if (geomType === 'LineString') multiFeatureIndex++;
892 break;
893 case 'Polygon':
894 case 'MultiLineString':
895 for (j = 0; j < coords.length; j++) {
896 for (k = 0; k < coords[j].length - wrapShrink; k++) {
897 callback(coords[j][k], coordIndex, featureIndex, multiFeatureIndex, geometryIndex);
898 coordIndex++;
899 }
900 if (geomType === 'MultiLineString') multiFeatureIndex++;
901 if (geomType === 'Polygon') geometryIndex++;
902 }
903 if (geomType === 'Polygon') multiFeatureIndex++;
904 break;
905 case 'MultiPolygon':
906 for (j = 0; j < coords.length; j++) {
907 if (geomType === 'MultiPolygon') geometryIndex = 0;
908 for (k = 0; k < coords[j].length; k++) {
909 for (l = 0; l < coords[j][k].length - wrapShrink; l++) {
910 callback(coords[j][k][l], coordIndex, featureIndex, multiFeatureIndex, geometryIndex);
911 coordIndex++;
912 }
913 geometryIndex++;
914 }
915 multiFeatureIndex++;
916 }
917 break;
918 case 'GeometryCollection':
919 for (j = 0; j < geometry$$1.geometries.length; j++)
920 coordEach(geometry$$1.geometries[j], callback, excludeWrapCoord);
921 break;
922 default:
923 throw new Error('Unknown Geometry Type');
924 }
925 }
926 }
927}
928
929/**
930 * Callback for coordReduce
931 *
932 * The first time the callback function is called, the values provided as arguments depend
933 * on whether the reduce method has an initialValue argument.
934 *
935 * If an initialValue is provided to the reduce method:
936 * - The previousValue argument is initialValue.
937 * - The currentValue argument is the value of the first element present in the array.
938 *
939 * If an initialValue is not provided:
940 * - The previousValue argument is the value of the first element present in the array.
941 * - The currentValue argument is the value of the second element present in the array.
942 *
943 * @callback coordReduceCallback
944 * @param {*} previousValue The accumulated value previously returned in the last invocation
945 * of the callback, or initialValue, if supplied.
946 * @param {Array<number>} currentCoord The current coordinate being processed.
947 * @param {number} coordIndex The current index of the coordinate being processed.
948 * Starts at index 0, if an initialValue is provided, and at index 1 otherwise.
949 * @param {number} featureIndex The current index of the Feature being processed.
950 * @param {number} multiFeatureIndex The current index of the Multi-Feature being processed.
951 * @param {number} geometryIndex The current index of the Geometry being processed.
952 */
953
954/**
955 * Reduce coordinates in any GeoJSON object, similar to Array.reduce()
956 *
957 * @name coordReduce
958 * @param {FeatureCollection|Geometry|Feature} geojson any GeoJSON object
959 * @param {Function} callback a method that takes (previousValue, currentCoord, coordIndex)
960 * @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
961 * @param {boolean} [excludeWrapCoord=false] whether or not to include the final coordinate of LinearRings that wraps the ring in its iteration.
962 * @returns {*} The value that results from the reduction.
963 * @example
964 * var features = turf.featureCollection([
965 * turf.point([26, 37], {"foo": "bar"}),
966 * turf.point([36, 53], {"hello": "world"})
967 * ]);
968 *
969 * turf.coordReduce(features, function (previousValue, currentCoord, coordIndex, featureIndex, multiFeatureIndex, geometryIndex) {
970 * //=previousValue
971 * //=currentCoord
972 * //=coordIndex
973 * //=featureIndex
974 * //=multiFeatureIndex
975 * //=geometryIndex
976 * return currentCoord;
977 * });
978 */
979function coordReduce(geojson, callback, initialValue, excludeWrapCoord) {
980 var previousValue = initialValue;
981 coordEach(geojson, function (currentCoord, coordIndex, featureIndex, multiFeatureIndex, geometryIndex) {
982 if (coordIndex === 0 && initialValue === undefined) previousValue = currentCoord;
983 else previousValue = callback(previousValue, currentCoord, coordIndex, featureIndex, multiFeatureIndex, geometryIndex);
984 }, excludeWrapCoord);
985 return previousValue;
986}
987
988/**
989 * Callback for propEach
990 *
991 * @callback propEachCallback
992 * @param {Object} currentProperties The current Properties being processed.
993 * @param {number} featureIndex The current index of the Feature being processed.
994 */
995
996/**
997 * Iterate over properties in any GeoJSON object, similar to Array.forEach()
998 *
999 * @name propEach
1000 * @param {FeatureCollection|Feature} geojson any GeoJSON object
1001 * @param {Function} callback a method that takes (currentProperties, featureIndex)
1002 * @example
1003 * var features = turf.featureCollection([
1004 * turf.point([26, 37], {foo: 'bar'}),
1005 * turf.point([36, 53], {hello: 'world'})
1006 * ]);
1007 *
1008 * turf.propEach(features, function (currentProperties, featureIndex) {
1009 * //=currentProperties
1010 * //=featureIndex
1011 * });
1012 */
1013function propEach(geojson, callback) {
1014 var i;
1015 switch (geojson.type) {
1016 case 'FeatureCollection':
1017 for (i = 0; i < geojson.features.length; i++) {
1018 callback(geojson.features[i].properties, i);
1019 }
1020 break;
1021 case 'Feature':
1022 callback(geojson.properties, 0);
1023 break;
1024 }
1025}
1026
1027
1028/**
1029 * Callback for propReduce
1030 *
1031 * The first time the callback function is called, the values provided as arguments depend
1032 * on whether the reduce method has an initialValue argument.
1033 *
1034 * If an initialValue is provided to the reduce method:
1035 * - The previousValue argument is initialValue.
1036 * - The currentValue argument is the value of the first element present in the array.
1037 *
1038 * If an initialValue is not provided:
1039 * - The previousValue argument is the value of the first element present in the array.
1040 * - The currentValue argument is the value of the second element present in the array.
1041 *
1042 * @callback propReduceCallback
1043 * @param {*} previousValue The accumulated value previously returned in the last invocation
1044 * of the callback, or initialValue, if supplied.
1045 * @param {*} currentProperties The current Properties being processed.
1046 * @param {number} featureIndex The current index of the Feature being processed.
1047 */
1048
1049/**
1050 * Reduce properties in any GeoJSON object into a single value,
1051 * similar to how Array.reduce works. However, in this case we lazily run
1052 * the reduction, so an array of all properties is unnecessary.
1053 *
1054 * @name propReduce
1055 * @param {FeatureCollection|Feature} geojson any GeoJSON object
1056 * @param {Function} callback a method that takes (previousValue, currentProperties, featureIndex)
1057 * @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
1058 * @returns {*} The value that results from the reduction.
1059 * @example
1060 * var features = turf.featureCollection([
1061 * turf.point([26, 37], {foo: 'bar'}),
1062 * turf.point([36, 53], {hello: 'world'})
1063 * ]);
1064 *
1065 * turf.propReduce(features, function (previousValue, currentProperties, featureIndex) {
1066 * //=previousValue
1067 * //=currentProperties
1068 * //=featureIndex
1069 * return currentProperties
1070 * });
1071 */
1072function propReduce(geojson, callback, initialValue) {
1073 var previousValue = initialValue;
1074 propEach(geojson, function (currentProperties, featureIndex) {
1075 if (featureIndex === 0 && initialValue === undefined) previousValue = currentProperties;
1076 else previousValue = callback(previousValue, currentProperties, featureIndex);
1077 });
1078 return previousValue;
1079}
1080
1081/**
1082 * Callback for featureEach
1083 *
1084 * @callback featureEachCallback
1085 * @param {Feature<any>} currentFeature The current Feature being processed.
1086 * @param {number} featureIndex The current index of the Feature being processed.
1087 */
1088
1089/**
1090 * Iterate over features in any GeoJSON object, similar to
1091 * Array.forEach.
1092 *
1093 * @name featureEach
1094 * @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
1095 * @param {Function} callback a method that takes (currentFeature, featureIndex)
1096 * @example
1097 * var features = turf.featureCollection([
1098 * turf.point([26, 37], {foo: 'bar'}),
1099 * turf.point([36, 53], {hello: 'world'})
1100 * ]);
1101 *
1102 * turf.featureEach(features, function (currentFeature, featureIndex) {
1103 * //=currentFeature
1104 * //=featureIndex
1105 * });
1106 */
1107function featureEach(geojson, callback) {
1108 if (geojson.type === 'Feature') {
1109 callback(geojson, 0);
1110 } else if (geojson.type === 'FeatureCollection') {
1111 for (var i = 0; i < geojson.features.length; i++) {
1112 callback(geojson.features[i], i);
1113 }
1114 }
1115}
1116
1117/**
1118 * Callback for featureReduce
1119 *
1120 * The first time the callback function is called, the values provided as arguments depend
1121 * on whether the reduce method has an initialValue argument.
1122 *
1123 * If an initialValue is provided to the reduce method:
1124 * - The previousValue argument is initialValue.
1125 * - The currentValue argument is the value of the first element present in the array.
1126 *
1127 * If an initialValue is not provided:
1128 * - The previousValue argument is the value of the first element present in the array.
1129 * - The currentValue argument is the value of the second element present in the array.
1130 *
1131 * @callback featureReduceCallback
1132 * @param {*} previousValue The accumulated value previously returned in the last invocation
1133 * of the callback, or initialValue, if supplied.
1134 * @param {Feature} currentFeature The current Feature being processed.
1135 * @param {number} featureIndex The current index of the Feature being processed.
1136 */
1137
1138/**
1139 * Reduce features in any GeoJSON object, similar to Array.reduce().
1140 *
1141 * @name featureReduce
1142 * @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
1143 * @param {Function} callback a method that takes (previousValue, currentFeature, featureIndex)
1144 * @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
1145 * @returns {*} The value that results from the reduction.
1146 * @example
1147 * var features = turf.featureCollection([
1148 * turf.point([26, 37], {"foo": "bar"}),
1149 * turf.point([36, 53], {"hello": "world"})
1150 * ]);
1151 *
1152 * turf.featureReduce(features, function (previousValue, currentFeature, featureIndex) {
1153 * //=previousValue
1154 * //=currentFeature
1155 * //=featureIndex
1156 * return currentFeature
1157 * });
1158 */
1159function featureReduce(geojson, callback, initialValue) {
1160 var previousValue = initialValue;
1161 featureEach(geojson, function (currentFeature, featureIndex) {
1162 if (featureIndex === 0 && initialValue === undefined) previousValue = currentFeature;
1163 else previousValue = callback(previousValue, currentFeature, featureIndex);
1164 });
1165 return previousValue;
1166}
1167
1168/**
1169 * Get all coordinates from any GeoJSON object.
1170 *
1171 * @name coordAll
1172 * @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
1173 * @returns {Array<Array<number>>} coordinate position array
1174 * @example
1175 * var features = turf.featureCollection([
1176 * turf.point([26, 37], {foo: 'bar'}),
1177 * turf.point([36, 53], {hello: 'world'})
1178 * ]);
1179 *
1180 * var coords = turf.coordAll(features);
1181 * //= [[26, 37], [36, 53]]
1182 */
1183function coordAll(geojson) {
1184 var coords = [];
1185 coordEach(geojson, function (coord) {
1186 coords.push(coord);
1187 });
1188 return coords;
1189}
1190
1191/**
1192 * Callback for geomEach
1193 *
1194 * @callback geomEachCallback
1195 * @param {Geometry} currentGeometry The current Geometry being processed.
1196 * @param {number} featureIndex The current index of the Feature being processed.
1197 * @param {Object} featureProperties The current Feature Properties being processed.
1198 * @param {Array<number>} featureBBox The current Feature BBox being processed.
1199 * @param {number|string} featureId The current Feature Id being processed.
1200 */
1201
1202/**
1203 * Iterate over each geometry in any GeoJSON object, similar to Array.forEach()
1204 *
1205 * @name geomEach
1206 * @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
1207 * @param {Function} callback a method that takes (currentGeometry, featureIndex, featureProperties, featureBBox, featureId)
1208 * @example
1209 * var features = turf.featureCollection([
1210 * turf.point([26, 37], {foo: 'bar'}),
1211 * turf.point([36, 53], {hello: 'world'})
1212 * ]);
1213 *
1214 * turf.geomEach(features, function (currentGeometry, featureIndex, featureProperties, featureBBox, featureId) {
1215 * //=currentGeometry
1216 * //=featureIndex
1217 * //=featureProperties
1218 * //=featureBBox
1219 * //=featureId
1220 * });
1221 */
1222function geomEach(geojson, callback) {
1223 var i, j, g, geometry$$1, stopG,
1224 geometryMaybeCollection,
1225 isGeometryCollection,
1226 featureProperties,
1227 featureBBox,
1228 featureId,
1229 featureIndex = 0,
1230 isFeatureCollection = geojson.type === 'FeatureCollection',
1231 isFeature = geojson.type === 'Feature',
1232 stop = isFeatureCollection ? geojson.features.length : 1;
1233
1234 // This logic may look a little weird. The reason why it is that way
1235 // is because it's trying to be fast. GeoJSON supports multiple kinds
1236 // of objects at its root: FeatureCollection, Features, Geometries.
1237 // This function has the responsibility of handling all of them, and that
1238 // means that some of the `for` loops you see below actually just don't apply
1239 // to certain inputs. For instance, if you give this just a
1240 // Point geometry, then both loops are short-circuited and all we do
1241 // is gradually rename the input until it's called 'geometry'.
1242 //
1243 // This also aims to allocate as few resources as possible: just a
1244 // few numbers and booleans, rather than any temporary arrays as would
1245 // be required with the normalization approach.
1246 for (i = 0; i < stop; i++) {
1247
1248 geometryMaybeCollection = (isFeatureCollection ? geojson.features[i].geometry :
1249 (isFeature ? geojson.geometry : geojson));
1250 featureProperties = (isFeatureCollection ? geojson.features[i].properties :
1251 (isFeature ? geojson.properties : {}));
1252 featureBBox = (isFeatureCollection ? geojson.features[i].bbox :
1253 (isFeature ? geojson.bbox : undefined));
1254 featureId = (isFeatureCollection ? geojson.features[i].id :
1255 (isFeature ? geojson.id : undefined));
1256 isGeometryCollection = (geometryMaybeCollection) ? geometryMaybeCollection.type === 'GeometryCollection' : false;
1257 stopG = isGeometryCollection ? geometryMaybeCollection.geometries.length : 1;
1258
1259 for (g = 0; g < stopG; g++) {
1260 geometry$$1 = isGeometryCollection ?
1261 geometryMaybeCollection.geometries[g] : geometryMaybeCollection;
1262
1263 // Handle null Geometry
1264 if (geometry$$1 === null) {
1265 callback(null, featureIndex, featureProperties, featureBBox, featureId);
1266 continue;
1267 }
1268 switch (geometry$$1.type) {
1269 case 'Point':
1270 case 'LineString':
1271 case 'MultiPoint':
1272 case 'Polygon':
1273 case 'MultiLineString':
1274 case 'MultiPolygon': {
1275 callback(geometry$$1, featureIndex, featureProperties, featureBBox, featureId);
1276 break;
1277 }
1278 case 'GeometryCollection': {
1279 for (j = 0; j < geometry$$1.geometries.length; j++) {
1280 callback(geometry$$1.geometries[j], featureIndex, featureProperties, featureBBox, featureId);
1281 }
1282 break;
1283 }
1284 default:
1285 throw new Error('Unknown Geometry Type');
1286 }
1287 }
1288 // Only increase `featureIndex` per each feature
1289 featureIndex++;
1290 }
1291}
1292
1293/**
1294 * Callback for geomReduce
1295 *
1296 * The first time the callback function is called, the values provided as arguments depend
1297 * on whether the reduce method has an initialValue argument.
1298 *
1299 * If an initialValue is provided to the reduce method:
1300 * - The previousValue argument is initialValue.
1301 * - The currentValue argument is the value of the first element present in the array.
1302 *
1303 * If an initialValue is not provided:
1304 * - The previousValue argument is the value of the first element present in the array.
1305 * - The currentValue argument is the value of the second element present in the array.
1306 *
1307 * @callback geomReduceCallback
1308 * @param {*} previousValue The accumulated value previously returned in the last invocation
1309 * of the callback, or initialValue, if supplied.
1310 * @param {Geometry} currentGeometry The current Geometry being processed.
1311 * @param {number} featureIndex The current index of the Feature being processed.
1312 * @param {Object} featureProperties The current Feature Properties being processed.
1313 * @param {Array<number>} featureBBox The current Feature BBox being processed.
1314 * @param {number|string} featureId The current Feature Id being processed.
1315 */
1316
1317/**
1318 * Reduce geometry in any GeoJSON object, similar to Array.reduce().
1319 *
1320 * @name geomReduce
1321 * @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
1322 * @param {Function} callback a method that takes (previousValue, currentGeometry, featureIndex, featureProperties, featureBBox, featureId)
1323 * @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
1324 * @returns {*} The value that results from the reduction.
1325 * @example
1326 * var features = turf.featureCollection([
1327 * turf.point([26, 37], {foo: 'bar'}),
1328 * turf.point([36, 53], {hello: 'world'})
1329 * ]);
1330 *
1331 * turf.geomReduce(features, function (previousValue, currentGeometry, featureIndex, featureProperties, featureBBox, featureId) {
1332 * //=previousValue
1333 * //=currentGeometry
1334 * //=featureIndex
1335 * //=featureProperties
1336 * //=featureBBox
1337 * //=featureId
1338 * return currentGeometry
1339 * });
1340 */
1341function geomReduce(geojson, callback, initialValue) {
1342 var previousValue = initialValue;
1343 geomEach(geojson, function (currentGeometry, featureIndex, featureProperties, featureBBox, featureId) {
1344 if (featureIndex === 0 && initialValue === undefined) previousValue = currentGeometry;
1345 else previousValue = callback(previousValue, currentGeometry, featureIndex, featureProperties, featureBBox, featureId);
1346 });
1347 return previousValue;
1348}
1349
1350/**
1351 * Callback for flattenEach
1352 *
1353 * @callback flattenEachCallback
1354 * @param {Feature} currentFeature The current flattened feature being processed.
1355 * @param {number} featureIndex The current index of the Feature being processed.
1356 * @param {number} multiFeatureIndex The current index of the Multi-Feature being processed.
1357 */
1358
1359/**
1360 * Iterate over flattened features in any GeoJSON object, similar to
1361 * Array.forEach.
1362 *
1363 * @name flattenEach
1364 * @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
1365 * @param {Function} callback a method that takes (currentFeature, featureIndex, multiFeatureIndex)
1366 * @example
1367 * var features = turf.featureCollection([
1368 * turf.point([26, 37], {foo: 'bar'}),
1369 * turf.multiPoint([[40, 30], [36, 53]], {hello: 'world'})
1370 * ]);
1371 *
1372 * turf.flattenEach(features, function (currentFeature, featureIndex, multiFeatureIndex) {
1373 * //=currentFeature
1374 * //=featureIndex
1375 * //=multiFeatureIndex
1376 * });
1377 */
1378function flattenEach(geojson, callback) {
1379 geomEach(geojson, function (geometry$$1, featureIndex, properties, bbox, id) {
1380 // Callback for single geometry
1381 var type = (geometry$$1 === null) ? null : geometry$$1.type;
1382 switch (type) {
1383 case null:
1384 case 'Point':
1385 case 'LineString':
1386 case 'Polygon':
1387 callback(feature(geometry$$1, properties, {bbox: bbox, id: id}), featureIndex, 0);
1388 return;
1389 }
1390
1391 var geomType;
1392
1393 // Callback for multi-geometry
1394 switch (type) {
1395 case 'MultiPoint':
1396 geomType = 'Point';
1397 break;
1398 case 'MultiLineString':
1399 geomType = 'LineString';
1400 break;
1401 case 'MultiPolygon':
1402 geomType = 'Polygon';
1403 break;
1404 }
1405
1406 geometry$$1.coordinates.forEach(function (coordinate, multiFeatureIndex) {
1407 var geom = {
1408 type: geomType,
1409 coordinates: coordinate
1410 };
1411 callback(feature(geom, properties), featureIndex, multiFeatureIndex);
1412 });
1413
1414 });
1415}
1416
1417/**
1418 * Callback for flattenReduce
1419 *
1420 * The first time the callback function is called, the values provided as arguments depend
1421 * on whether the reduce method has an initialValue argument.
1422 *
1423 * If an initialValue is provided to the reduce method:
1424 * - The previousValue argument is initialValue.
1425 * - The currentValue argument is the value of the first element present in the array.
1426 *
1427 * If an initialValue is not provided:
1428 * - The previousValue argument is the value of the first element present in the array.
1429 * - The currentValue argument is the value of the second element present in the array.
1430 *
1431 * @callback flattenReduceCallback
1432 * @param {*} previousValue The accumulated value previously returned in the last invocation
1433 * of the callback, or initialValue, if supplied.
1434 * @param {Feature} currentFeature The current Feature being processed.
1435 * @param {number} featureIndex The current index of the Feature being processed.
1436 * @param {number} multiFeatureIndex The current index of the Multi-Feature being processed.
1437 */
1438
1439/**
1440 * Reduce flattened features in any GeoJSON object, similar to Array.reduce().
1441 *
1442 * @name flattenReduce
1443 * @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object
1444 * @param {Function} callback a method that takes (previousValue, currentFeature, featureIndex, multiFeatureIndex)
1445 * @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
1446 * @returns {*} The value that results from the reduction.
1447 * @example
1448 * var features = turf.featureCollection([
1449 * turf.point([26, 37], {foo: 'bar'}),
1450 * turf.multiPoint([[40, 30], [36, 53]], {hello: 'world'})
1451 * ]);
1452 *
1453 * turf.flattenReduce(features, function (previousValue, currentFeature, featureIndex, multiFeatureIndex) {
1454 * //=previousValue
1455 * //=currentFeature
1456 * //=featureIndex
1457 * //=multiFeatureIndex
1458 * return currentFeature
1459 * });
1460 */
1461function flattenReduce(geojson, callback, initialValue) {
1462 var previousValue = initialValue;
1463 flattenEach(geojson, function (currentFeature, featureIndex, multiFeatureIndex) {
1464 if (featureIndex === 0 && multiFeatureIndex === 0 && initialValue === undefined) previousValue = currentFeature;
1465 else previousValue = callback(previousValue, currentFeature, featureIndex, multiFeatureIndex);
1466 });
1467 return previousValue;
1468}
1469
1470/**
1471 * Callback for segmentEach
1472 *
1473 * @callback segmentEachCallback
1474 * @param {Feature<LineString>} currentSegment The current Segment being processed.
1475 * @param {number} featureIndex The current index of the Feature being processed.
1476 * @param {number} multiFeatureIndex The current index of the Multi-Feature being processed.
1477 * @param {number} geometryIndex The current index of the Geometry being processed.
1478 * @param {number} segmentIndex The current index of the Segment being processed.
1479 * @returns {void}
1480 */
1481
1482/**
1483 * Iterate over 2-vertex line segment in any GeoJSON object, similar to Array.forEach()
1484 * (Multi)Point geometries do not contain segments therefore they are ignored during this operation.
1485 *
1486 * @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON
1487 * @param {Function} callback a method that takes (currentSegment, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex)
1488 * @returns {void}
1489 * @example
1490 * var polygon = turf.polygon([[[-50, 5], [-40, -10], [-50, -10], [-40, 5], [-50, 5]]]);
1491 *
1492 * // Iterate over GeoJSON by 2-vertex segments
1493 * turf.segmentEach(polygon, function (currentSegment, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex) {
1494 * //=currentSegment
1495 * //=featureIndex
1496 * //=multiFeatureIndex
1497 * //=geometryIndex
1498 * //=segmentIndex
1499 * });
1500 *
1501 * // Calculate the total number of segments
1502 * var total = 0;
1503 * turf.segmentEach(polygon, function () {
1504 * total++;
1505 * });
1506 */
1507function segmentEach(geojson, callback) {
1508 flattenEach(geojson, function (feature$$1, featureIndex, multiFeatureIndex) {
1509 var segmentIndex = 0;
1510
1511 // Exclude null Geometries
1512 if (!feature$$1.geometry) return;
1513 // (Multi)Point geometries do not contain segments therefore they are ignored during this operation.
1514 var type = feature$$1.geometry.type;
1515 if (type === 'Point' || type === 'MultiPoint') return;
1516
1517 // Generate 2-vertex line segments
1518 coordReduce(feature$$1, function (previousCoords, currentCoord, coordIndex, featureIndexCoord, mutliPartIndexCoord, geometryIndex) {
1519 var currentSegment = lineString([previousCoords, currentCoord], feature$$1.properties);
1520 callback(currentSegment, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex);
1521 segmentIndex++;
1522 return currentCoord;
1523 });
1524 });
1525}
1526
1527/**
1528 * Callback for segmentReduce
1529 *
1530 * The first time the callback function is called, the values provided as arguments depend
1531 * on whether the reduce method has an initialValue argument.
1532 *
1533 * If an initialValue is provided to the reduce method:
1534 * - The previousValue argument is initialValue.
1535 * - The currentValue argument is the value of the first element present in the array.
1536 *
1537 * If an initialValue is not provided:
1538 * - The previousValue argument is the value of the first element present in the array.
1539 * - The currentValue argument is the value of the second element present in the array.
1540 *
1541 * @callback segmentReduceCallback
1542 * @param {*} previousValue The accumulated value previously returned in the last invocation
1543 * of the callback, or initialValue, if supplied.
1544 * @param {Feature<LineString>} currentSegment The current Segment being processed.
1545 * @param {number} featureIndex The current index of the Feature being processed.
1546 * @param {number} multiFeatureIndex The current index of the Multi-Feature being processed.
1547 * @param {number} geometryIndex The current index of the Geometry being processed.
1548 * @param {number} segmentIndex The current index of the Segment being processed.
1549 */
1550
1551/**
1552 * Reduce 2-vertex line segment in any GeoJSON object, similar to Array.reduce()
1553 * (Multi)Point geometries do not contain segments therefore they are ignored during this operation.
1554 *
1555 * @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON
1556 * @param {Function} callback a method that takes (previousValue, currentSegment, currentIndex)
1557 * @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
1558 * @returns {void}
1559 * @example
1560 * var polygon = turf.polygon([[[-50, 5], [-40, -10], [-50, -10], [-40, 5], [-50, 5]]]);
1561 *
1562 * // Iterate over GeoJSON by 2-vertex segments
1563 * turf.segmentReduce(polygon, function (previousSegment, currentSegment, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex) {
1564 * //= previousSegment
1565 * //= currentSegment
1566 * //= featureIndex
1567 * //= multiFeatureIndex
1568 * //= geometryIndex
1569 * //= segmentInex
1570 * return currentSegment
1571 * });
1572 *
1573 * // Calculate the total number of segments
1574 * var initialValue = 0
1575 * var total = turf.segmentReduce(polygon, function (previousValue) {
1576 * previousValue++;
1577 * return previousValue;
1578 * }, initialValue);
1579 */
1580function segmentReduce(geojson, callback, initialValue) {
1581 var previousValue = initialValue;
1582 var started = false;
1583 segmentEach(geojson, function (currentSegment, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex) {
1584 if (started === false && initialValue === undefined) previousValue = currentSegment;
1585 else previousValue = callback(previousValue, currentSegment, featureIndex, multiFeatureIndex, geometryIndex, segmentIndex);
1586 started = true;
1587 });
1588 return previousValue;
1589}
1590
1591/**
1592 * Callback for lineEach
1593 *
1594 * @callback lineEachCallback
1595 * @param {Feature<LineString>} currentLine The current LineString|LinearRing being processed
1596 * @param {number} featureIndex The current index of the Feature being processed
1597 * @param {number} multiFeatureIndex The current index of the Multi-Feature being processed
1598 * @param {number} geometryIndex The current index of the Geometry being processed
1599 */
1600
1601/**
1602 * Iterate over line or ring coordinates in LineString, Polygon, MultiLineString, MultiPolygon Features or Geometries,
1603 * similar to Array.forEach.
1604 *
1605 * @name lineEach
1606 * @param {Geometry|Feature<LineString|Polygon|MultiLineString|MultiPolygon>} geojson object
1607 * @param {Function} callback a method that takes (currentLine, featureIndex, multiFeatureIndex, geometryIndex)
1608 * @example
1609 * var multiLine = turf.multiLineString([
1610 * [[26, 37], [35, 45]],
1611 * [[36, 53], [38, 50], [41, 55]]
1612 * ]);
1613 *
1614 * turf.lineEach(multiLine, function (currentLine, featureIndex, multiFeatureIndex, geometryIndex) {
1615 * //=currentLine
1616 * //=featureIndex
1617 * //=multiFeatureIndex
1618 * //=geometryIndex
1619 * });
1620 */
1621function lineEach(geojson, callback) {
1622 // validation
1623 if (!geojson) throw new Error('geojson is required');
1624
1625 flattenEach(geojson, function (feature$$1, featureIndex, multiFeatureIndex) {
1626 if (feature$$1.geometry === null) return;
1627 var type = feature$$1.geometry.type;
1628 var coords = feature$$1.geometry.coordinates;
1629 switch (type) {
1630 case 'LineString':
1631 callback(feature$$1, featureIndex, multiFeatureIndex, 0, 0);
1632 break;
1633 case 'Polygon':
1634 for (var geometryIndex = 0; geometryIndex < coords.length; geometryIndex++) {
1635 callback(lineString(coords[geometryIndex], feature$$1.properties), featureIndex, multiFeatureIndex, geometryIndex);
1636 }
1637 break;
1638 }
1639 });
1640}
1641
1642/**
1643 * Callback for lineReduce
1644 *
1645 * The first time the callback function is called, the values provided as arguments depend
1646 * on whether the reduce method has an initialValue argument.
1647 *
1648 * If an initialValue is provided to the reduce method:
1649 * - The previousValue argument is initialValue.
1650 * - The currentValue argument is the value of the first element present in the array.
1651 *
1652 * If an initialValue is not provided:
1653 * - The previousValue argument is the value of the first element present in the array.
1654 * - The currentValue argument is the value of the second element present in the array.
1655 *
1656 * @callback lineReduceCallback
1657 * @param {*} previousValue The accumulated value previously returned in the last invocation
1658 * of the callback, or initialValue, if supplied.
1659 * @param {Feature<LineString>} currentLine The current LineString|LinearRing being processed.
1660 * @param {number} featureIndex The current index of the Feature being processed
1661 * @param {number} multiFeatureIndex The current index of the Multi-Feature being processed
1662 * @param {number} geometryIndex The current index of the Geometry being processed
1663 */
1664
1665/**
1666 * Reduce features in any GeoJSON object, similar to Array.reduce().
1667 *
1668 * @name lineReduce
1669 * @param {Geometry|Feature<LineString|Polygon|MultiLineString|MultiPolygon>} geojson object
1670 * @param {Function} callback a method that takes (previousValue, currentLine, featureIndex, multiFeatureIndex, geometryIndex)
1671 * @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
1672 * @returns {*} The value that results from the reduction.
1673 * @example
1674 * var multiPoly = turf.multiPolygon([
1675 * turf.polygon([[[12,48],[2,41],[24,38],[12,48]], [[9,44],[13,41],[13,45],[9,44]]]),
1676 * turf.polygon([[[5, 5], [0, 0], [2, 2], [4, 4], [5, 5]]])
1677 * ]);
1678 *
1679 * turf.lineReduce(multiPoly, function (previousValue, currentLine, featureIndex, multiFeatureIndex, geometryIndex) {
1680 * //=previousValue
1681 * //=currentLine
1682 * //=featureIndex
1683 * //=multiFeatureIndex
1684 * //=geometryIndex
1685 * return currentLine
1686 * });
1687 */
1688function lineReduce(geojson, callback, initialValue) {
1689 var previousValue = initialValue;
1690 lineEach(geojson, function (currentLine, featureIndex, multiFeatureIndex, geometryIndex) {
1691 if (featureIndex === 0 && initialValue === undefined) previousValue = currentLine;
1692 else previousValue = callback(previousValue, currentLine, featureIndex, multiFeatureIndex, geometryIndex);
1693 });
1694 return previousValue;
1695}
1696
1697
1698
1699
1700var main_es = Object.freeze({
1701 coordEach: coordEach,
1702 coordReduce: coordReduce,
1703 propEach: propEach,
1704 propReduce: propReduce,
1705 featureEach: featureEach,
1706 featureReduce: featureReduce,
1707 coordAll: coordAll,
1708 geomEach: geomEach,
1709 geomReduce: geomReduce,
1710 flattenEach: flattenEach,
1711 flattenReduce: flattenReduce,
1712 segmentEach: segmentEach,
1713 segmentReduce: segmentReduce,
1714 lineEach: lineEach,
1715 lineReduce: lineReduce
1716});
1717
1718/**
1719 * Takes a set of features, calculates the bbox of all input features, and returns a bounding box.
1720 *
1721 * @name bbox
1722 * @param {GeoJSON} geojson any GeoJSON object
1723 * @returns {BBox} bbox extent in [minX, minY, maxX, maxY] order
1724 * @example
1725 * var line = turf.lineString([[-74, 40], [-78, 42], [-82, 35]]);
1726 * var bbox = turf.bbox(line);
1727 * var bboxPolygon = turf.bboxPolygon(bbox);
1728 *
1729 * //addToMap
1730 * var addToMap = [line, bboxPolygon]
1731 */
1732function bbox(geojson) {
1733 var BBox = [Infinity, Infinity, -Infinity, -Infinity];
1734 coordEach(geojson, function (coord) {
1735 if (BBox[0] > coord[0]) BBox[0] = coord[0];
1736 if (BBox[1] > coord[1]) BBox[1] = coord[1];
1737 if (BBox[2] < coord[0]) BBox[2] = coord[0];
1738 if (BBox[3] < coord[1]) BBox[3] = coord[1];
1739 });
1740 return BBox;
1741}
1742
1743/**
1744 * Unwrap a coordinate from a Point Feature, Geometry or a single coordinate.
1745 *
1746 * @name getCoord
1747 * @param {Array<number>|Geometry<Point>|Feature<Point>} obj Object
1748 * @returns {Array<number>} coordinates
1749 * @example
1750 * var pt = turf.point([10, 10]);
1751 *
1752 * var coord = turf.getCoord(pt);
1753 * //= [10, 10]
1754 */
1755function getCoord(obj) {
1756 if (!obj) throw new Error('obj is required');
1757
1758 var coordinates = getCoords(obj);
1759
1760 // getCoord() must contain at least two numbers (Point)
1761 if (coordinates.length > 1 && isNumber(coordinates[0]) && isNumber(coordinates[1])) {
1762 return coordinates;
1763 } else {
1764 throw new Error('Coordinate is not a valid Point');
1765 }
1766}
1767
1768/**
1769 * Unwrap coordinates from a Feature, Geometry Object or an Array of numbers
1770 *
1771 * @name getCoords
1772 * @param {Array<number>|Geometry|Feature} obj Object
1773 * @returns {Array<number>} coordinates
1774 * @example
1775 * var poly = turf.polygon([[[119.32, -8.7], [119.55, -8.69], [119.51, -8.54], [119.32, -8.7]]]);
1776 *
1777 * var coord = turf.getCoords(poly);
1778 * //= [[[119.32, -8.7], [119.55, -8.69], [119.51, -8.54], [119.32, -8.7]]]
1779 */
1780function getCoords(obj) {
1781 if (!obj) throw new Error('obj is required');
1782 var coordinates;
1783
1784 // Array of numbers
1785 if (obj.length) {
1786 coordinates = obj;
1787
1788 // Geometry Object
1789 } else if (obj.coordinates) {
1790 coordinates = obj.coordinates;
1791
1792 // Feature
1793 } else if (obj.geometry && obj.geometry.coordinates) {
1794 coordinates = obj.geometry.coordinates;
1795 }
1796 // Checks if coordinates contains a number
1797 if (coordinates) {
1798 containsNumber(coordinates);
1799 return coordinates;
1800 }
1801 throw new Error('No valid coordinates');
1802}
1803
1804/**
1805 * Checks if coordinates contains a number
1806 *
1807 * @name containsNumber
1808 * @param {Array<any>} coordinates GeoJSON Coordinates
1809 * @returns {boolean} true if Array contains a number
1810 */
1811function containsNumber(coordinates) {
1812 if (coordinates.length > 1 && isNumber(coordinates[0]) && isNumber(coordinates[1])) {
1813 return true;
1814 }
1815
1816 if (Array.isArray(coordinates[0]) && coordinates[0].length) {
1817 return containsNumber(coordinates[0]);
1818 }
1819 throw new Error('coordinates must only contain numbers');
1820}
1821
1822/**
1823 * Enforce expectations about types of GeoJSON objects for Turf.
1824 *
1825 * @name geojsonType
1826 * @param {GeoJSON} value any GeoJSON object
1827 * @param {string} type expected GeoJSON type
1828 * @param {string} name name of calling function
1829 * @throws {Error} if value is not the expected type.
1830 */
1831function geojsonType(value, type, name) {
1832 if (!type || !name) throw new Error('type and name required');
1833
1834 if (!value || value.type !== type) {
1835 throw new Error('Invalid input to ' + name + ': must be a ' + type + ', given ' + value.type);
1836 }
1837}
1838
1839/**
1840 * Enforce expectations about types of {@link Feature} inputs for Turf.
1841 * Internally this uses {@link geojsonType} to judge geometry types.
1842 *
1843 * @name featureOf
1844 * @param {Feature} feature a feature with an expected geometry type
1845 * @param {string} type expected GeoJSON type
1846 * @param {string} name name of calling function
1847 * @throws {Error} error if value is not the expected type.
1848 */
1849function featureOf(feature$$1, type, name) {
1850 if (!feature$$1) throw new Error('No feature passed');
1851 if (!name) throw new Error('.featureOf() requires a name');
1852 if (!feature$$1 || feature$$1.type !== 'Feature' || !feature$$1.geometry) {
1853 throw new Error('Invalid input to ' + name + ', Feature with geometry required');
1854 }
1855 if (!feature$$1.geometry || feature$$1.geometry.type !== type) {
1856 throw new Error('Invalid input to ' + name + ': must be a ' + type + ', given ' + feature$$1.geometry.type);
1857 }
1858}
1859
1860/**
1861 * Enforce expectations about types of {@link FeatureCollection} inputs for Turf.
1862 * Internally this uses {@link geojsonType} to judge geometry types.
1863 *
1864 * @name collectionOf
1865 * @param {FeatureCollection} featureCollection a FeatureCollection for which features will be judged
1866 * @param {string} type expected GeoJSON type
1867 * @param {string} name name of calling function
1868 * @throws {Error} if value is not the expected type.
1869 */
1870function collectionOf(featureCollection$$1, type, name) {
1871 if (!featureCollection$$1) throw new Error('No featureCollection passed');
1872 if (!name) throw new Error('.collectionOf() requires a name');
1873 if (!featureCollection$$1 || featureCollection$$1.type !== 'FeatureCollection') {
1874 throw new Error('Invalid input to ' + name + ', FeatureCollection required');
1875 }
1876 for (var i = 0; i < featureCollection$$1.features.length; i++) {
1877 var feature$$1 = featureCollection$$1.features[i];
1878 if (!feature$$1 || feature$$1.type !== 'Feature' || !feature$$1.geometry) {
1879 throw new Error('Invalid input to ' + name + ', Feature with geometry required');
1880 }
1881 if (!feature$$1.geometry || feature$$1.geometry.type !== type) {
1882 throw new Error('Invalid input to ' + name + ': must be a ' + type + ', given ' + feature$$1.geometry.type);
1883 }
1884 }
1885}
1886
1887/**
1888 * Get Geometry from Feature or Geometry Object
1889 *
1890 * @param {Feature|Geometry} geojson GeoJSON Feature or Geometry Object
1891 * @returns {Geometry|null} GeoJSON Geometry Object
1892 * @throws {Error} if geojson is not a Feature or Geometry Object
1893 * @example
1894 * var point = {
1895 * "type": "Feature",
1896 * "properties": {},
1897 * "geometry": {
1898 * "type": "Point",
1899 * "coordinates": [110, 40]
1900 * }
1901 * }
1902 * var geom = turf.getGeom(point)
1903 * //={"type": "Point", "coordinates": [110, 40]}
1904 */
1905function getGeom(geojson) {
1906 if (!geojson) throw new Error('geojson is required');
1907 if (geojson.geometry !== undefined) return geojson.geometry;
1908 if (geojson.coordinates || geojson.geometries) return geojson;
1909 throw new Error('geojson must be a valid Feature or Geometry Object');
1910}
1911
1912/**
1913 * Get Geometry Type from Feature or Geometry Object
1914 *
1915 * @throws {Error} **DEPRECATED** in v5.0.0 in favor of getType
1916 */
1917function getGeomType() {
1918 throw new Error('invariant.getGeomType has been deprecated in v5.0 in favor of invariant.getType');
1919}
1920
1921/**
1922 * Get GeoJSON object's type, Geometry type is prioritize.
1923 *
1924 * @param {GeoJSON} geojson GeoJSON object
1925 * @param {string} [name] name of the variable to display in error message
1926 * @returns {string} GeoJSON type
1927 * @example
1928 * var point = {
1929 * "type": "Feature",
1930 * "properties": {},
1931 * "geometry": {
1932 * "type": "Point",
1933 * "coordinates": [110, 40]
1934 * }
1935 * }
1936 * var geom = turf.getType(point)
1937 * //="Point"
1938 */
1939function getType(geojson, name) {
1940 if (!geojson) throw new Error((name || 'geojson') + ' is required');
1941 // GeoJSON Feature & GeometryCollection
1942 if (geojson.geometry && geojson.geometry.type) return geojson.geometry.type;
1943 // GeoJSON Geometry & FeatureCollection
1944 if (geojson.type) return geojson.type;
1945 throw new Error((name || 'geojson') + ' is invalid');
1946}
1947
1948
1949
1950
1951var main_es$2 = Object.freeze({
1952 getCoord: getCoord,
1953 getCoords: getCoords,
1954 containsNumber: containsNumber,
1955 geojsonType: geojsonType,
1956 featureOf: featureOf,
1957 collectionOf: collectionOf,
1958 getGeom: getGeom,
1959 getGeomType: getGeomType,
1960 getType: getType
1961});
1962
1963/**
1964 * @license GNU Affero General Public License.
1965 * Copyright (c) 2015, 2015 Ronny Lorenz <ronny@tbi.univie.ac.at>
1966 * v. 1.2.0
1967 * https://github.com/RaumZeit/MarchingSquares.js
1968 */
1969
1970/**
1971 * Compute the isocontour(s) of a scalar 2D field given
1972 * a certain threshold by applying the Marching Squares
1973 * Algorithm. The function returns a list of path coordinates
1974 */
1975var defaultSettings = {
1976 successCallback: null,
1977 verbose: false
1978};
1979
1980var settings = {};
1981
1982function isoContours(data, threshold, options) {
1983 /* process options */
1984 options = options ? options : {};
1985
1986 var optionKeys = Object.keys(defaultSettings);
1987
1988 for (var i = 0; i < optionKeys.length; i++) {
1989 var key = optionKeys[i];
1990 var val = options[key];
1991 val = ((typeof val !== 'undefined') && (val !== null)) ? val : defaultSettings[key];
1992
1993 settings[key] = val;
1994 }
1995
1996 if (settings.verbose)
1997 console.log('MarchingSquaresJS-isoContours: computing isocontour for ' + threshold);
1998
1999 var ret = contourGrid2Paths(computeContourGrid(data, threshold));
2000
2001 if (typeof settings.successCallback === 'function')
2002 settings.successCallback(ret);
2003
2004 return ret;
2005}
2006
2007/*
2008 Thats all for the public interface, below follows the actual
2009 implementation
2010*/
2011
2012/*
2013################################
2014Isocontour implementation below
2015################################
2016*/
2017
2018/* assume that x1 == 1 && x0 == 0 */
2019function interpolateX(y, y0, y1) {
2020 return (y - y0) / (y1 - y0);
2021}
2022
2023/* compute the isocontour 4-bit grid */
2024function computeContourGrid(data, threshold) {
2025 var rows = data.length - 1;
2026 var cols = data[0].length - 1;
2027 var ContourGrid = { rows: rows, cols: cols, cells: [] };
2028
2029 for (var j = 0; j < rows; ++j) {
2030 ContourGrid.cells[j] = [];
2031 for (var i = 0; i < cols; ++i) {
2032 /* compose the 4-bit corner representation */
2033 var cval = 0;
2034
2035 var tl = data[j + 1][i];
2036 var tr = data[j + 1][i + 1];
2037 var br = data[j][i + 1];
2038 var bl = data[j][i];
2039
2040 if (isNaN(tl) || isNaN(tr) || isNaN(br) || isNaN(bl)) {
2041 continue;
2042 }
2043 cval |= ((tl >= threshold) ? 8 : 0);
2044 cval |= ((tr >= threshold) ? 4 : 0);
2045 cval |= ((br >= threshold) ? 2 : 0);
2046 cval |= ((bl >= threshold) ? 1 : 0);
2047
2048 /* resolve ambiguity for cval == 5 || 10 via averaging */
2049 var flipped = false;
2050 if (cval === 5 || cval === 10) {
2051 var average = (tl + tr + br + bl) / 4;
2052 if (cval === 5 && (average < threshold)) {
2053 cval = 10;
2054 flipped = true;
2055 } else if (cval === 10 && (average < threshold)) {
2056 cval = 5;
2057 flipped = true;
2058 }
2059 }
2060
2061 /* add cell to ContourGrid if it contains edges */
2062 if (cval !== 0 && cval !== 15) {
2063 var top, bottom, left, right;
2064 top = bottom = left = right = 0.5;
2065 /* interpolate edges of cell */
2066 if (cval === 1) {
2067 left = 1 - interpolateX(threshold, tl, bl);
2068 bottom = 1 - interpolateX(threshold, br, bl);
2069 } else if (cval === 2) {
2070 bottom = interpolateX(threshold, bl, br);
2071 right = 1 - interpolateX(threshold, tr, br);
2072 } else if (cval === 3) {
2073 left = 1 - interpolateX(threshold, tl, bl);
2074 right = 1 - interpolateX(threshold, tr, br);
2075 } else if (cval === 4) {
2076 top = interpolateX(threshold, tl, tr);
2077 right = interpolateX(threshold, br, tr);
2078 } else if (cval === 5) {
2079 top = interpolateX(threshold, tl, tr);
2080 right = interpolateX(threshold, br, tr);
2081 bottom = 1 - interpolateX(threshold, br, bl);
2082 left = 1 - interpolateX(threshold, tl, bl);
2083 } else if (cval === 6) {
2084 bottom = interpolateX(threshold, bl, br);
2085 top = interpolateX(threshold, tl, tr);
2086 } else if (cval === 7) {
2087 left = 1 - interpolateX(threshold, tl, bl);
2088 top = interpolateX(threshold, tl, tr);
2089 } else if (cval === 8) {
2090 left = interpolateX(threshold, bl, tl);
2091 top = 1 - interpolateX(threshold, tr, tl);
2092 } else if (cval === 9) {
2093 bottom = 1 - interpolateX(threshold, br, bl);
2094 top = 1 - interpolateX(threshold, tr, tl);
2095 } else if (cval === 10) {
2096 top = 1 - interpolateX(threshold, tr, tl);
2097 right = 1 - interpolateX(threshold, tr, br);
2098 bottom = interpolateX(threshold, bl, br);
2099 left = interpolateX(threshold, bl, tl);
2100 } else if (cval === 11) {
2101 top = 1 - interpolateX(threshold, tr, tl);
2102 right = 1 - interpolateX(threshold, tr, br);
2103 } else if (cval === 12) {
2104 left = interpolateX(threshold, bl, tl);
2105 right = interpolateX(threshold, br, tr);
2106 } else if (cval === 13) {
2107 bottom = 1 - interpolateX(threshold, br, bl);
2108 right = interpolateX(threshold, br, tr);
2109 } else if (cval === 14) {
2110 left = interpolateX(threshold, bl, tl);
2111 bottom = interpolateX(threshold, bl, br);
2112 } else {
2113 console.log('MarchingSquaresJS-isoContours: Illegal cval detected: ' + cval);
2114 }
2115 ContourGrid.cells[j][i] = {
2116 cval: cval,
2117 flipped: flipped,
2118 top: top,
2119 right: right,
2120 bottom: bottom,
2121 left: left
2122 };
2123 }
2124
2125 }
2126 }
2127
2128 return ContourGrid;
2129}
2130
2131function isSaddle(cell) {
2132 return cell.cval === 5 || cell.cval === 10;
2133}
2134
2135function isTrivial(cell) {
2136 return cell.cval === 0 || cell.cval === 15;
2137}
2138
2139function clearCell(cell) {
2140 if ((!isTrivial(cell)) && (cell.cval !== 5) && (cell.cval !== 10)) {
2141 cell.cval = 15;
2142 }
2143}
2144
2145function getXY(cell, edge) {
2146 if (edge === 'top') {
2147 return [cell.top, 1.0];
2148 } else if (edge === 'bottom') {
2149 return [cell.bottom, 0.0];
2150 } else if (edge === 'right') {
2151 return [1.0, cell.right];
2152 } else if (edge === 'left') {
2153 return [0.0, cell.left];
2154 }
2155}
2156
2157function contourGrid2Paths(grid) {
2158 var paths = [];
2159 var path_idx = 0;
2160 var rows = grid.rows;
2161 var cols = grid.cols;
2162 var epsilon = 1e-7;
2163
2164 grid.cells.forEach(function (g, j) {
2165 g.forEach(function (gg, i) {
2166 if ((typeof gg !== 'undefined') && (!isSaddle(gg)) && (!isTrivial(gg))) {
2167 var p = tracePath(grid.cells, j, i);
2168 var merged = false;
2169 /* we may try to merge paths at this point */
2170 if (p.info === 'mergeable') {
2171 /*
2172 search backwards through the path array to find an entry
2173 that starts with where the current path ends...
2174 */
2175 var x = p.path[p.path.length - 1][0],
2176 y = p.path[p.path.length - 1][1];
2177
2178 for (var k = path_idx - 1; k >= 0; k--) {
2179 if ((Math.abs(paths[k][0][0] - x) <= epsilon) && (Math.abs(paths[k][0][1] - y) <= epsilon)) {
2180 for (var l = p.path.length - 2; l >= 0; --l) {
2181 paths[k].unshift(p.path[l]);
2182 }
2183 merged = true;
2184 break;
2185 }
2186 }
2187 }
2188 if (!merged)
2189 paths[path_idx++] = p.path;
2190 }
2191 });
2192 });
2193
2194 return paths;
2195}
2196
2197/*
2198 construct consecutive line segments from starting cell by
2199 walking arround the enclosed area clock-wise
2200 */
2201function tracePath(grid, j, i) {
2202 var maxj = grid.length;
2203 var p = [];
2204 var dxContour = [0, 0, 1, 1, 0, 0, 0, 0, -1, 0, 1, 1, -1, 0, -1, 0];
2205 var dyContour = [0, -1, 0, 0, 1, 1, 1, 1, 0, -1, 0, 0, 0, -1, 0, 0];
2206 var dx, dy;
2207 var startEdge = ['none', 'left', 'bottom', 'left', 'right', 'none', 'bottom', 'left', 'top', 'top', 'none', 'top', 'right', 'right', 'bottom', 'none'];
2208 var nextEdge = ['none', 'bottom', 'right', 'right', 'top', 'top', 'top', 'top', 'left', 'bottom', 'right', 'right', 'left', 'bottom', 'left', 'none'];
2209 var edge;
2210
2211 var startCell = grid[j][i];
2212 var currentCell = grid[j][i];
2213
2214 var cval = currentCell.cval;
2215 var edge = startEdge[cval];
2216
2217 var pt = getXY(currentCell, edge);
2218
2219 /* push initial segment */
2220 p.push([i + pt[0], j + pt[1]]);
2221 edge = nextEdge[cval];
2222 pt = getXY(currentCell, edge);
2223 p.push([i + pt[0], j + pt[1]]);
2224 clearCell(currentCell);
2225
2226 /* now walk arround the enclosed area in clockwise-direction */
2227 var k = i + dxContour[cval];
2228 var l = j + dyContour[cval];
2229 var prev_cval = cval;
2230
2231 while ((k >= 0) && (l >= 0) && (l < maxj) && ((k != i) || (l != j))) {
2232 currentCell = grid[l][k];
2233 if (typeof currentCell === 'undefined') { /* path ends here */
2234 //console.log(k + " " + l + " is undefined, stopping path!");
2235 break;
2236 }
2237 cval = currentCell.cval;
2238 if ((cval === 0) || (cval === 15)) {
2239 return { path: p, info: 'mergeable' };
2240 }
2241 edge = nextEdge[cval];
2242 dx = dxContour[cval];
2243 dy = dyContour[cval];
2244 if ((cval === 5) || (cval === 10)) {
2245 /* select upper or lower band, depending on previous cells cval */
2246 if (cval === 5) {
2247 if (currentCell.flipped) { /* this is actually a flipped case 10 */
2248 if (dyContour[prev_cval] === -1) {
2249 edge = 'left';
2250 dx = -1;
2251 dy = 0;
2252 } else {
2253 edge = 'right';
2254 dx = 1;
2255 dy = 0;
2256 }
2257 } else { /* real case 5 */
2258 if (dxContour[prev_cval] === -1) {
2259 edge = 'bottom';
2260 dx = 0;
2261 dy = -1;
2262 }
2263 }
2264 } else if (cval === 10) {
2265 if (currentCell.flipped) { /* this is actually a flipped case 5 */
2266 if (dxContour[prev_cval] === -1) {
2267 edge = 'top';
2268 dx = 0;
2269 dy = 1;
2270 } else {
2271 edge = 'bottom';
2272 dx = 0;
2273 dy = -1;
2274 }
2275 } else { /* real case 10 */
2276 if (dyContour[prev_cval] === 1) {
2277 edge = 'left';
2278 dx = -1;
2279 dy = 0;
2280 }
2281 }
2282 }
2283 }
2284 pt = getXY(currentCell, edge);
2285 p.push([k + pt[0], l + pt[1]]);
2286 clearCell(currentCell);
2287 k += dx;
2288 l += dy;
2289 prev_cval = cval;
2290 }
2291
2292 return { path: p, info: 'closed' };
2293}
2294
2295/**
2296 * Takes a {@link Point} grid and returns a correspondent matrix {Array<Array<number>>}
2297 * of the 'property' values
2298 *
2299 * @name gridToMatrix
2300 * @param {FeatureCollection<Point>} grid of points
2301 * @param {Object} [options={}] Optional parameters
2302 * @param {string} [options.zProperty='elevation'] the property name in `points` from which z-values will be pulled
2303 * @param {boolean} [options.flip=false] returns the matrix upside-down
2304 * @param {boolean} [options.flags=false] flags, adding a `matrixPosition` array field ([row, column]) to its properties,
2305 * the grid points with coordinates on the matrix
2306 * @returns {Array<Array<number>>} matrix of property values
2307 * @example
2308 * var extent = [-70.823364, -33.553984, -70.473175, -33.302986];
2309 * var cellSize = 3;
2310 * var grid = turf.pointGrid(extent, cellSize);
2311 * // add a random property to each point between 0 and 60
2312 * for (var i = 0; i < grid.features.length; i++) {
2313 * grid.features[i].properties.elevation = (Math.random() * 60);
2314 * }
2315 * gridToMatrix(grid);
2316 * //= [
2317 * [ 1, 13, 10, 9, 10, 13, 18],
2318 * [34, 8, 5, 4, 5, 8, 13],
2319 * [10, 5, 2, 1, 2, 5, 4],
2320 * [ 0, 4, 56, 19, 1, 4, 9],
2321 * [10, 5, 2, 1, 2, 5, 10],
2322 * [57, 8, 5, 4, 5, 0, 57],
2323 * [ 3, 13, 10, 9, 5, 13, 18],
2324 * [18, 13, 10, 9, 78, 13, 18]
2325 * ]
2326 */
2327function gridToMatrix(grid, options) {
2328 // Optional parameters
2329 options = options || {};
2330 if (!isObject(options)) throw new Error('options is invalid');
2331 var zProperty = options.zProperty || 'elevation';
2332 var flip = options.flip;
2333 var flags = options.flags;
2334
2335 // validation
2336 collectionOf(grid, 'Point', 'input must contain Points');
2337
2338 var pointsMatrix = sortPointsByLatLng(grid, flip);
2339
2340 var matrix = [];
2341 // create property matrix from sorted points
2342 // looping order matters here
2343 for (var r = 0; r < pointsMatrix.length; r++) {
2344 var pointRow = pointsMatrix[r];
2345 var row = [];
2346 for (var c = 0; c < pointRow.length; c++) {
2347 var point$$1 = pointRow[c];
2348 // Check if zProperty exist
2349 if (point$$1.properties[zProperty]) row.push(point$$1.properties[zProperty]);
2350 else row.push(0);
2351 // add flags
2352 if (flags === true) point$$1.properties.matrixPosition = [r, c];
2353 }
2354 matrix.push(row);
2355 }
2356
2357 return matrix;
2358}
2359
2360/**
2361 * Sorts points by latitude and longitude, creating a 2-dimensional array of points
2362 *
2363 * @private
2364 * @param {FeatureCollection<Point>} points GeoJSON Point features
2365 * @param {boolean} [flip=false] returns the matrix upside-down
2366 * @returns {Array<Array<Point>>} points ordered by latitude and longitude
2367 */
2368function sortPointsByLatLng(points$$1, flip) {
2369 var pointsByLatitude = {};
2370
2371 // divide points by rows with the same latitude
2372 featureEach(points$$1, function (point$$1) {
2373 var lat = getCoords(point$$1)[1];
2374 if (!pointsByLatitude[lat]) pointsByLatitude[lat] = [];
2375 pointsByLatitude[lat].push(point$$1);
2376 });
2377
2378 // sort points (with the same latitude) by longitude
2379 var orderedRowsByLatitude = Object.keys(pointsByLatitude).map(function (lat) {
2380 var row = pointsByLatitude[lat];
2381 var rowOrderedByLongitude = row.sort(function (a, b) {
2382 return getCoords(a)[0] - getCoords(b)[0];
2383 });
2384 return rowOrderedByLongitude;
2385 });
2386
2387 // sort rows (of points with the same latitude) by latitude
2388 var pointMatrix = orderedRowsByLatitude.sort(function (a, b) {
2389 if (flip) return getCoords(a[0])[1] - getCoords(b[0])[1];
2390 else return getCoords(b[0])[1] - getCoords(a[0])[1];
2391 });
2392
2393 return pointMatrix;
2394}
2395
2396/**
2397 * Takes a grid {@link FeatureCollection} of {@link Point} features with z-values and an array of
2398 * value breaks and generates [isolines](http://en.wikipedia.org/wiki/Isoline).
2399 *
2400 * @name isolines
2401 * @param {FeatureCollection<Point>} pointGrid input points
2402 * @param {Array<number>} breaks values of `zProperty` where to draw isolines
2403 * @param {Object} [options={}] Optional parameters
2404 * @param {string} [options.zProperty='elevation'] the property name in `points` from which z-values will be pulled
2405 * @param {Object} [options.commonProperties={}] GeoJSON properties passed to ALL isolines
2406 * @param {Array<Object>} [options.breaksProperties=[]] GeoJSON properties passed, in order, to the correspondent isoline;
2407 * the breaks array will define the order in which the isolines are created
2408 * @returns {FeatureCollection<MultiLineString>} a FeatureCollection of {@link MultiLineString} features representing isolines
2409 * @example
2410 * // create a grid of points with random z-values in their properties
2411 * var extent = [0, 30, 20, 50];
2412 * var cellWidth = 100;
2413 * var pointGrid = turf.pointGrid(extent, cellWidth, {units: 'miles'});
2414 *
2415 * for (var i = 0; i < pointGrid.features.length; i++) {
2416 * pointGrid.features[i].properties.temperature = Math.random() * 10;
2417 * }
2418 * var breaks = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
2419 *
2420 * var lines = turf.isolines(pointGrid, breaks, {zProperty: 'temperature'});
2421 *
2422 * //addToMap
2423 * var addToMap = [lines];
2424 */
2425function isolines(pointGrid, breaks, options) {
2426 // Optional parameters
2427 options = options || {};
2428 if (!isObject(options)) throw new Error('options is invalid');
2429 var zProperty = options.zProperty || 'elevation';
2430 var commonProperties = options.commonProperties || {};
2431 var breaksProperties = options.breaksProperties || [];
2432
2433 // Input validation
2434 collectionOf(pointGrid, 'Point', 'Input must contain Points');
2435 if (!breaks) throw new Error('breaks is required');
2436 if (!Array.isArray(breaks)) throw new Error('breaks must be an Array');
2437 if (!isObject(commonProperties)) throw new Error('commonProperties must be an Object');
2438 if (!Array.isArray(breaksProperties)) throw new Error('breaksProperties must be an Array');
2439
2440 // Isoline methods
2441 var matrix = gridToMatrix(pointGrid, {zProperty: zProperty, flip: true});
2442 var createdIsoLines = createIsoLines(matrix, breaks, zProperty, commonProperties, breaksProperties);
2443 var scaledIsolines = rescaleIsolines(createdIsoLines, matrix, pointGrid);
2444
2445 return featureCollection(scaledIsolines);
2446}
2447
2448/**
2449 * Creates the isolines lines (featuresCollection of MultiLineString features) from the 2D data grid
2450 *
2451 * Marchingsquares process the grid data as a 3D representation of a function on a 2D plane, therefore it
2452 * assumes the points (x-y coordinates) are one 'unit' distance. The result of the isolines function needs to be
2453 * rescaled, with turfjs, to the original area and proportions on the map
2454 *
2455 * @private
2456 * @param {Array<Array<number>>} matrix Grid Data
2457 * @param {Array<number>} breaks Breaks
2458 * @param {string} zProperty name of the z-values property
2459 * @param {Object} [commonProperties={}] GeoJSON properties passed to ALL isolines
2460 * @param {Object} [breaksProperties=[]] GeoJSON properties passed to the correspondent isoline
2461 * @returns {Array<MultiLineString>} isolines
2462 */
2463function createIsoLines(matrix, breaks, zProperty, commonProperties, breaksProperties) {
2464 var results = [];
2465 for (var i = 1; i < breaks.length; i++) {
2466 var threshold = +breaks[i]; // make sure it's a number
2467
2468 var properties = Object.assign(
2469 {},
2470 commonProperties,
2471 breaksProperties[i]
2472 );
2473 properties[zProperty] = threshold;
2474 var isoline = multiLineString(isoContours(matrix, threshold), properties);
2475
2476 results.push(isoline);
2477 }
2478 return results;
2479}
2480
2481/**
2482 * Translates and scales isolines
2483 *
2484 * @private
2485 * @param {Array<MultiLineString>} createdIsoLines to be rescaled
2486 * @param {Array<Array<number>>} matrix Grid Data
2487 * @param {Object} points Points by Latitude
2488 * @returns {Array<MultiLineString>} isolines
2489 */
2490function rescaleIsolines(createdIsoLines, matrix, points$$1) {
2491
2492 // get dimensions (on the map) of the original grid
2493 var gridBbox = bbox(points$$1); // [ minX, minY, maxX, maxY ]
2494 var originalWidth = gridBbox[2] - gridBbox[0];
2495 var originalHeigth = gridBbox[3] - gridBbox[1];
2496
2497 // get origin, which is the first point of the last row on the rectangular data on the map
2498 var x0 = gridBbox[0];
2499 var y0 = gridBbox[1];
2500
2501 // get number of cells per side
2502 var matrixWidth = matrix[0].length - 1;
2503 var matrixHeight = matrix.length - 1;
2504
2505 // calculate the scaling factor between matrix and rectangular grid on the map
2506 var scaleX = originalWidth / matrixWidth;
2507 var scaleY = originalHeigth / matrixHeight;
2508
2509 var resize = function (point$$1) {
2510 point$$1[0] = point$$1[0] * scaleX + x0;
2511 point$$1[1] = point$$1[1] * scaleY + y0;
2512 };
2513
2514 // resize and shift each point/line of the createdIsoLines
2515 createdIsoLines.forEach(function (isoline) {
2516 coordEach(isoline, resize);
2517 });
2518 return createdIsoLines;
2519}
2520
2521var quickselect = partialSort;
2522
2523// Floyd-Rivest selection algorithm:
2524// Rearrange items so that all items in the [left, k] range are smaller than all items in (k, right];
2525// The k-th element will have the (k - left + 1)th smallest value in [left, right]
2526
2527function partialSort(arr, k, left, right, compare) {
2528 left = left || 0;
2529 right = right || (arr.length - 1);
2530 compare = compare || defaultCompare;
2531
2532 while (right > left) {
2533 if (right - left > 600) {
2534 var n = right - left + 1;
2535 var m = k - left + 1;
2536 var z = Math.log(n);
2537 var s = 0.5 * Math.exp(2 * z / 3);
2538 var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
2539 var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
2540 var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
2541 partialSort(arr, k, newLeft, newRight, compare);
2542 }
2543
2544 var t = arr[k];
2545 var i = left;
2546 var j = right;
2547
2548 swap(arr, left, k);
2549 if (compare(arr[right], t) > 0) swap(arr, left, right);
2550
2551 while (i < j) {
2552 swap(arr, i, j);
2553 i++;
2554 j--;
2555 while (compare(arr[i], t) < 0) i++;
2556 while (compare(arr[j], t) > 0) j--;
2557 }
2558
2559 if (compare(arr[left], t) === 0) swap(arr, left, j);
2560 else {
2561 j++;
2562 swap(arr, j, right);
2563 }
2564
2565 if (j <= k) left = j + 1;
2566 if (k <= j) right = j - 1;
2567 }
2568}
2569
2570function swap(arr, i, j) {
2571 var tmp = arr[i];
2572 arr[i] = arr[j];
2573 arr[j] = tmp;
2574}
2575
2576function defaultCompare(a, b) {
2577 return a < b ? -1 : a > b ? 1 : 0;
2578}
2579
2580var rbush_1 = rbush;
2581
2582
2583
2584function rbush(maxEntries, format) {
2585 if (!(this instanceof rbush)) return new rbush(maxEntries, format);
2586
2587 // max entries in a node is 9 by default; min node fill is 40% for best performance
2588 this._maxEntries = Math.max(4, maxEntries || 9);
2589 this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
2590
2591 if (format) {
2592 this._initFormat(format);
2593 }
2594
2595 this.clear();
2596}
2597
2598rbush.prototype = {
2599
2600 all: function () {
2601 return this._all(this.data, []);
2602 },
2603
2604 search: function (bbox) {
2605
2606 var node = this.data,
2607 result = [],
2608 toBBox = this.toBBox;
2609
2610 if (!intersects$1(bbox, node)) return result;
2611
2612 var nodesToSearch = [],
2613 i, len, child, childBBox;
2614
2615 while (node) {
2616 for (i = 0, len = node.children.length; i < len; i++) {
2617
2618 child = node.children[i];
2619 childBBox = node.leaf ? toBBox(child) : child;
2620
2621 if (intersects$1(bbox, childBBox)) {
2622 if (node.leaf) result.push(child);
2623 else if (contains(bbox, childBBox)) this._all(child, result);
2624 else nodesToSearch.push(child);
2625 }
2626 }
2627 node = nodesToSearch.pop();
2628 }
2629
2630 return result;
2631 },
2632
2633 collides: function (bbox) {
2634
2635 var node = this.data,
2636 toBBox = this.toBBox;
2637
2638 if (!intersects$1(bbox, node)) return false;
2639
2640 var nodesToSearch = [],
2641 i, len, child, childBBox;
2642
2643 while (node) {
2644 for (i = 0, len = node.children.length; i < len; i++) {
2645
2646 child = node.children[i];
2647 childBBox = node.leaf ? toBBox(child) : child;
2648
2649 if (intersects$1(bbox, childBBox)) {
2650 if (node.leaf || contains(bbox, childBBox)) return true;
2651 nodesToSearch.push(child);
2652 }
2653 }
2654 node = nodesToSearch.pop();
2655 }
2656
2657 return false;
2658 },
2659
2660 load: function (data) {
2661 if (!(data && data.length)) return this;
2662
2663 if (data.length < this._minEntries) {
2664 for (var i = 0, len = data.length; i < len; i++) {
2665 this.insert(data[i]);
2666 }
2667 return this;
2668 }
2669
2670 // recursively build the tree with the given data from stratch using OMT algorithm
2671 var node = this._build(data.slice(), 0, data.length - 1, 0);
2672
2673 if (!this.data.children.length) {
2674 // save as is if tree is empty
2675 this.data = node;
2676
2677 } else if (this.data.height === node.height) {
2678 // split root if trees have the same height
2679 this._splitRoot(this.data, node);
2680
2681 } else {
2682 if (this.data.height < node.height) {
2683 // swap trees if inserted one is bigger
2684 var tmpNode = this.data;
2685 this.data = node;
2686 node = tmpNode;
2687 }
2688
2689 // insert the small tree into the large tree at appropriate level
2690 this._insert(node, this.data.height - node.height - 1, true);
2691 }
2692
2693 return this;
2694 },
2695
2696 insert: function (item) {
2697 if (item) this._insert(item, this.data.height - 1);
2698 return this;
2699 },
2700
2701 clear: function () {
2702 this.data = createNode([]);
2703 return this;
2704 },
2705
2706 remove: function (item, equalsFn) {
2707 if (!item) return this;
2708
2709 var node = this.data,
2710 bbox = this.toBBox(item),
2711 path = [],
2712 indexes = [],
2713 i, parent, index, goingUp;
2714
2715 // depth-first iterative tree traversal
2716 while (node || path.length) {
2717
2718 if (!node) { // go up
2719 node = path.pop();
2720 parent = path[path.length - 1];
2721 i = indexes.pop();
2722 goingUp = true;
2723 }
2724
2725 if (node.leaf) { // check current node
2726 index = findItem(item, node.children, equalsFn);
2727
2728 if (index !== -1) {
2729 // item found, remove the item and condense tree upwards
2730 node.children.splice(index, 1);
2731 path.push(node);
2732 this._condense(path);
2733 return this;
2734 }
2735 }
2736
2737 if (!goingUp && !node.leaf && contains(node, bbox)) { // go down
2738 path.push(node);
2739 indexes.push(i);
2740 i = 0;
2741 parent = node;
2742 node = node.children[0];
2743
2744 } else if (parent) { // go right
2745 i++;
2746 node = parent.children[i];
2747 goingUp = false;
2748
2749 } else node = null; // nothing found
2750 }
2751
2752 return this;
2753 },
2754
2755 toBBox: function (item) { return item; },
2756
2757 compareMinX: compareNodeMinX,
2758 compareMinY: compareNodeMinY,
2759
2760 toJSON: function () { return this.data; },
2761
2762 fromJSON: function (data) {
2763 this.data = data;
2764 return this;
2765 },
2766
2767 _all: function (node, result) {
2768 var nodesToSearch = [];
2769 while (node) {
2770 if (node.leaf) result.push.apply(result, node.children);
2771 else nodesToSearch.push.apply(nodesToSearch, node.children);
2772
2773 node = nodesToSearch.pop();
2774 }
2775 return result;
2776 },
2777
2778 _build: function (items, left, right, height) {
2779
2780 var N = right - left + 1,
2781 M = this._maxEntries,
2782 node;
2783
2784 if (N <= M) {
2785 // reached leaf level; return leaf
2786 node = createNode(items.slice(left, right + 1));
2787 calcBBox(node, this.toBBox);
2788 return node;
2789 }
2790
2791 if (!height) {
2792 // target height of the bulk-loaded tree
2793 height = Math.ceil(Math.log(N) / Math.log(M));
2794
2795 // target number of root entries to maximize storage utilization
2796 M = Math.ceil(N / Math.pow(M, height - 1));
2797 }
2798
2799 node = createNode([]);
2800 node.leaf = false;
2801 node.height = height;
2802
2803 // split the items into M mostly square tiles
2804
2805 var N2 = Math.ceil(N / M),
2806 N1 = N2 * Math.ceil(Math.sqrt(M)),
2807 i, j, right2, right3;
2808
2809 multiSelect(items, left, right, N1, this.compareMinX);
2810
2811 for (i = left; i <= right; i += N1) {
2812
2813 right2 = Math.min(i + N1 - 1, right);
2814
2815 multiSelect(items, i, right2, N2, this.compareMinY);
2816
2817 for (j = i; j <= right2; j += N2) {
2818
2819 right3 = Math.min(j + N2 - 1, right2);
2820
2821 // pack each entry recursively
2822 node.children.push(this._build(items, j, right3, height - 1));
2823 }
2824 }
2825
2826 calcBBox(node, this.toBBox);
2827
2828 return node;
2829 },
2830
2831 _chooseSubtree: function (bbox, node, level, path) {
2832
2833 var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
2834
2835 while (true) {
2836 path.push(node);
2837
2838 if (node.leaf || path.length - 1 === level) break;
2839
2840 minArea = minEnlargement = Infinity;
2841
2842 for (i = 0, len = node.children.length; i < len; i++) {
2843 child = node.children[i];
2844 area = bboxArea(child);
2845 enlargement = enlargedArea(bbox, child) - area;
2846
2847 // choose entry with the least area enlargement
2848 if (enlargement < minEnlargement) {
2849 minEnlargement = enlargement;
2850 minArea = area < minArea ? area : minArea;
2851 targetNode = child;
2852
2853 } else if (enlargement === minEnlargement) {
2854 // otherwise choose one with the smallest area
2855 if (area < minArea) {
2856 minArea = area;
2857 targetNode = child;
2858 }
2859 }
2860 }
2861
2862 node = targetNode || node.children[0];
2863 }
2864
2865 return node;
2866 },
2867
2868 _insert: function (item, level, isNode) {
2869
2870 var toBBox = this.toBBox,
2871 bbox = isNode ? item : toBBox(item),
2872 insertPath = [];
2873
2874 // find the best node for accommodating the item, saving all nodes along the path too
2875 var node = this._chooseSubtree(bbox, this.data, level, insertPath);
2876
2877 // put the item into the node
2878 node.children.push(item);
2879 extend(node, bbox);
2880
2881 // split on node overflow; propagate upwards if necessary
2882 while (level >= 0) {
2883 if (insertPath[level].children.length > this._maxEntries) {
2884 this._split(insertPath, level);
2885 level--;
2886 } else break;
2887 }
2888
2889 // adjust bboxes along the insertion path
2890 this._adjustParentBBoxes(bbox, insertPath, level);
2891 },
2892
2893 // split overflowed node into two
2894 _split: function (insertPath, level) {
2895
2896 var node = insertPath[level],
2897 M = node.children.length,
2898 m = this._minEntries;
2899
2900 this._chooseSplitAxis(node, m, M);
2901
2902 var splitIndex = this._chooseSplitIndex(node, m, M);
2903
2904 var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
2905 newNode.height = node.height;
2906 newNode.leaf = node.leaf;
2907
2908 calcBBox(node, this.toBBox);
2909 calcBBox(newNode, this.toBBox);
2910
2911 if (level) insertPath[level - 1].children.push(newNode);
2912 else this._splitRoot(node, newNode);
2913 },
2914
2915 _splitRoot: function (node, newNode) {
2916 // split root node
2917 this.data = createNode([node, newNode]);
2918 this.data.height = node.height + 1;
2919 this.data.leaf = false;
2920 calcBBox(this.data, this.toBBox);
2921 },
2922
2923 _chooseSplitIndex: function (node, m, M) {
2924
2925 var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
2926
2927 minOverlap = minArea = Infinity;
2928
2929 for (i = m; i <= M - m; i++) {
2930 bbox1 = distBBox(node, 0, i, this.toBBox);
2931 bbox2 = distBBox(node, i, M, this.toBBox);
2932
2933 overlap = intersectionArea(bbox1, bbox2);
2934 area = bboxArea(bbox1) + bboxArea(bbox2);
2935
2936 // choose distribution with minimum overlap
2937 if (overlap < minOverlap) {
2938 minOverlap = overlap;
2939 index = i;
2940
2941 minArea = area < minArea ? area : minArea;
2942
2943 } else if (overlap === minOverlap) {
2944 // otherwise choose distribution with minimum area
2945 if (area < minArea) {
2946 minArea = area;
2947 index = i;
2948 }
2949 }
2950 }
2951
2952 return index;
2953 },
2954
2955 // sorts node children by the best axis for split
2956 _chooseSplitAxis: function (node, m, M) {
2957
2958 var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX,
2959 compareMinY = node.leaf ? this.compareMinY : compareNodeMinY,
2960 xMargin = this._allDistMargin(node, m, M, compareMinX),
2961 yMargin = this._allDistMargin(node, m, M, compareMinY);
2962
2963 // if total distributions margin value is minimal for x, sort by minX,
2964 // otherwise it's already sorted by minY
2965 if (xMargin < yMargin) node.children.sort(compareMinX);
2966 },
2967
2968 // total margin of all possible split distributions where each node is at least m full
2969 _allDistMargin: function (node, m, M, compare) {
2970
2971 node.children.sort(compare);
2972
2973 var toBBox = this.toBBox,
2974 leftBBox = distBBox(node, 0, m, toBBox),
2975 rightBBox = distBBox(node, M - m, M, toBBox),
2976 margin = bboxMargin(leftBBox) + bboxMargin(rightBBox),
2977 i, child;
2978
2979 for (i = m; i < M - m; i++) {
2980 child = node.children[i];
2981 extend(leftBBox, node.leaf ? toBBox(child) : child);
2982 margin += bboxMargin(leftBBox);
2983 }
2984
2985 for (i = M - m - 1; i >= m; i--) {
2986 child = node.children[i];
2987 extend(rightBBox, node.leaf ? toBBox(child) : child);
2988 margin += bboxMargin(rightBBox);
2989 }
2990
2991 return margin;
2992 },
2993
2994 _adjustParentBBoxes: function (bbox, path, level) {
2995 // adjust bboxes along the given tree path
2996 for (var i = level; i >= 0; i--) {
2997 extend(path[i], bbox);
2998 }
2999 },
3000
3001 _condense: function (path) {
3002 // go through the path, removing empty nodes and updating bboxes
3003 for (var i = path.length - 1, siblings; i >= 0; i--) {
3004 if (path[i].children.length === 0) {
3005 if (i > 0) {
3006 siblings = path[i - 1].children;
3007 siblings.splice(siblings.indexOf(path[i]), 1);
3008
3009 } else this.clear();
3010
3011 } else calcBBox(path[i], this.toBBox);
3012 }
3013 },
3014
3015 _initFormat: function (format) {
3016 // data format (minX, minY, maxX, maxY accessors)
3017
3018 // uses eval-type function compilation instead of just accepting a toBBox function
3019 // because the algorithms are very sensitive to sorting functions performance,
3020 // so they should be dead simple and without inner calls
3021
3022 var compareArr = ['return a', ' - b', ';'];
3023
3024 this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
3025 this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
3026
3027 this.toBBox = new Function('a',
3028 'return {minX: a' + format[0] +
3029 ', minY: a' + format[1] +
3030 ', maxX: a' + format[2] +
3031 ', maxY: a' + format[3] + '};');
3032 }
3033};
3034
3035function findItem(item, items, equalsFn) {
3036 if (!equalsFn) return items.indexOf(item);
3037
3038 for (var i = 0; i < items.length; i++) {
3039 if (equalsFn(item, items[i])) return i;
3040 }
3041 return -1;
3042}
3043
3044// calculate node's bbox from bboxes of its children
3045function calcBBox(node, toBBox) {
3046 distBBox(node, 0, node.children.length, toBBox, node);
3047}
3048
3049// min bounding rectangle of node children from k to p-1
3050function distBBox(node, k, p, toBBox, destNode) {
3051 if (!destNode) destNode = createNode(null);
3052 destNode.minX = Infinity;
3053 destNode.minY = Infinity;
3054 destNode.maxX = -Infinity;
3055 destNode.maxY = -Infinity;
3056
3057 for (var i = k, child; i < p; i++) {
3058 child = node.children[i];
3059 extend(destNode, node.leaf ? toBBox(child) : child);
3060 }
3061
3062 return destNode;
3063}
3064
3065function extend(a, b) {
3066 a.minX = Math.min(a.minX, b.minX);
3067 a.minY = Math.min(a.minY, b.minY);
3068 a.maxX = Math.max(a.maxX, b.maxX);
3069 a.maxY = Math.max(a.maxY, b.maxY);
3070 return a;
3071}
3072
3073function compareNodeMinX(a, b) { return a.minX - b.minX; }
3074function compareNodeMinY(a, b) { return a.minY - b.minY; }
3075
3076function bboxArea(a) { return (a.maxX - a.minX) * (a.maxY - a.minY); }
3077function bboxMargin(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); }
3078
3079function enlargedArea(a, b) {
3080 return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) *
3081 (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
3082}
3083
3084function intersectionArea(a, b) {
3085 var minX = Math.max(a.minX, b.minX),
3086 minY = Math.max(a.minY, b.minY),
3087 maxX = Math.min(a.maxX, b.maxX),
3088 maxY = Math.min(a.maxY, b.maxY);
3089
3090 return Math.max(0, maxX - minX) *
3091 Math.max(0, maxY - minY);
3092}
3093
3094function contains(a, b) {
3095 return a.minX <= b.minX &&
3096 a.minY <= b.minY &&
3097 b.maxX <= a.maxX &&
3098 b.maxY <= a.maxY;
3099}
3100
3101function intersects$1(a, b) {
3102 return b.minX <= a.maxX &&
3103 b.minY <= a.maxY &&
3104 b.maxX >= a.minX &&
3105 b.maxY >= a.minY;
3106}
3107
3108function createNode(children) {
3109 return {
3110 children: children,
3111 height: 1,
3112 leaf: true,
3113 minX: Infinity,
3114 minY: Infinity,
3115 maxX: -Infinity,
3116 maxY: -Infinity
3117 };
3118}
3119
3120// sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
3121// combines selection algorithm with binary divide & conquer approach
3122
3123function multiSelect(arr, left, right, n, compare) {
3124 var stack = [left, right],
3125 mid;
3126
3127 while (stack.length) {
3128 right = stack.pop();
3129 left = stack.pop();
3130
3131 if (right - left <= n) continue;
3132
3133 mid = left + Math.ceil((right - left) / n / 2) * n;
3134 quickselect(arr, mid, left, right, compare);
3135
3136 stack.push(left, mid, mid, right);
3137 }
3138}
3139
3140function createCommonjsModule(fn, module) {
3141 return module = { exports: {} }, fn(module, module.exports), module.exports;
3142}
3143
3144var twoProduct_1 = twoProduct;
3145
3146var SPLITTER = +(Math.pow(2, 27) + 1.0);
3147
3148function twoProduct(a, b, result) {
3149 var x = a * b;
3150
3151 var c = SPLITTER * a;
3152 var abig = c - a;
3153 var ahi = c - abig;
3154 var alo = a - ahi;
3155
3156 var d = SPLITTER * b;
3157 var bbig = d - b;
3158 var bhi = d - bbig;
3159 var blo = b - bhi;
3160
3161 var err1 = x - (ahi * bhi);
3162 var err2 = err1 - (alo * bhi);
3163 var err3 = err2 - (ahi * blo);
3164
3165 var y = alo * blo - err3;
3166
3167 if(result) {
3168 result[0] = y;
3169 result[1] = x;
3170 return result
3171 }
3172
3173 return [ y, x ]
3174}
3175
3176var robustSum = linearExpansionSum;
3177
3178//Easy case: Add two scalars
3179function scalarScalar(a, b) {
3180 var x = a + b;
3181 var bv = x - a;
3182 var av = x - bv;
3183 var br = b - bv;
3184 var ar = a - av;
3185 var y = ar + br;
3186 if(y) {
3187 return [y, x]
3188 }
3189 return [x]
3190}
3191
3192function linearExpansionSum(e, f) {
3193 var ne = e.length|0;
3194 var nf = f.length|0;
3195 if(ne === 1 && nf === 1) {
3196 return scalarScalar(e[0], f[0])
3197 }
3198 var n = ne + nf;
3199 var g = new Array(n);
3200 var count = 0;
3201 var eptr = 0;
3202 var fptr = 0;
3203 var abs = Math.abs;
3204 var ei = e[eptr];
3205 var ea = abs(ei);
3206 var fi = f[fptr];
3207 var fa = abs(fi);
3208 var a, b;
3209 if(ea < fa) {
3210 b = ei;
3211 eptr += 1;
3212 if(eptr < ne) {
3213 ei = e[eptr];
3214 ea = abs(ei);
3215 }
3216 } else {
3217 b = fi;
3218 fptr += 1;
3219 if(fptr < nf) {
3220 fi = f[fptr];
3221 fa = abs(fi);
3222 }
3223 }
3224 if((eptr < ne && ea < fa) || (fptr >= nf)) {
3225 a = ei;
3226 eptr += 1;
3227 if(eptr < ne) {
3228 ei = e[eptr];
3229 ea = abs(ei);
3230 }
3231 } else {
3232 a = fi;
3233 fptr += 1;
3234 if(fptr < nf) {
3235 fi = f[fptr];
3236 fa = abs(fi);
3237 }
3238 }
3239 var x = a + b;
3240 var bv = x - a;
3241 var y = b - bv;
3242 var q0 = y;
3243 var q1 = x;
3244 var _x, _bv, _av, _br, _ar;
3245 while(eptr < ne && fptr < nf) {
3246 if(ea < fa) {
3247 a = ei;
3248 eptr += 1;
3249 if(eptr < ne) {
3250 ei = e[eptr];
3251 ea = abs(ei);
3252 }
3253 } else {
3254 a = fi;
3255 fptr += 1;
3256 if(fptr < nf) {
3257 fi = f[fptr];
3258 fa = abs(fi);
3259 }
3260 }
3261 b = q0;
3262 x = a + b;
3263 bv = x - a;
3264 y = b - bv;
3265 if(y) {
3266 g[count++] = y;
3267 }
3268 _x = q1 + x;
3269 _bv = _x - q1;
3270 _av = _x - _bv;
3271 _br = x - _bv;
3272 _ar = q1 - _av;
3273 q0 = _ar + _br;
3274 q1 = _x;
3275 }
3276 while(eptr < ne) {
3277 a = ei;
3278 b = q0;
3279 x = a + b;
3280 bv = x - a;
3281 y = b - bv;
3282 if(y) {
3283 g[count++] = y;
3284 }
3285 _x = q1 + x;
3286 _bv = _x - q1;
3287 _av = _x - _bv;
3288 _br = x - _bv;
3289 _ar = q1 - _av;
3290 q0 = _ar + _br;
3291 q1 = _x;
3292 eptr += 1;
3293 if(eptr < ne) {
3294 ei = e[eptr];
3295 }
3296 }
3297 while(fptr < nf) {
3298 a = fi;
3299 b = q0;
3300 x = a + b;
3301 bv = x - a;
3302 y = b - bv;
3303 if(y) {
3304 g[count++] = y;
3305 }
3306 _x = q1 + x;
3307 _bv = _x - q1;
3308 _av = _x - _bv;
3309 _br = x - _bv;
3310 _ar = q1 - _av;
3311 q0 = _ar + _br;
3312 q1 = _x;
3313 fptr += 1;
3314 if(fptr < nf) {
3315 fi = f[fptr];
3316 }
3317 }
3318 if(q0) {
3319 g[count++] = q0;
3320 }
3321 if(q1) {
3322 g[count++] = q1;
3323 }
3324 if(!count) {
3325 g[count++] = 0.0;
3326 }
3327 g.length = count;
3328 return g
3329}
3330
3331var twoSum = fastTwoSum;
3332
3333function fastTwoSum(a, b, result) {
3334 var x = a + b;
3335 var bv = x - a;
3336 var av = x - bv;
3337 var br = b - bv;
3338 var ar = a - av;
3339 if(result) {
3340 result[0] = ar + br;
3341 result[1] = x;
3342 return result
3343 }
3344 return [ar+br, x]
3345}
3346
3347var robustScale = scaleLinearExpansion;
3348
3349function scaleLinearExpansion(e, scale) {
3350 var n = e.length;
3351 if(n === 1) {
3352 var ts = twoProduct_1(e[0], scale);
3353 if(ts[0]) {
3354 return ts
3355 }
3356 return [ ts[1] ]
3357 }
3358 var g = new Array(2 * n);
3359 var q = [0.1, 0.1];
3360 var t = [0.1, 0.1];
3361 var count = 0;
3362 twoProduct_1(e[0], scale, q);
3363 if(q[0]) {
3364 g[count++] = q[0];
3365 }
3366 for(var i=1; i<n; ++i) {
3367 twoProduct_1(e[i], scale, t);
3368 var pq = q[1];
3369 twoSum(pq, t[0], q);
3370 if(q[0]) {
3371 g[count++] = q[0];
3372 }
3373 var a = t[1];
3374 var b = q[1];
3375 var x = a + b;
3376 var bv = x - a;
3377 var y = b - bv;
3378 q[1] = x;
3379 if(y) {
3380 g[count++] = y;
3381 }
3382 }
3383 if(q[1]) {
3384 g[count++] = q[1];
3385 }
3386 if(count === 0) {
3387 g[count++] = 0.0;
3388 }
3389 g.length = count;
3390 return g
3391}
3392
3393var robustDiff = robustSubtract;
3394
3395//Easy case: Add two scalars
3396function scalarScalar$1(a, b) {
3397 var x = a + b;
3398 var bv = x - a;
3399 var av = x - bv;
3400 var br = b - bv;
3401 var ar = a - av;
3402 var y = ar + br;
3403 if(y) {
3404 return [y, x]
3405 }
3406 return [x]
3407}
3408
3409function robustSubtract(e, f) {
3410 var ne = e.length|0;
3411 var nf = f.length|0;
3412 if(ne === 1 && nf === 1) {
3413 return scalarScalar$1(e[0], -f[0])
3414 }
3415 var n = ne + nf;
3416 var g = new Array(n);
3417 var count = 0;
3418 var eptr = 0;
3419 var fptr = 0;
3420 var abs = Math.abs;
3421 var ei = e[eptr];
3422 var ea = abs(ei);
3423 var fi = -f[fptr];
3424 var fa = abs(fi);
3425 var a, b;
3426 if(ea < fa) {
3427 b = ei;
3428 eptr += 1;
3429 if(eptr < ne) {
3430 ei = e[eptr];
3431 ea = abs(ei);
3432 }
3433 } else {
3434 b = fi;
3435 fptr += 1;
3436 if(fptr < nf) {
3437 fi = -f[fptr];
3438 fa = abs(fi);
3439 }
3440 }
3441 if((eptr < ne && ea < fa) || (fptr >= nf)) {
3442 a = ei;
3443 eptr += 1;
3444 if(eptr < ne) {
3445 ei = e[eptr];
3446 ea = abs(ei);
3447 }
3448 } else {
3449 a = fi;
3450 fptr += 1;
3451 if(fptr < nf) {
3452 fi = -f[fptr];
3453 fa = abs(fi);
3454 }
3455 }
3456 var x = a + b;
3457 var bv = x - a;
3458 var y = b - bv;
3459 var q0 = y;
3460 var q1 = x;
3461 var _x, _bv, _av, _br, _ar;
3462 while(eptr < ne && fptr < nf) {
3463 if(ea < fa) {
3464 a = ei;
3465 eptr += 1;
3466 if(eptr < ne) {
3467 ei = e[eptr];
3468 ea = abs(ei);
3469 }
3470 } else {
3471 a = fi;
3472 fptr += 1;
3473 if(fptr < nf) {
3474 fi = -f[fptr];
3475 fa = abs(fi);
3476 }
3477 }
3478 b = q0;
3479 x = a + b;
3480 bv = x - a;
3481 y = b - bv;
3482 if(y) {
3483 g[count++] = y;
3484 }
3485 _x = q1 + x;
3486 _bv = _x - q1;
3487 _av = _x - _bv;
3488 _br = x - _bv;
3489 _ar = q1 - _av;
3490 q0 = _ar + _br;
3491 q1 = _x;
3492 }
3493 while(eptr < ne) {
3494 a = ei;
3495 b = q0;
3496 x = a + b;
3497 bv = x - a;
3498 y = b - bv;
3499 if(y) {
3500 g[count++] = y;
3501 }
3502 _x = q1 + x;
3503 _bv = _x - q1;
3504 _av = _x - _bv;
3505 _br = x - _bv;
3506 _ar = q1 - _av;
3507 q0 = _ar + _br;
3508 q1 = _x;
3509 eptr += 1;
3510 if(eptr < ne) {
3511 ei = e[eptr];
3512 }
3513 }
3514 while(fptr < nf) {
3515 a = fi;
3516 b = q0;
3517 x = a + b;
3518 bv = x - a;
3519 y = b - bv;
3520 if(y) {
3521 g[count++] = y;
3522 }
3523 _x = q1 + x;
3524 _bv = _x - q1;
3525 _av = _x - _bv;
3526 _br = x - _bv;
3527 _ar = q1 - _av;
3528 q0 = _ar + _br;
3529 q1 = _x;
3530 fptr += 1;
3531 if(fptr < nf) {
3532 fi = -f[fptr];
3533 }
3534 }
3535 if(q0) {
3536 g[count++] = q0;
3537 }
3538 if(q1) {
3539 g[count++] = q1;
3540 }
3541 if(!count) {
3542 g[count++] = 0.0;
3543 }
3544 g.length = count;
3545 return g
3546}
3547
3548var orientation_1 = createCommonjsModule(function (module) {
3549var NUM_EXPAND = 5;
3550
3551var EPSILON = 1.1102230246251565e-16;
3552var ERRBOUND3 = (3.0 + 16.0 * EPSILON) * EPSILON;
3553var ERRBOUND4 = (7.0 + 56.0 * EPSILON) * EPSILON;
3554
3555function cofactor(m, c) {
3556 var result = new Array(m.length-1);
3557 for(var i=1; i<m.length; ++i) {
3558 var r = result[i-1] = new Array(m.length-1);
3559 for(var j=0,k=0; j<m.length; ++j) {
3560 if(j === c) {
3561 continue
3562 }
3563 r[k++] = m[i][j];
3564 }
3565 }
3566 return result
3567}
3568
3569function matrix(n) {
3570 var result = new Array(n);
3571 for(var i=0; i<n; ++i) {
3572 result[i] = new Array(n);
3573 for(var j=0; j<n; ++j) {
3574 result[i][j] = ["m", j, "[", (n-i-1), "]"].join("");
3575 }
3576 }
3577 return result
3578}
3579
3580function sign(n) {
3581 if(n & 1) {
3582 return "-"
3583 }
3584 return ""
3585}
3586
3587function generateSum(expr) {
3588 if(expr.length === 1) {
3589 return expr[0]
3590 } else if(expr.length === 2) {
3591 return ["sum(", expr[0], ",", expr[1], ")"].join("")
3592 } else {
3593 var m = expr.length>>1;
3594 return ["sum(", generateSum(expr.slice(0, m)), ",", generateSum(expr.slice(m)), ")"].join("")
3595 }
3596}
3597
3598function determinant(m) {
3599 if(m.length === 2) {
3600 return [["sum(prod(", m[0][0], ",", m[1][1], "),prod(-", m[0][1], ",", m[1][0], "))"].join("")]
3601 } else {
3602 var expr = [];
3603 for(var i=0; i<m.length; ++i) {
3604 expr.push(["scale(", generateSum(determinant(cofactor(m, i))), ",", sign(i), m[0][i], ")"].join(""));
3605 }
3606 return expr
3607 }
3608}
3609
3610function orientation(n) {
3611 var pos = [];
3612 var neg = [];
3613 var m = matrix(n);
3614 var args = [];
3615 for(var i=0; i<n; ++i) {
3616 if((i&1)===0) {
3617 pos.push.apply(pos, determinant(cofactor(m, i)));
3618 } else {
3619 neg.push.apply(neg, determinant(cofactor(m, i)));
3620 }
3621 args.push("m" + i);
3622 }
3623 var posExpr = generateSum(pos);
3624 var negExpr = generateSum(neg);
3625 var funcName = "orientation" + n + "Exact";
3626 var code = ["function ", funcName, "(", args.join(), "){var p=", posExpr, ",n=", negExpr, ",d=sub(p,n);\
3627return d[d.length-1];};return ", funcName].join("");
3628 var proc = new Function("sum", "prod", "scale", "sub", code);
3629 return proc(robustSum, twoProduct_1, robustScale, robustDiff)
3630}
3631
3632var orientation3Exact = orientation(3);
3633var orientation4Exact = orientation(4);
3634
3635var CACHED = [
3636 function orientation0() { return 0 },
3637 function orientation1() { return 0 },
3638 function orientation2(a, b) {
3639 return b[0] - a[0]
3640 },
3641 function orientation3(a, b, c) {
3642 var l = (a[1] - c[1]) * (b[0] - c[0]);
3643 var r = (a[0] - c[0]) * (b[1] - c[1]);
3644 var det = l - r;
3645 var s;
3646 if(l > 0) {
3647 if(r <= 0) {
3648 return det
3649 } else {
3650 s = l + r;
3651 }
3652 } else if(l < 0) {
3653 if(r >= 0) {
3654 return det
3655 } else {
3656 s = -(l + r);
3657 }
3658 } else {
3659 return det
3660 }
3661 var tol = ERRBOUND3 * s;
3662 if(det >= tol || det <= -tol) {
3663 return det
3664 }
3665 return orientation3Exact(a, b, c)
3666 },
3667 function orientation4(a,b,c,d) {
3668 var adx = a[0] - d[0];
3669 var bdx = b[0] - d[0];
3670 var cdx = c[0] - d[0];
3671 var ady = a[1] - d[1];
3672 var bdy = b[1] - d[1];
3673 var cdy = c[1] - d[1];
3674 var adz = a[2] - d[2];
3675 var bdz = b[2] - d[2];
3676 var cdz = c[2] - d[2];
3677 var bdxcdy = bdx * cdy;
3678 var cdxbdy = cdx * bdy;
3679 var cdxady = cdx * ady;
3680 var adxcdy = adx * cdy;
3681 var adxbdy = adx * bdy;
3682 var bdxady = bdx * ady;
3683 var det = adz * (bdxcdy - cdxbdy)
3684 + bdz * (cdxady - adxcdy)
3685 + cdz * (adxbdy - bdxady);
3686 var permanent = (Math.abs(bdxcdy) + Math.abs(cdxbdy)) * Math.abs(adz)
3687 + (Math.abs(cdxady) + Math.abs(adxcdy)) * Math.abs(bdz)
3688 + (Math.abs(adxbdy) + Math.abs(bdxady)) * Math.abs(cdz);
3689 var tol = ERRBOUND4 * permanent;
3690 if ((det > tol) || (-det > tol)) {
3691 return det
3692 }
3693 return orientation4Exact(a,b,c,d)
3694 }
3695];
3696
3697function slowOrient(args) {
3698 var proc = CACHED[args.length];
3699 if(!proc) {
3700 proc = CACHED[args.length] = orientation(args.length);
3701 }
3702 return proc.apply(undefined, args)
3703}
3704
3705function generateOrientationProc() {
3706 while(CACHED.length <= NUM_EXPAND) {
3707 CACHED.push(orientation(CACHED.length));
3708 }
3709 var args = [];
3710 var procArgs = ["slow"];
3711 for(var i=0; i<=NUM_EXPAND; ++i) {
3712 args.push("a" + i);
3713 procArgs.push("o" + i);
3714 }
3715 var code = [
3716 "function getOrientation(", args.join(), "){switch(arguments.length){case 0:case 1:return 0;"
3717 ];
3718 for(var i=2; i<=NUM_EXPAND; ++i) {
3719 code.push("case ", i, ":return o", i, "(", args.slice(0, i).join(), ");");
3720 }
3721 code.push("}var s=new Array(arguments.length);for(var i=0;i<arguments.length;++i){s[i]=arguments[i]};return slow(s);}return getOrientation");
3722 procArgs.push(code.join(""));
3723
3724 var proc = Function.apply(undefined, procArgs);
3725 module.exports = proc.apply(undefined, [slowOrient].concat(CACHED));
3726 for(var i=0; i<=NUM_EXPAND; ++i) {
3727 module.exports[i] = CACHED[i];
3728 }
3729}
3730
3731generateOrientationProc();
3732});
3733
3734var monotoneConvexHull2d = monotoneConvexHull2D;
3735
3736var orient$1 = orientation_1[3];
3737
3738function monotoneConvexHull2D(points) {
3739 var n = points.length;
3740
3741 if(n < 3) {
3742 var result = new Array(n);
3743 for(var i=0; i<n; ++i) {
3744 result[i] = i;
3745 }
3746
3747 if(n === 2 &&
3748 points[0][0] === points[1][0] &&
3749 points[0][1] === points[1][1]) {
3750 return [0]
3751 }
3752
3753 return result
3754 }
3755
3756 //Sort point indices along x-axis
3757 var sorted = new Array(n);
3758 for(var i=0; i<n; ++i) {
3759 sorted[i] = i;
3760 }
3761 sorted.sort(function(a,b) {
3762 var d = points[a][0]-points[b][0];
3763 if(d) {
3764 return d
3765 }
3766 return points[a][1] - points[b][1]
3767 });
3768
3769 //Construct upper and lower hulls
3770 var lower = [sorted[0], sorted[1]];
3771 var upper = [sorted[0], sorted[1]];
3772
3773 for(var i=2; i<n; ++i) {
3774 var idx = sorted[i];
3775 var p = points[idx];
3776
3777 //Insert into lower list
3778 var m = lower.length;
3779 while(m > 1 && orient$1(
3780 points[lower[m-2]],
3781 points[lower[m-1]],
3782 p) <= 0) {
3783 m -= 1;
3784 lower.pop();
3785 }
3786 lower.push(idx);
3787
3788 //Insert into upper list
3789 m = upper.length;
3790 while(m > 1 && orient$1(
3791 points[upper[m-2]],
3792 points[upper[m-1]],
3793 p) >= 0) {
3794 m -= 1;
3795 upper.pop();
3796 }
3797 upper.push(idx);
3798 }
3799
3800 //Merge lists together
3801 var result = new Array(upper.length + lower.length - 2);
3802 var ptr = 0;
3803 for(var i=0, nl=lower.length; i<nl; ++i) {
3804 result[ptr++] = lower[i];
3805 }
3806 for(var j=upper.length-2; j>0; --j) {
3807 result[ptr++] = upper[j];
3808 }
3809
3810 //Return result
3811 return result
3812}
3813
3814var tinyqueue = TinyQueue;
3815var default_1$1 = TinyQueue;
3816
3817function TinyQueue(data, compare) {
3818 if (!(this instanceof TinyQueue)) return new TinyQueue(data, compare);
3819
3820 this.data = data || [];
3821 this.length = this.data.length;
3822 this.compare = compare || defaultCompare$1;
3823
3824 if (this.length > 0) {
3825 for (var i = (this.length >> 1) - 1; i >= 0; i--) this._down(i);
3826 }
3827}
3828
3829function defaultCompare$1(a, b) {
3830 return a < b ? -1 : a > b ? 1 : 0;
3831}
3832
3833TinyQueue.prototype = {
3834
3835 push: function (item) {
3836 this.data.push(item);
3837 this.length++;
3838 this._up(this.length - 1);
3839 },
3840
3841 pop: function () {
3842 if (this.length === 0) return undefined;
3843
3844 var top = this.data[0];
3845 this.length--;
3846
3847 if (this.length > 0) {
3848 this.data[0] = this.data[this.length];
3849 this._down(0);
3850 }
3851 this.data.pop();
3852
3853 return top;
3854 },
3855
3856 peek: function () {
3857 return this.data[0];
3858 },
3859
3860 _up: function (pos) {
3861 var data = this.data;
3862 var compare = this.compare;
3863 var item = data[pos];
3864
3865 while (pos > 0) {
3866 var parent = (pos - 1) >> 1;
3867 var current = data[parent];
3868 if (compare(item, current) >= 0) break;
3869 data[pos] = current;
3870 pos = parent;
3871 }
3872
3873 data[pos] = item;
3874 },
3875
3876 _down: function (pos) {
3877 var data = this.data;
3878 var compare = this.compare;
3879 var halfLength = this.length >> 1;
3880 var item = data[pos];
3881
3882 while (pos < halfLength) {
3883 var left = (pos << 1) + 1;
3884 var right = left + 1;
3885 var best = data[left];
3886
3887 if (right < this.length && compare(data[right], best) < 0) {
3888 left = right;
3889 best = data[right];
3890 }
3891 if (compare(best, item) >= 0) break;
3892
3893 data[pos] = best;
3894 pos = left;
3895 }
3896
3897 data[pos] = item;
3898 }
3899};
3900
3901tinyqueue.default = default_1$1;
3902
3903var pointInPolygon = function (point, vs) {
3904 // ray-casting algorithm based on
3905 // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
3906
3907 var x = point[0], y = point[1];
3908
3909 var inside = false;
3910 for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
3911 var xi = vs[i][0], yi = vs[i][1];
3912 var xj = vs[j][0], yj = vs[j][1];
3913
3914 var intersect = ((yi > y) != (yj > y))
3915 && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
3916 if (intersect) inside = !inside;
3917 }
3918
3919 return inside;
3920};
3921
3922var orient = orientation_1[3];
3923
3924var concaveman_1 = concaveman;
3925var default_1 = concaveman;
3926
3927function concaveman(points, concavity, lengthThreshold) {
3928 // a relative measure of concavity; higher value means simpler hull
3929 concavity = Math.max(0, concavity === undefined ? 2 : concavity);
3930
3931 // when a segment goes below this length threshold, it won't be drilled down further
3932 lengthThreshold = lengthThreshold || 0;
3933
3934 // start with a convex hull of the points
3935 var hull = fastConvexHull(points);
3936
3937 // index the points with an R-tree
3938 var tree = rbush_1(16, ['[0]', '[1]', '[0]', '[1]']).load(points);
3939
3940 // turn the convex hull into a linked list and populate the initial edge queue with the nodes
3941 var queue = [];
3942 for (var i = 0, last; i < hull.length; i++) {
3943 var p = hull[i];
3944 tree.remove(p);
3945 last = insertNode(p, last);
3946 queue.push(last);
3947 }
3948
3949 // index the segments with an R-tree (for intersection checks)
3950 var segTree = rbush_1(16);
3951 for (i = 0; i < queue.length; i++) segTree.insert(updateBBox(queue[i]));
3952
3953 var sqConcavity = concavity * concavity;
3954 var sqLenThreshold = lengthThreshold * lengthThreshold;
3955
3956 // process edges one by one
3957 while (queue.length) {
3958 var node = queue.shift();
3959 var a = node.p;
3960 var b = node.next.p;
3961
3962 // skip the edge if it's already short enough
3963 var sqLen = getSqDist(a, b);
3964 if (sqLen < sqLenThreshold) continue;
3965
3966 var maxSqLen = sqLen / sqConcavity;
3967
3968 // find the best connection point for the current edge to flex inward to
3969 p = findCandidate(tree, node.prev.p, a, b, node.next.next.p, maxSqLen, segTree);
3970
3971 // if we found a connection and it satisfies our concavity measure
3972 if (p && Math.min(getSqDist(p, a), getSqDist(p, b)) <= maxSqLen) {
3973 // connect the edge endpoints through this point and add 2 new edges to the queue
3974 queue.push(node);
3975 queue.push(insertNode(p, node));
3976
3977 // update point and segment indexes
3978 tree.remove(p);
3979 segTree.remove(node);
3980 segTree.insert(updateBBox(node));
3981 segTree.insert(updateBBox(node.next));
3982 }
3983 }
3984
3985 // convert the resulting hull linked list to an array of points
3986 node = last;
3987 var concave = [];
3988 do {
3989 concave.push(node.p);
3990 node = node.next;
3991 } while (node !== last);
3992
3993 concave.push(node.p);
3994
3995 return concave;
3996}
3997
3998function findCandidate(tree, a, b, c, d, maxDist, segTree) {
3999 var queue = new tinyqueue(null, compareDist);
4000 var node = tree.data;
4001
4002 // search through the point R-tree with a depth-first search using a priority queue
4003 // in the order of distance to the edge (b, c)
4004 while (node) {
4005 for (var i = 0; i < node.children.length; i++) {
4006 var child = node.children[i];
4007
4008 var dist = node.leaf ? sqSegDist(child, b, c) : sqSegBoxDist(b, c, child);
4009 if (dist > maxDist) continue; // skip the node if it's farther than we ever need
4010
4011 queue.push({
4012 node: child,
4013 dist: dist
4014 });
4015 }
4016
4017 while (queue.length && !queue.peek().node.children) {
4018 var item = queue.pop();
4019 var p = item.node;
4020
4021 // skip all points that are as close to adjacent edges (a,b) and (c,d),
4022 // and points that would introduce self-intersections when connected
4023 var d0 = sqSegDist(p, a, b);
4024 var d1 = sqSegDist(p, c, d);
4025 if (item.dist < d0 && item.dist < d1 &&
4026 noIntersections(b, p, segTree) &&
4027 noIntersections(c, p, segTree)) return p;
4028 }
4029
4030 node = queue.pop();
4031 if (node) node = node.node;
4032 }
4033
4034 return null;
4035}
4036
4037function compareDist(a, b) {
4038 return a.dist - b.dist;
4039}
4040
4041// square distance from a segment bounding box to the given one
4042function sqSegBoxDist(a, b, bbox) {
4043 if (inside(a, bbox) || inside(b, bbox)) return 0;
4044 var d1 = sqSegSegDist(a[0], a[1], b[0], b[1], bbox.minX, bbox.minY, bbox.maxX, bbox.minY);
4045 if (d1 === 0) return 0;
4046 var d2 = sqSegSegDist(a[0], a[1], b[0], b[1], bbox.minX, bbox.minY, bbox.minX, bbox.maxY);
4047 if (d2 === 0) return 0;
4048 var d3 = sqSegSegDist(a[0], a[1], b[0], b[1], bbox.maxX, bbox.minY, bbox.maxX, bbox.maxY);
4049 if (d3 === 0) return 0;
4050 var d4 = sqSegSegDist(a[0], a[1], b[0], b[1], bbox.minX, bbox.maxY, bbox.maxX, bbox.maxY);
4051 if (d4 === 0) return 0;
4052 return Math.min(d1, d2, d3, d4);
4053}
4054
4055function inside(a, bbox) {
4056 return a[0] >= bbox.minX &&
4057 a[0] <= bbox.maxX &&
4058 a[1] >= bbox.minY &&
4059 a[1] <= bbox.maxY;
4060}
4061
4062// check if the edge (a,b) doesn't intersect any other edges
4063function noIntersections(a, b, segTree) {
4064 var minX = Math.min(a[0], b[0]);
4065 var minY = Math.min(a[1], b[1]);
4066 var maxX = Math.max(a[0], b[0]);
4067 var maxY = Math.max(a[1], b[1]);
4068
4069 var edges = segTree.search({minX: minX, minY: minY, maxX: maxX, maxY: maxY});
4070 for (var i = 0; i < edges.length; i++) {
4071 if (intersects(edges[i].p, edges[i].next.p, a, b)) return false;
4072 }
4073 return true;
4074}
4075
4076// check if the edges (p1,q1) and (p2,q2) intersect
4077function intersects(p1, q1, p2, q2) {
4078 return p1 !== q2 && q1 !== p2 &&
4079 orient(p1, q1, p2) > 0 !== orient(p1, q1, q2) > 0 &&
4080 orient(p2, q2, p1) > 0 !== orient(p2, q2, q1) > 0;
4081}
4082
4083// update the bounding box of a node's edge
4084function updateBBox(node) {
4085 var p1 = node.p;
4086 var p2 = node.next.p;
4087 node.minX = Math.min(p1[0], p2[0]);
4088 node.minY = Math.min(p1[1], p2[1]);
4089 node.maxX = Math.max(p1[0], p2[0]);
4090 node.maxY = Math.max(p1[1], p2[1]);
4091 return node;
4092}
4093
4094// speed up convex hull by filtering out points inside quadrilateral formed by 4 extreme points
4095function fastConvexHull(points) {
4096 var left = points[0];
4097 var top = points[0];
4098 var right = points[0];
4099 var bottom = points[0];
4100
4101 // find the leftmost, rightmost, topmost and bottommost points
4102 for (var i = 0; i < points.length; i++) {
4103 var p = points[i];
4104 if (p[0] < left[0]) left = p;
4105 if (p[0] > right[0]) right = p;
4106 if (p[1] < top[1]) top = p;
4107 if (p[1] > bottom[1]) bottom = p;
4108 }
4109
4110 // filter out points that are inside the resulting quadrilateral
4111 var cull = [left, top, right, bottom];
4112 var filtered = cull.slice();
4113 for (i = 0; i < points.length; i++) {
4114 if (!pointInPolygon(points[i], cull)) filtered.push(points[i]);
4115 }
4116
4117 // get convex hull around the filtered points
4118 var indices = monotoneConvexHull2d(filtered);
4119
4120 // return the hull as array of points (rather than indices)
4121 var hull = [];
4122 for (i = 0; i < indices.length; i++) hull.push(filtered[indices[i]]);
4123 return hull;
4124}
4125
4126// create a new node in a doubly linked list
4127function insertNode(p, prev) {
4128 var node = {
4129 p: p,
4130 prev: null,
4131 next: null,
4132 minX: 0,
4133 minY: 0,
4134 maxX: 0,
4135 maxY: 0
4136 };
4137
4138 if (!prev) {
4139 node.prev = node;
4140 node.next = node;
4141
4142 } else {
4143 node.next = prev.next;
4144 node.prev = prev;
4145 prev.next.prev = node;
4146 prev.next = node;
4147 }
4148 return node;
4149}
4150
4151// square distance between 2 points
4152function getSqDist(p1, p2) {
4153
4154 var dx = p1[0] - p2[0],
4155 dy = p1[1] - p2[1];
4156
4157 return dx * dx + dy * dy;
4158}
4159
4160// square distance from a point to a segment
4161function sqSegDist(p, p1, p2) {
4162
4163 var x = p1[0],
4164 y = p1[1],
4165 dx = p2[0] - x,
4166 dy = p2[1] - y;
4167
4168 if (dx !== 0 || dy !== 0) {
4169
4170 var t = ((p[0] - x) * dx + (p[1] - y) * dy) / (dx * dx + dy * dy);
4171
4172 if (t > 1) {
4173 x = p2[0];
4174 y = p2[1];
4175
4176 } else if (t > 0) {
4177 x += dx * t;
4178 y += dy * t;
4179 }
4180 }
4181
4182 dx = p[0] - x;
4183 dy = p[1] - y;
4184
4185 return dx * dx + dy * dy;
4186}
4187
4188// segment to segment distance, ported from http://geomalgorithms.com/a07-_distance.html by Dan Sunday
4189function sqSegSegDist(x0, y0, x1, y1, x2, y2, x3, y3) {
4190 var ux = x1 - x0;
4191 var uy = y1 - y0;
4192 var vx = x3 - x2;
4193 var vy = y3 - y2;
4194 var wx = x0 - x2;
4195 var wy = y0 - y2;
4196 var a = ux * ux + uy * uy;
4197 var b = ux * vx + uy * vy;
4198 var c = vx * vx + vy * vy;
4199 var d = ux * wx + uy * wy;
4200 var e = vx * wx + vy * wy;
4201 var D = a * c - b * b;
4202
4203 var sc, sN, tc, tN;
4204 var sD = D;
4205 var tD = D;
4206
4207 if (D === 0) {
4208 sN = 0;
4209 sD = 1;
4210 tN = e;
4211 tD = c;
4212 } else {
4213 sN = b * e - c * d;
4214 tN = a * e - b * d;
4215 if (sN < 0) {
4216 sN = 0;
4217 tN = e;
4218 tD = c;
4219 } else if (sN > sD) {
4220 sN = sD;
4221 tN = e + b;
4222 tD = c;
4223 }
4224 }
4225
4226 if (tN < 0.0) {
4227 tN = 0.0;
4228 if (-d < 0.0) sN = 0.0;
4229 else if (-d > a) sN = sD;
4230 else {
4231 sN = -d;
4232 sD = a;
4233 }
4234 } else if (tN > tD) {
4235 tN = tD;
4236 if ((-d + b) < 0.0) sN = 0;
4237 else if (-d + b > a) sN = sD;
4238 else {
4239 sN = -d + b;
4240 sD = a;
4241 }
4242 }
4243
4244 sc = sN === 0 ? 0 : sN / sD;
4245 tc = tN === 0 ? 0 : tN / tD;
4246
4247 var cx = (1 - sc) * x0 + sc * x1;
4248 var cy = (1 - sc) * y0 + sc * y1;
4249 var cx2 = (1 - tc) * x2 + tc * x3;
4250 var cy2 = (1 - tc) * y2 + tc * y3;
4251 var dx = cx2 - cx;
4252 var dy = cy2 - cy;
4253
4254 return dx * dx + dy * dy;
4255}
4256
4257concaveman_1.default = default_1;
4258
4259/**
4260 * Takes a {@link Feature} or a {@link FeatureCollection} and returns a convex hull {@link Polygon}.
4261 *
4262 * Internally this uses
4263 * the [convex-hull](https://github.com/mikolalysenko/convex-hull) module that
4264 * implements a [monotone chain hull](http://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain).
4265 *
4266 * @name convex
4267 * @param {GeoJSON} geojson input Feature or FeatureCollection
4268 * @param {Object} [options={}] Optional parameters
4269 * @param {number} [options.concavity=Infinity] 1 - thin shape. Infinity - convex hull.
4270 * @returns {Feature<Polygon>} a convex hull
4271 * @example
4272 * var points = turf.featureCollection([
4273 * turf.point([10.195312, 43.755225]),
4274 * turf.point([10.404052, 43.8424511]),
4275 * turf.point([10.579833, 43.659924]),
4276 * turf.point([10.360107, 43.516688]),
4277 * turf.point([10.14038, 43.588348]),
4278 * turf.point([10.195312, 43.755225])
4279 * ]);
4280 *
4281 * var hull = turf.convex(points);
4282 *
4283 * //addToMap
4284 * var addToMap = [points, hull]
4285 */
4286function convex(geojson, options) {
4287 // Optional parameters
4288 options = options || {};
4289 if (!isObject(options)) throw new Error('options is invalid');
4290 var concavity = options.concavity || Infinity;
4291 var points$$1 = [];
4292
4293 // Convert all points to flat 2D coordinate Array
4294 coordEach(geojson, function (coord) {
4295 points$$1.push([coord[0], coord[1]]);
4296 });
4297 if (!points$$1.length) return null;
4298
4299 var convexHull = concaveman_1(points$$1, concavity);
4300
4301 // Convex hull should have at least 3 different vertices in order to create a valid polygon
4302 if (convexHull.length > 3) {
4303 return polygon([convexHull]);
4304 }
4305 return null;
4306}
4307
4308// http://en.wikipedia.org/wiki/Even%E2%80%93odd_rule
4309// modified from: https://github.com/substack/point-in-polygon/blob/master/index.js
4310// which was modified from http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
4311
4312/**
4313 * Takes a {@link Point} and a {@link Polygon} or {@link MultiPolygon} and determines if the point resides inside the polygon. The polygon can
4314 * be convex or concave. The function accounts for holes.
4315 *
4316 * @name booleanPointInPolygon
4317 * @param {Coord} point input point
4318 * @param {Feature<Polygon|MultiPolygon>} polygon input polygon or multipolygon
4319 * @param {Object} [options={}] Optional parameters
4320 * @param {boolean} [options.ignoreBoundary=false] True if polygon boundary should be ignored when determining if the point is inside the polygon otherwise false.
4321 * @returns {boolean} `true` if the Point is inside the Polygon; `false` if the Point is not inside the Polygon
4322 * @example
4323 * var pt = turf.point([-77, 44]);
4324 * var poly = turf.polygon([[
4325 * [-81, 41],
4326 * [-81, 47],
4327 * [-72, 47],
4328 * [-72, 41],
4329 * [-81, 41]
4330 * ]]);
4331 *
4332 * turf.booleanPointInPolygon(pt, poly);
4333 * //= true
4334 */
4335function booleanPointInPolygon(point, polygon, options) {
4336 // Optional parameters
4337 options = options || {};
4338 if (typeof options !== 'object') throw new Error('options is invalid');
4339 var ignoreBoundary = options.ignoreBoundary;
4340
4341 // validation
4342 if (!point) throw new Error('point is required');
4343 if (!polygon) throw new Error('polygon is required');
4344
4345 var pt = getCoord(point);
4346 var polys = getCoords(polygon);
4347 var type = (polygon.geometry) ? polygon.geometry.type : polygon.type;
4348 var bbox = polygon.bbox;
4349
4350 // Quick elimination if point is not inside bbox
4351 if (bbox && inBBox(pt, bbox) === false) return false;
4352
4353 // normalize to multipolygon
4354 if (type === 'Polygon') polys = [polys];
4355
4356 for (var i = 0, insidePoly = false; i < polys.length && !insidePoly; i++) {
4357 // check if it is in the outer ring first
4358 if (inRing(pt, polys[i][0], ignoreBoundary)) {
4359 var inHole = false;
4360 var k = 1;
4361 // check for the point in any of the holes
4362 while (k < polys[i].length && !inHole) {
4363 if (inRing(pt, polys[i][k], !ignoreBoundary)) {
4364 inHole = true;
4365 }
4366 k++;
4367 }
4368 if (!inHole) insidePoly = true;
4369 }
4370 }
4371 return insidePoly;
4372}
4373
4374/**
4375 * inRing
4376 *
4377 * @private
4378 * @param {Array<number>} pt [x,y]
4379 * @param {Array<Array<number>>} ring [[x,y], [x,y],..]
4380 * @param {boolean} ignoreBoundary ignoreBoundary
4381 * @returns {boolean} inRing
4382 */
4383function inRing(pt, ring, ignoreBoundary) {
4384 var isInside = false;
4385 if (ring[0][0] === ring[ring.length - 1][0] && ring[0][1] === ring[ring.length - 1][1]) ring = ring.slice(0, ring.length - 1);
4386
4387 for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) {
4388 var xi = ring[i][0], yi = ring[i][1];
4389 var xj = ring[j][0], yj = ring[j][1];
4390 var onBoundary = (pt[1] * (xi - xj) + yi * (xj - pt[0]) + yj * (pt[0] - xi) === 0) &&
4391 ((xi - pt[0]) * (xj - pt[0]) <= 0) && ((yi - pt[1]) * (yj - pt[1]) <= 0);
4392 if (onBoundary) return !ignoreBoundary;
4393 var intersect = ((yi > pt[1]) !== (yj > pt[1])) &&
4394 (pt[0] < (xj - xi) * (pt[1] - yi) / (yj - yi) + xi);
4395 if (intersect) isInside = !isInside;
4396 }
4397 return isInside;
4398}
4399
4400/**
4401 * inBBox
4402 *
4403 * @private
4404 * @param {Position} pt point [x,y]
4405 * @param {BBox} bbox BBox [west, south, east, north]
4406 * @returns {boolean} true/false if point is inside BBox
4407 */
4408function inBBox(pt, bbox) {
4409 return bbox[0] <= pt[0] &&
4410 bbox[1] <= pt[1] &&
4411 bbox[2] >= pt[0] &&
4412 bbox[3] >= pt[1];
4413}
4414
4415/**
4416 * Finds {@link Points} that fall within {@link (Multi)Polygon(s)}.
4417 *
4418 * @name pointsWithinPolygon
4419 * @param {Feauture|FeatureCollection<Point>} points Points as input search
4420 * @param {FeatureCollection|Geoemtry|Feature<Polygon|MultiPolygon>} polygons Points must be within these (Multi)Polygon(s)
4421 * @returns {FeatureCollection<Point>} points that land within at least one polygon
4422 * @example
4423 * var points = turf.points([
4424 * [-46.6318, -23.5523],
4425 * [-46.6246, -23.5325],
4426 * [-46.6062, -23.5513],
4427 * [-46.663, -23.554],
4428 * [-46.643, -23.557]
4429 * ]);
4430 *
4431 * var searchWithin = turf.polygon([[
4432 * [-46.653,-23.543],
4433 * [-46.634,-23.5346],
4434 * [-46.613,-23.543],
4435 * [-46.614,-23.559],
4436 * [-46.631,-23.567],
4437 * [-46.653,-23.560],
4438 * [-46.653,-23.543]
4439 * ]]);
4440 *
4441 * var ptsWithin = turf.pointsWithinPolygon(points, searchWithin);
4442 *
4443 * //addToMap
4444 * var addToMap = [points, searchWithin, ptsWithin]
4445 * turf.featureEach(ptsWithin, function (currentFeature) {
4446 * currentFeature.properties['marker-size'] = 'large';
4447 * currentFeature.properties['marker-color'] = '#000';
4448 * });
4449 */
4450function pointsWithinPolygon(points$$1, polygons$$1) {
4451 var results = [];
4452 geomEach(polygons$$1, function (polygon$$1) {
4453 featureEach(points$$1, function (point$$1) {
4454 if (booleanPointInPolygon(point$$1, polygon$$1)) results.push(point$$1);
4455 });
4456 });
4457 return featureCollection(results);
4458}
4459
4460//http://en.wikipedia.org/wiki/Delaunay_triangulation
4461//https://github.com/ironwallaby/delaunay
4462/**
4463 * Takes a set of {@link Point|points} and creates a
4464 * [Triangulated Irregular Network](http://en.wikipedia.org/wiki/Triangulated_irregular_network),
4465 * or a TIN for short, returned as a collection of Polygons. These are often used
4466 * for developing elevation contour maps or stepped heat visualizations.
4467 *
4468 * If an optional z-value property is provided then it is added as properties called `a`, `b`,
4469 * and `c` representing its value at each of the points that represent the corners of the
4470 * triangle.
4471 *
4472 * @name tin
4473 * @param {FeatureCollection<Point>} points input points
4474 * @param {String} [z] name of the property from which to pull z values
4475 * This is optional: if not given, then there will be no extra data added to the derived triangles.
4476 * @returns {FeatureCollection<Polygon>} TIN output
4477 * @example
4478 * // generate some random point data
4479 * var points = turf.randomPoint(30, {bbox: [50, 30, 70, 50]});
4480 *
4481 * // add a random property to each point between 0 and 9
4482 * for (var i = 0; i < points.features.length; i++) {
4483 * points.features[i].properties.z = ~~(Math.random() * 9);
4484 * }
4485 * var tin = turf.tin(points, 'z');
4486 *
4487 * //addToMap
4488 * var addToMap = [tin, points]
4489 * for (var i = 0; i < tin.features.length; i++) {
4490 * var properties = tin.features[i].properties;
4491 * properties.fill = '#' + properties.a + properties.b + properties.c;
4492 * }
4493 */
4494function tin(points$$1, z) {
4495 if (points$$1.type !== 'FeatureCollection') throw new Error('points must be a FeatureCollection');
4496 //break down points
4497 var isPointZ = false;
4498 return featureCollection(triangulate(points$$1.features.map(function (p) {
4499 var point$$1 = {
4500 x: p.geometry.coordinates[0],
4501 y: p.geometry.coordinates[1]
4502 };
4503 if (z) {
4504 point$$1.z = p.properties[z];
4505 } else if (p.geometry.coordinates.length === 3) {
4506 isPointZ = true;
4507 point$$1.z = p.geometry.coordinates[2];
4508 }
4509 return point$$1;
4510 })).map(function (triangle) {
4511
4512 var a = [triangle.a.x, triangle.a.y];
4513 var b = [triangle.b.x, triangle.b.y];
4514 var c = [triangle.c.x, triangle.c.y];
4515 var properties = {};
4516
4517 // Add z coordinates to triangle points if user passed
4518 // them in that way otherwise add it as a property.
4519 if (isPointZ) {
4520 a.push(triangle.a.z);
4521 b.push(triangle.b.z);
4522 c.push(triangle.c.z);
4523 } else {
4524 properties = {
4525 a: triangle.a.z,
4526 b: triangle.b.z,
4527 c: triangle.c.z
4528 };
4529 }
4530
4531 return polygon([[a, b, c, a]], properties);
4532
4533 }));
4534}
4535
4536function Triangle(a, b, c) {
4537 this.a = a;
4538 this.b = b;
4539 this.c = c;
4540
4541 var A = b.x - a.x,
4542 B = b.y - a.y,
4543 C = c.x - a.x,
4544 D = c.y - a.y,
4545 E = A * (a.x + b.x) + B * (a.y + b.y),
4546 F = C * (a.x + c.x) + D * (a.y + c.y),
4547 G = 2 * (A * (c.y - b.y) - B * (c.x - b.x)),
4548 dx, dy;
4549
4550 // If the points of the triangle are collinear, then just find the
4551 // extremes and use the midpoint as the center of the circumcircle.
4552 this.x = (D * E - B * F) / G;
4553 this.y = (A * F - C * E) / G;
4554 dx = this.x - a.x;
4555 dy = this.y - a.y;
4556 this.r = dx * dx + dy * dy;
4557}
4558
4559function byX(a, b) {
4560 return b.x - a.x;
4561}
4562
4563function dedup(edges) {
4564 var j = edges.length,
4565 a, b, i, m, n;
4566
4567 outer:
4568 while (j) {
4569 b = edges[--j];
4570 a = edges[--j];
4571 i = j;
4572 while (i) {
4573 n = edges[--i];
4574 m = edges[--i];
4575 if ((a === m && b === n) || (a === n && b === m)) {
4576 edges.splice(j, 2);
4577 edges.splice(i, 2);
4578 j -= 2;
4579 continue outer;
4580 }
4581 }
4582 }
4583}
4584
4585function triangulate(vertices) {
4586 // Bail if there aren't enough vertices to form any triangles.
4587 if (vertices.length < 3)
4588 return [];
4589
4590 // Ensure the vertex array is in order of descending X coordinate
4591 // (which is needed to ensure a subquadratic runtime), and then find
4592 // the bounding box around the points.
4593 vertices.sort(byX);
4594
4595 var i = vertices.length - 1,
4596 xmin = vertices[i].x,
4597 xmax = vertices[0].x,
4598 ymin = vertices[i].y,
4599 ymax = ymin,
4600 epsilon = 1e-12;
4601
4602 var a,
4603 b,
4604 c,
4605 A,
4606 B,
4607 G;
4608
4609 while (i--) {
4610 if (vertices[i].y < ymin)
4611 ymin = vertices[i].y;
4612 if (vertices[i].y > ymax)
4613 ymax = vertices[i].y;
4614 }
4615
4616 //Find a supertriangle, which is a triangle that surrounds all the
4617 //vertices. This is used like something of a sentinel value to remove
4618 //cases in the main algorithm, and is removed before we return any
4619 // results.
4620
4621 // Once found, put it in the "open" list. (The "open" list is for
4622 // triangles who may still need to be considered; the "closed" list is
4623 // for triangles which do not.)
4624 var dx = xmax - xmin,
4625 dy = ymax - ymin,
4626 dmax = (dx > dy) ? dx : dy,
4627 xmid = (xmax + xmin) * 0.5,
4628 ymid = (ymax + ymin) * 0.5,
4629 open = [
4630 new Triangle({
4631 x: xmid - 20 * dmax,
4632 y: ymid - dmax,
4633 __sentinel: true
4634 }, {
4635 x: xmid,
4636 y: ymid + 20 * dmax,
4637 __sentinel: true
4638 }, {
4639 x: xmid + 20 * dmax,
4640 y: ymid - dmax,
4641 __sentinel: true
4642 }
4643 )],
4644 closed = [],
4645 edges = [],
4646 j;
4647
4648 // Incrementally add each vertex to the mesh.
4649 i = vertices.length;
4650 while (i--) {
4651 // For each open triangle, check to see if the current point is
4652 // inside it's circumcircle. If it is, remove the triangle and add
4653 // it's edges to an edge list.
4654 edges.length = 0;
4655 j = open.length;
4656 while (j--) {
4657 // If this point is to the right of this triangle's circumcircle,
4658 // then this triangle should never get checked again. Remove it
4659 // from the open list, add it to the closed list, and skip.
4660 dx = vertices[i].x - open[j].x;
4661 if (dx > 0 && dx * dx > open[j].r) {
4662 closed.push(open[j]);
4663 open.splice(j, 1);
4664 continue;
4665 }
4666
4667 // If not, skip this triangle.
4668 dy = vertices[i].y - open[j].y;
4669 if (dx * dx + dy * dy > open[j].r)
4670 continue;
4671
4672 // Remove the triangle and add it's edges to the edge list.
4673 edges.push(
4674 open[j].a, open[j].b,
4675 open[j].b, open[j].c,
4676 open[j].c, open[j].a
4677 );
4678 open.splice(j, 1);
4679 }
4680
4681 // Remove any doubled edges.
4682 dedup(edges);
4683
4684 // Add a new triangle for each edge.
4685 j = edges.length;
4686 while (j) {
4687 b = edges[--j];
4688 a = edges[--j];
4689 c = vertices[i];
4690 // Avoid adding colinear triangles (which have error-prone
4691 // circumcircles)
4692 A = b.x - a.x;
4693 B = b.y - a.y;
4694 G = 2 * (A * (c.y - b.y) - B * (c.x - b.x));
4695 if (Math.abs(G) > epsilon) {
4696 open.push(new Triangle(a, b, c));
4697 }
4698 }
4699 }
4700
4701 // Copy any remaining open triangles to the closed list, and then
4702 // remove any triangles that share a vertex with the supertriangle.
4703 Array.prototype.push.apply(closed, open);
4704
4705 i = closed.length;
4706 while (i--)
4707 if (closed[i].a.__sentinel ||
4708 closed[i].b.__sentinel ||
4709 closed[i].c.__sentinel)
4710 closed.splice(i, 1);
4711
4712 return closed;
4713}
4714
4715//http://en.wikipedia.org/wiki/Haversine_formula
4716//http://www.movable-type.co.uk/scripts/latlong.html
4717
4718/**
4719 * Calculates the distance between two {@link Point|points} in degrees, radians,
4720 * miles, or kilometers. This uses the
4721 * [Haversine formula](http://en.wikipedia.org/wiki/Haversine_formula)
4722 * to account for global curvature.
4723 *
4724 * @name distance
4725 * @param {Coord} from origin point
4726 * @param {Coord} to destination point
4727 * @param {Object} [options={}] Optional parameters
4728 * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers
4729 * @returns {number} distance between the two points
4730 * @example
4731 * var from = turf.point([-75.343, 39.984]);
4732 * var to = turf.point([-75.534, 39.123]);
4733 * var options = {units: 'miles'};
4734 *
4735 * var distance = turf.distance(from, to, options);
4736 *
4737 * //addToMap
4738 * var addToMap = [from, to];
4739 * from.properties.distance = distance;
4740 * to.properties.distance = distance;
4741 */
4742function distance(from, to, options) {
4743 // Optional parameters
4744 options = options || {};
4745 if (!isObject(options)) throw new Error('options is invalid');
4746 var units = options.units;
4747
4748 var coordinates1 = getCoord(from);
4749 var coordinates2 = getCoord(to);
4750 var dLat = degreesToRadians((coordinates2[1] - coordinates1[1]));
4751 var dLon = degreesToRadians((coordinates2[0] - coordinates1[0]));
4752 var lat1 = degreesToRadians(coordinates1[1]);
4753 var lat2 = degreesToRadians(coordinates2[1]);
4754
4755 var a = Math.pow(Math.sin(dLat / 2), 2) +
4756 Math.pow(Math.sin(dLon / 2), 2) * Math.cos(lat1) * Math.cos(lat2);
4757
4758 return radiansToLength(2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)), units);
4759}
4760
4761/**
4762 * Returns a cloned copy of the passed GeoJSON Object, including possible 'Foreign Members'.
4763 * ~3-5x faster than the common JSON.parse + JSON.stringify combo method.
4764 *
4765 * @name clone
4766 * @param {GeoJSON} geojson GeoJSON Object
4767 * @returns {GeoJSON} cloned GeoJSON Object
4768 * @example
4769 * var line = turf.lineString([[-74, 40], [-78, 42], [-82, 35]], {color: 'red'});
4770 *
4771 * var lineCloned = turf.clone(line);
4772 */
4773function clone(geojson) {
4774 if (!geojson) throw new Error('geojson is required');
4775
4776 switch (geojson.type) {
4777 case 'Feature':
4778 return cloneFeature(geojson);
4779 case 'FeatureCollection':
4780 return cloneFeatureCollection(geojson);
4781 case 'Point':
4782 case 'LineString':
4783 case 'Polygon':
4784 case 'MultiPoint':
4785 case 'MultiLineString':
4786 case 'MultiPolygon':
4787 case 'GeometryCollection':
4788 return cloneGeometry(geojson);
4789 default:
4790 throw new Error('unknown GeoJSON type');
4791 }
4792}
4793
4794/**
4795 * Clone Feature
4796 *
4797 * @private
4798 * @param {Feature<any>} geojson GeoJSON Feature
4799 * @returns {Feature<any>} cloned Feature
4800 */
4801function cloneFeature(geojson) {
4802 var cloned = {type: 'Feature'};
4803 // Preserve Foreign Members
4804 Object.keys(geojson).forEach(function (key) {
4805 switch (key) {
4806 case 'type':
4807 case 'properties':
4808 case 'geometry':
4809 return;
4810 default:
4811 cloned[key] = geojson[key];
4812 }
4813 });
4814 // Add properties & geometry last
4815 cloned.properties = cloneProperties(geojson.properties);
4816 cloned.geometry = cloneGeometry(geojson.geometry);
4817 return cloned;
4818}
4819
4820/**
4821 * Clone Properties
4822 *
4823 * @private
4824 * @param {Object} properties GeoJSON Properties
4825 * @returns {Object} cloned Properties
4826 */
4827function cloneProperties(properties) {
4828 var cloned = {};
4829 if (!properties) return cloned;
4830 Object.keys(properties).forEach(function (key) {
4831 var value = properties[key];
4832 if (typeof value === 'object') {
4833 if (value === null) {
4834 // handle null
4835 cloned[key] = null;
4836 } else if (value.length) {
4837 // handle Array
4838 cloned[key] = value.map(function (item) {
4839 return item;
4840 });
4841 } else {
4842 // handle generic Object
4843 cloned[key] = cloneProperties(value);
4844 }
4845 } else cloned[key] = value;
4846 });
4847 return cloned;
4848}
4849
4850/**
4851 * Clone Feature Collection
4852 *
4853 * @private
4854 * @param {FeatureCollection<any>} geojson GeoJSON Feature Collection
4855 * @returns {FeatureCollection<any>} cloned Feature Collection
4856 */
4857function cloneFeatureCollection(geojson) {
4858 var cloned = {type: 'FeatureCollection'};
4859
4860 // Preserve Foreign Members
4861 Object.keys(geojson).forEach(function (key) {
4862 switch (key) {
4863 case 'type':
4864 case 'features':
4865 return;
4866 default:
4867 cloned[key] = geojson[key];
4868 }
4869 });
4870 // Add features
4871 cloned.features = geojson.features.map(function (feature) {
4872 return cloneFeature(feature);
4873 });
4874 return cloned;
4875}
4876
4877/**
4878 * Clone Geometry
4879 *
4880 * @private
4881 * @param {Geometry<any>} geometry GeoJSON Geometry
4882 * @returns {Geometry<any>} cloned Geometry
4883 */
4884function cloneGeometry(geometry) {
4885 var geom = {type: geometry.type};
4886 if (geometry.bbox) geom.bbox = geometry.bbox;
4887
4888 if (geometry.type === 'GeometryCollection') {
4889 geom.geometries = geometry.geometries.map(function (geom) {
4890 return cloneGeometry(geom);
4891 });
4892 return geom;
4893 }
4894 geom.coordinates = deepSlice(geometry.coordinates);
4895 return geom;
4896}
4897
4898/**
4899 * Deep Slice coordinates
4900 *
4901 * @private
4902 * @param {Coordinates} coords Coordinates
4903 * @returns {Coordinates} all coordinates sliced
4904 */
4905function deepSlice(coords) {
4906 if (typeof coords[0] !== 'object') { return coords.slice(); }
4907 return coords.map(function (coord) {
4908 return deepSlice(coord);
4909 });
4910}
4911
4912var identity = function(x) {
4913 return x;
4914};
4915
4916var transform = function(transform) {
4917 if (transform == null) return identity;
4918 var x0,
4919 y0,
4920 kx = transform.scale[0],
4921 ky = transform.scale[1],
4922 dx = transform.translate[0],
4923 dy = transform.translate[1];
4924 return function(input, i) {
4925 if (!i) x0 = y0 = 0;
4926 var j = 2, n = input.length, output = new Array(n);
4927 output[0] = (x0 += input[0]) * kx + dx;
4928 output[1] = (y0 += input[1]) * ky + dy;
4929 while (j < n) output[j] = input[j], ++j;
4930 return output;
4931 };
4932};
4933
4934var reverse = function(array, n) {
4935 var t, j = array.length, i = j - n;
4936 while (i < --j) t = array[i], array[i++] = array[j], array[j] = t;
4937};
4938
4939function object(topology, o) {
4940 var transformPoint = transform(topology.transform),
4941 arcs = topology.arcs;
4942
4943 function arc(i, points) {
4944 if (points.length) points.pop();
4945 for (var a = arcs[i < 0 ? ~i : i], k = 0, n = a.length; k < n; ++k) {
4946 points.push(transformPoint(a[k], k));
4947 }
4948 if (i < 0) reverse(points, n);
4949 }
4950
4951 function point(p) {
4952 return transformPoint(p);
4953 }
4954
4955 function line(arcs) {
4956 var points = [];
4957 for (var i = 0, n = arcs.length; i < n; ++i) arc(arcs[i], points);
4958 if (points.length < 2) points.push(points[0]); // This should never happen per the specification.
4959 return points;
4960 }
4961
4962 function ring(arcs) {
4963 var points = line(arcs);
4964 while (points.length < 4) points.push(points[0]); // This may happen if an arc has only two points.
4965 return points;
4966 }
4967
4968 function polygon(arcs) {
4969 return arcs.map(ring);
4970 }
4971
4972 function geometry(o) {
4973 var type = o.type, coordinates;
4974 switch (type) {
4975 case "GeometryCollection": return {type: type, geometries: o.geometries.map(geometry)};
4976 case "Point": coordinates = point(o.coordinates); break;
4977 case "MultiPoint": coordinates = o.coordinates.map(point); break;
4978 case "LineString": coordinates = line(o.arcs); break;
4979 case "MultiLineString": coordinates = o.arcs.map(line); break;
4980 case "Polygon": coordinates = polygon(o.arcs); break;
4981 case "MultiPolygon": coordinates = o.arcs.map(polygon); break;
4982 default: return null;
4983 }
4984 return {type: type, coordinates: coordinates};
4985 }
4986
4987 return geometry(o);
4988}
4989
4990var stitch = function(topology, arcs) {
4991 var stitchedArcs = {},
4992 fragmentByStart = {},
4993 fragmentByEnd = {},
4994 fragments = [],
4995 emptyIndex = -1;
4996
4997 // Stitch empty arcs first, since they may be subsumed by other arcs.
4998 arcs.forEach(function(i, j) {
4999 var arc = topology.arcs[i < 0 ? ~i : i], t;
5000 if (arc.length < 3 && !arc[1][0] && !arc[1][1]) {
5001 t = arcs[++emptyIndex], arcs[emptyIndex] = i, arcs[j] = t;
5002 }
5003 });
5004
5005 arcs.forEach(function(i) {
5006 var e = ends(i),
5007 start = e[0],
5008 end = e[1],
5009 f, g;
5010
5011 if (f = fragmentByEnd[start]) {
5012 delete fragmentByEnd[f.end];
5013 f.push(i);
5014 f.end = end;
5015 if (g = fragmentByStart[end]) {
5016 delete fragmentByStart[g.start];
5017 var fg = g === f ? f : f.concat(g);
5018 fragmentByStart[fg.start = f.start] = fragmentByEnd[fg.end = g.end] = fg;
5019 } else {
5020 fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
5021 }
5022 } else if (f = fragmentByStart[end]) {
5023 delete fragmentByStart[f.start];
5024 f.unshift(i);
5025 f.start = start;
5026 if (g = fragmentByEnd[start]) {
5027 delete fragmentByEnd[g.end];
5028 var gf = g === f ? f : g.concat(f);
5029 fragmentByStart[gf.start = g.start] = fragmentByEnd[gf.end = f.end] = gf;
5030 } else {
5031 fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
5032 }
5033 } else {
5034 f = [i];
5035 fragmentByStart[f.start = start] = fragmentByEnd[f.end = end] = f;
5036 }
5037 });
5038
5039 function ends(i) {
5040 var arc = topology.arcs[i < 0 ? ~i : i], p0 = arc[0], p1;
5041 if (topology.transform) p1 = [0, 0], arc.forEach(function(dp) { p1[0] += dp[0], p1[1] += dp[1]; });
5042 else p1 = arc[arc.length - 1];
5043 return i < 0 ? [p1, p0] : [p0, p1];
5044 }
5045
5046 function flush(fragmentByEnd, fragmentByStart) {
5047 for (var k in fragmentByEnd) {
5048 var f = fragmentByEnd[k];
5049 delete fragmentByStart[f.start];
5050 delete f.start;
5051 delete f.end;
5052 f.forEach(function(i) { stitchedArcs[i < 0 ? ~i : i] = 1; });
5053 fragments.push(f);
5054 }
5055 }
5056
5057 flush(fragmentByEnd, fragmentByStart);
5058 flush(fragmentByStart, fragmentByEnd);
5059 arcs.forEach(function(i) { if (!stitchedArcs[i < 0 ? ~i : i]) fragments.push([i]); });
5060
5061 return fragments;
5062};
5063
5064function planarRingArea(ring) {
5065 var i = -1, n = ring.length, a, b = ring[n - 1], area = 0;
5066 while (++i < n) a = b, b = ring[i], area += a[0] * b[1] - a[1] * b[0];
5067 return Math.abs(area); // Note: doubled area!
5068}
5069
5070var merge = function(topology) {
5071 return object(topology, mergeArcs.apply(this, arguments));
5072};
5073
5074function mergeArcs(topology, objects) {
5075 var polygonsByArc = {},
5076 polygons = [],
5077 groups = [];
5078
5079 objects.forEach(geometry);
5080
5081 function geometry(o) {
5082 switch (o.type) {
5083 case "GeometryCollection": o.geometries.forEach(geometry); break;
5084 case "Polygon": extract(o.arcs); break;
5085 case "MultiPolygon": o.arcs.forEach(extract); break;
5086 }
5087 }
5088
5089 function extract(polygon) {
5090 polygon.forEach(function(ring) {
5091 ring.forEach(function(arc) {
5092 (polygonsByArc[arc = arc < 0 ? ~arc : arc] || (polygonsByArc[arc] = [])).push(polygon);
5093 });
5094 });
5095 polygons.push(polygon);
5096 }
5097
5098 function area(ring) {
5099 return planarRingArea(object(topology, {type: "Polygon", arcs: [ring]}).coordinates[0]);
5100 }
5101
5102 polygons.forEach(function(polygon) {
5103 if (!polygon._) {
5104 var group = [],
5105 neighbors = [polygon];
5106 polygon._ = 1;
5107 groups.push(group);
5108 while (polygon = neighbors.pop()) {
5109 group.push(polygon);
5110 polygon.forEach(function(ring) {
5111 ring.forEach(function(arc) {
5112 polygonsByArc[arc < 0 ? ~arc : arc].forEach(function(polygon) {
5113 if (!polygon._) {
5114 polygon._ = 1;
5115 neighbors.push(polygon);
5116 }
5117 });
5118 });
5119 });
5120 }
5121 }
5122 });
5123
5124 polygons.forEach(function(polygon) {
5125 delete polygon._;
5126 });
5127
5128 return {
5129 type: "MultiPolygon",
5130 arcs: groups.map(function(polygons) {
5131 var arcs = [], n;
5132
5133 // Extract the exterior (unique) arcs.
5134 polygons.forEach(function(polygon) {
5135 polygon.forEach(function(ring) {
5136 ring.forEach(function(arc) {
5137 if (polygonsByArc[arc < 0 ? ~arc : arc].length < 2) {
5138 arcs.push(arc);
5139 }
5140 });
5141 });
5142 });
5143
5144 // Stitch the arcs into one or more rings.
5145 arcs = stitch(topology, arcs);
5146
5147 // If more than one ring is returned,
5148 // at most one of these rings can be the exterior;
5149 // choose the one with the greatest absolute area.
5150 if ((n = arcs.length) > 1) {
5151 for (var i = 1, k = area(arcs[0]), ki, t; i < n; ++i) {
5152 if ((ki = area(arcs[i])) > k) {
5153 t = arcs[0], arcs[0] = arcs[i], arcs[i] = t, k = ki;
5154 }
5155 }
5156 }
5157
5158 return arcs;
5159 })
5160 };
5161}
5162
5163// Computes the bounding box of the specified hash of GeoJSON objects.
5164var bounds = function(objects) {
5165 var x0 = Infinity,
5166 y0 = Infinity,
5167 x1 = -Infinity,
5168 y1 = -Infinity;
5169
5170 function boundGeometry(geometry) {
5171 if (geometry != null && boundGeometryType.hasOwnProperty(geometry.type)) boundGeometryType[geometry.type](geometry);
5172 }
5173
5174 var boundGeometryType = {
5175 GeometryCollection: function(o) { o.geometries.forEach(boundGeometry); },
5176 Point: function(o) { boundPoint(o.coordinates); },
5177 MultiPoint: function(o) { o.coordinates.forEach(boundPoint); },
5178 LineString: function(o) { boundLine(o.arcs); },
5179 MultiLineString: function(o) { o.arcs.forEach(boundLine); },
5180 Polygon: function(o) { o.arcs.forEach(boundLine); },
5181 MultiPolygon: function(o) { o.arcs.forEach(boundMultiLine); }
5182 };
5183
5184 function boundPoint(coordinates) {
5185 var x = coordinates[0],
5186 y = coordinates[1];
5187 if (x < x0) x0 = x;
5188 if (x > x1) x1 = x;
5189 if (y < y0) y0 = y;
5190 if (y > y1) y1 = y;
5191 }
5192
5193 function boundLine(coordinates) {
5194 coordinates.forEach(boundPoint);
5195 }
5196
5197 function boundMultiLine(coordinates) {
5198 coordinates.forEach(boundLine);
5199 }
5200
5201 for (var key in objects) {
5202 boundGeometry(objects[key]);
5203 }
5204
5205 return x1 >= x0 && y1 >= y0 ? [x0, y0, x1, y1] : undefined;
5206};
5207
5208var hashset = function(size, hash, equal, type, empty) {
5209 if (arguments.length === 3) {
5210 type = Array;
5211 empty = null;
5212 }
5213
5214 var store = new type(size = 1 << Math.max(4, Math.ceil(Math.log(size) / Math.LN2))),
5215 mask = size - 1;
5216
5217 for (var i = 0; i < size; ++i) {
5218 store[i] = empty;
5219 }
5220
5221 function add(value) {
5222 var index = hash(value) & mask,
5223 match = store[index],
5224 collisions = 0;
5225 while (match != empty) {
5226 if (equal(match, value)) return true;
5227 if (++collisions >= size) throw new Error("full hashset");
5228 match = store[index = (index + 1) & mask];
5229 }
5230 store[index] = value;
5231 return true;
5232 }
5233
5234 function has(value) {
5235 var index = hash(value) & mask,
5236 match = store[index],
5237 collisions = 0;
5238 while (match != empty) {
5239 if (equal(match, value)) return true;
5240 if (++collisions >= size) break;
5241 match = store[index = (index + 1) & mask];
5242 }
5243 return false;
5244 }
5245
5246 function values() {
5247 var values = [];
5248 for (var i = 0, n = store.length; i < n; ++i) {
5249 var match = store[i];
5250 if (match != empty) values.push(match);
5251 }
5252 return values;
5253 }
5254
5255 return {
5256 add: add,
5257 has: has,
5258 values: values
5259 };
5260};
5261
5262var hashmap = function(size, hash, equal, keyType, keyEmpty, valueType) {
5263 if (arguments.length === 3) {
5264 keyType = valueType = Array;
5265 keyEmpty = null;
5266 }
5267
5268 var keystore = new keyType(size = 1 << Math.max(4, Math.ceil(Math.log(size) / Math.LN2))),
5269 valstore = new valueType(size),
5270 mask = size - 1;
5271
5272 for (var i = 0; i < size; ++i) {
5273 keystore[i] = keyEmpty;
5274 }
5275
5276 function set(key, value) {
5277 var index = hash(key) & mask,
5278 matchKey = keystore[index],
5279 collisions = 0;
5280 while (matchKey != keyEmpty) {
5281 if (equal(matchKey, key)) return valstore[index] = value;
5282 if (++collisions >= size) throw new Error("full hashmap");
5283 matchKey = keystore[index = (index + 1) & mask];
5284 }
5285 keystore[index] = key;
5286 valstore[index] = value;
5287 return value;
5288 }
5289
5290 function maybeSet(key, value) {
5291 var index = hash(key) & mask,
5292 matchKey = keystore[index],
5293 collisions = 0;
5294 while (matchKey != keyEmpty) {
5295 if (equal(matchKey, key)) return valstore[index];
5296 if (++collisions >= size) throw new Error("full hashmap");
5297 matchKey = keystore[index = (index + 1) & mask];
5298 }
5299 keystore[index] = key;
5300 valstore[index] = value;
5301 return value;
5302 }
5303
5304 function get(key, missingValue) {
5305 var index = hash(key) & mask,
5306 matchKey = keystore[index],
5307 collisions = 0;
5308 while (matchKey != keyEmpty) {
5309 if (equal(matchKey, key)) return valstore[index];
5310 if (++collisions >= size) break;
5311 matchKey = keystore[index = (index + 1) & mask];
5312 }
5313 return missingValue;
5314 }
5315
5316 function keys() {
5317 var keys = [];
5318 for (var i = 0, n = keystore.length; i < n; ++i) {
5319 var matchKey = keystore[i];
5320 if (matchKey != keyEmpty) keys.push(matchKey);
5321 }
5322 return keys;
5323 }
5324
5325 return {
5326 set: set,
5327 maybeSet: maybeSet, // set if unset
5328 get: get,
5329 keys: keys
5330 };
5331};
5332
5333var equalPoint = function(pointA, pointB) {
5334 return pointA[0] === pointB[0] && pointA[1] === pointB[1];
5335};
5336
5337// TODO if quantized, use simpler Int32 hashing?
5338
5339var buffer = new ArrayBuffer(16);
5340var floats = new Float64Array(buffer);
5341var uints = new Uint32Array(buffer);
5342
5343var hashPoint = function(point) {
5344 floats[0] = point[0];
5345 floats[1] = point[1];
5346 var hash = uints[0] ^ uints[1];
5347 hash = hash << 5 ^ hash >> 7 ^ uints[2] ^ uints[3];
5348 return hash & 0x7fffffff;
5349};
5350
5351// Given an extracted (pre-)topology, identifies all of the junctions. These are
5352// the points at which arcs (lines or rings) will need to be cut so that each
5353// arc is represented uniquely.
5354//
5355// A junction is a point where at least one arc deviates from another arc going
5356// through the same point. For example, consider the point B. If there is a arc
5357// through ABC and another arc through CBA, then B is not a junction because in
5358// both cases the adjacent point pairs are {A,C}. However, if there is an
5359// additional arc ABD, then {A,D} != {A,C}, and thus B becomes a junction.
5360//
5361// For a closed ring ABCA, the first point A’s adjacent points are the second
5362// and last point {B,C}. For a line, the first and last point are always
5363// considered junctions, even if the line is closed; this ensures that a closed
5364// line is never rotated.
5365var join = function(topology) {
5366 var coordinates = topology.coordinates,
5367 lines = topology.lines,
5368 rings = topology.rings,
5369 indexes = index(),
5370 visitedByIndex = new Int32Array(coordinates.length),
5371 leftByIndex = new Int32Array(coordinates.length),
5372 rightByIndex = new Int32Array(coordinates.length),
5373 junctionByIndex = new Int8Array(coordinates.length),
5374 junctionCount = 0, // upper bound on number of junctions
5375 i, n,
5376 previousIndex,
5377 currentIndex,
5378 nextIndex;
5379
5380 for (i = 0, n = coordinates.length; i < n; ++i) {
5381 visitedByIndex[i] = leftByIndex[i] = rightByIndex[i] = -1;
5382 }
5383
5384 for (i = 0, n = lines.length; i < n; ++i) {
5385 var line = lines[i],
5386 lineStart = line[0],
5387 lineEnd = line[1];
5388 currentIndex = indexes[lineStart];
5389 nextIndex = indexes[++lineStart];
5390 ++junctionCount, junctionByIndex[currentIndex] = 1; // start
5391 while (++lineStart <= lineEnd) {
5392 sequence(i, previousIndex = currentIndex, currentIndex = nextIndex, nextIndex = indexes[lineStart]);
5393 }
5394 ++junctionCount, junctionByIndex[nextIndex] = 1; // end
5395 }
5396
5397 for (i = 0, n = coordinates.length; i < n; ++i) {
5398 visitedByIndex[i] = -1;
5399 }
5400
5401 for (i = 0, n = rings.length; i < n; ++i) {
5402 var ring = rings[i],
5403 ringStart = ring[0] + 1,
5404 ringEnd = ring[1];
5405 previousIndex = indexes[ringEnd - 1];
5406 currentIndex = indexes[ringStart - 1];
5407 nextIndex = indexes[ringStart];
5408 sequence(i, previousIndex, currentIndex, nextIndex);
5409 while (++ringStart <= ringEnd) {
5410 sequence(i, previousIndex = currentIndex, currentIndex = nextIndex, nextIndex = indexes[ringStart]);
5411 }
5412 }
5413
5414 function sequence(i, previousIndex, currentIndex, nextIndex) {
5415 if (visitedByIndex[currentIndex] === i) return; // ignore self-intersection
5416 visitedByIndex[currentIndex] = i;
5417 var leftIndex = leftByIndex[currentIndex];
5418 if (leftIndex >= 0) {
5419 var rightIndex = rightByIndex[currentIndex];
5420 if ((leftIndex !== previousIndex || rightIndex !== nextIndex)
5421 && (leftIndex !== nextIndex || rightIndex !== previousIndex)) {
5422 ++junctionCount, junctionByIndex[currentIndex] = 1;
5423 }
5424 } else {
5425 leftByIndex[currentIndex] = previousIndex;
5426 rightByIndex[currentIndex] = nextIndex;
5427 }
5428 }
5429
5430 function index() {
5431 var indexByPoint = hashmap(coordinates.length * 1.4, hashIndex, equalIndex, Int32Array, -1, Int32Array),
5432 indexes = new Int32Array(coordinates.length);
5433
5434 for (var i = 0, n = coordinates.length; i < n; ++i) {
5435 indexes[i] = indexByPoint.maybeSet(i, i);
5436 }
5437
5438 return indexes;
5439 }
5440
5441 function hashIndex(i) {
5442 return hashPoint(coordinates[i]);
5443 }
5444
5445 function equalIndex(i, j) {
5446 return equalPoint(coordinates[i], coordinates[j]);
5447 }
5448
5449 visitedByIndex = leftByIndex = rightByIndex = null;
5450
5451 var junctionByPoint = hashset(junctionCount * 1.4, hashPoint, equalPoint), j;
5452
5453 // Convert back to a standard hashset by point for caller convenience.
5454 for (i = 0, n = coordinates.length; i < n; ++i) {
5455 if (junctionByIndex[j = indexes[i]]) {
5456 junctionByPoint.add(coordinates[j]);
5457 }
5458 }
5459
5460 return junctionByPoint;
5461};
5462
5463// Given an extracted (pre-)topology, cuts (or rotates) arcs so that all shared
5464// point sequences are identified. The topology can then be subsequently deduped
5465// to remove exact duplicate arcs.
5466var cut = function(topology) {
5467 var junctions = join(topology),
5468 coordinates = topology.coordinates,
5469 lines = topology.lines,
5470 rings = topology.rings,
5471 next,
5472 i, n;
5473
5474 for (i = 0, n = lines.length; i < n; ++i) {
5475 var line = lines[i],
5476 lineMid = line[0],
5477 lineEnd = line[1];
5478 while (++lineMid < lineEnd) {
5479 if (junctions.has(coordinates[lineMid])) {
5480 next = {0: lineMid, 1: line[1]};
5481 line[1] = lineMid;
5482 line = line.next = next;
5483 }
5484 }
5485 }
5486
5487 for (i = 0, n = rings.length; i < n; ++i) {
5488 var ring = rings[i],
5489 ringStart = ring[0],
5490 ringMid = ringStart,
5491 ringEnd = ring[1],
5492 ringFixed = junctions.has(coordinates[ringStart]);
5493 while (++ringMid < ringEnd) {
5494 if (junctions.has(coordinates[ringMid])) {
5495 if (ringFixed) {
5496 next = {0: ringMid, 1: ring[1]};
5497 ring[1] = ringMid;
5498 ring = ring.next = next;
5499 } else { // For the first junction, we can rotate rather than cut.
5500 rotateArray(coordinates, ringStart, ringEnd, ringEnd - ringMid);
5501 coordinates[ringEnd] = coordinates[ringStart];
5502 ringFixed = true;
5503 ringMid = ringStart; // restart; we may have skipped junctions
5504 }
5505 }
5506 }
5507 }
5508
5509 return topology;
5510};
5511
5512function rotateArray(array, start, end, offset) {
5513 reverse$1(array, start, end);
5514 reverse$1(array, start, start + offset);
5515 reverse$1(array, start + offset, end);
5516}
5517
5518function reverse$1(array, start, end) {
5519 for (var mid = start + ((end-- - start) >> 1), t; start < mid; ++start, --end) {
5520 t = array[start], array[start] = array[end], array[end] = t;
5521 }
5522}
5523
5524// Given a cut topology, combines duplicate arcs.
5525var dedup$1 = function(topology) {
5526 var coordinates = topology.coordinates,
5527 lines = topology.lines, line,
5528 rings = topology.rings, ring,
5529 arcCount = lines.length + rings.length,
5530 i, n;
5531
5532 delete topology.lines;
5533 delete topology.rings;
5534
5535 // Count the number of (non-unique) arcs to initialize the hashmap safely.
5536 for (i = 0, n = lines.length; i < n; ++i) {
5537 line = lines[i]; while (line = line.next) ++arcCount;
5538 }
5539 for (i = 0, n = rings.length; i < n; ++i) {
5540 ring = rings[i]; while (ring = ring.next) ++arcCount;
5541 }
5542
5543 var arcsByEnd = hashmap(arcCount * 2 * 1.4, hashPoint, equalPoint),
5544 arcs = topology.arcs = [];
5545
5546 for (i = 0, n = lines.length; i < n; ++i) {
5547 line = lines[i];
5548 do {
5549 dedupLine(line);
5550 } while (line = line.next);
5551 }
5552
5553 for (i = 0, n = rings.length; i < n; ++i) {
5554 ring = rings[i];
5555 if (ring.next) { // arc is no longer closed
5556 do {
5557 dedupLine(ring);
5558 } while (ring = ring.next);
5559 } else {
5560 dedupRing(ring);
5561 }
5562 }
5563
5564 function dedupLine(arc) {
5565 var startPoint,
5566 endPoint,
5567 startArcs, startArc,
5568 endArcs, endArc,
5569 i, n;
5570
5571 // Does this arc match an existing arc in order?
5572 if (startArcs = arcsByEnd.get(startPoint = coordinates[arc[0]])) {
5573 for (i = 0, n = startArcs.length; i < n; ++i) {
5574 startArc = startArcs[i];
5575 if (equalLine(startArc, arc)) {
5576 arc[0] = startArc[0];
5577 arc[1] = startArc[1];
5578 return;
5579 }
5580 }
5581 }
5582
5583 // Does this arc match an existing arc in reverse order?
5584 if (endArcs = arcsByEnd.get(endPoint = coordinates[arc[1]])) {
5585 for (i = 0, n = endArcs.length; i < n; ++i) {
5586 endArc = endArcs[i];
5587 if (reverseEqualLine(endArc, arc)) {
5588 arc[1] = endArc[0];
5589 arc[0] = endArc[1];
5590 return;
5591 }
5592 }
5593 }
5594
5595 if (startArcs) startArcs.push(arc); else arcsByEnd.set(startPoint, [arc]);
5596 if (endArcs) endArcs.push(arc); else arcsByEnd.set(endPoint, [arc]);
5597 arcs.push(arc);
5598 }
5599
5600 function dedupRing(arc) {
5601 var endPoint,
5602 endArcs,
5603 endArc,
5604 i, n;
5605
5606 // Does this arc match an existing line in order, or reverse order?
5607 // Rings are closed, so their start point and end point is the same.
5608 if (endArcs = arcsByEnd.get(endPoint = coordinates[arc[0]])) {
5609 for (i = 0, n = endArcs.length; i < n; ++i) {
5610 endArc = endArcs[i];
5611 if (equalRing(endArc, arc)) {
5612 arc[0] = endArc[0];
5613 arc[1] = endArc[1];
5614 return;
5615 }
5616 if (reverseEqualRing(endArc, arc)) {
5617 arc[0] = endArc[1];
5618 arc[1] = endArc[0];
5619 return;
5620 }
5621 }
5622 }
5623
5624 // Otherwise, does this arc match an existing ring in order, or reverse order?
5625 if (endArcs = arcsByEnd.get(endPoint = coordinates[arc[0] + findMinimumOffset(arc)])) {
5626 for (i = 0, n = endArcs.length; i < n; ++i) {
5627 endArc = endArcs[i];
5628 if (equalRing(endArc, arc)) {
5629 arc[0] = endArc[0];
5630 arc[1] = endArc[1];
5631 return;
5632 }
5633 if (reverseEqualRing(endArc, arc)) {
5634 arc[0] = endArc[1];
5635 arc[1] = endArc[0];
5636 return;
5637 }
5638 }
5639 }
5640
5641 if (endArcs) endArcs.push(arc); else arcsByEnd.set(endPoint, [arc]);
5642 arcs.push(arc);
5643 }
5644
5645 function equalLine(arcA, arcB) {
5646 var ia = arcA[0], ib = arcB[0],
5647 ja = arcA[1], jb = arcB[1];
5648 if (ia - ja !== ib - jb) return false;
5649 for (; ia <= ja; ++ia, ++ib) if (!equalPoint(coordinates[ia], coordinates[ib])) return false;
5650 return true;
5651 }
5652
5653 function reverseEqualLine(arcA, arcB) {
5654 var ia = arcA[0], ib = arcB[0],
5655 ja = arcA[1], jb = arcB[1];
5656 if (ia - ja !== ib - jb) return false;
5657 for (; ia <= ja; ++ia, --jb) if (!equalPoint(coordinates[ia], coordinates[jb])) return false;
5658 return true;
5659 }
5660
5661 function equalRing(arcA, arcB) {
5662 var ia = arcA[0], ib = arcB[0],
5663 ja = arcA[1], jb = arcB[1],
5664 n = ja - ia;
5665 if (n !== jb - ib) return false;
5666 var ka = findMinimumOffset(arcA),
5667 kb = findMinimumOffset(arcB);
5668 for (var i = 0; i < n; ++i) {
5669 if (!equalPoint(coordinates[ia + (i + ka) % n], coordinates[ib + (i + kb) % n])) return false;
5670 }
5671 return true;
5672 }
5673
5674 function reverseEqualRing(arcA, arcB) {
5675 var ia = arcA[0], ib = arcB[0],
5676 ja = arcA[1], jb = arcB[1],
5677 n = ja - ia;
5678 if (n !== jb - ib) return false;
5679 var ka = findMinimumOffset(arcA),
5680 kb = n - findMinimumOffset(arcB);
5681 for (var i = 0; i < n; ++i) {
5682 if (!equalPoint(coordinates[ia + (i + ka) % n], coordinates[jb - (i + kb) % n])) return false;
5683 }
5684 return true;
5685 }
5686
5687 // Rings are rotated to a consistent, but arbitrary, start point.
5688 // This is necessary to detect when a ring and a rotated copy are dupes.
5689 function findMinimumOffset(arc) {
5690 var start = arc[0],
5691 end = arc[1],
5692 mid = start,
5693 minimum = mid,
5694 minimumPoint = coordinates[mid];
5695 while (++mid < end) {
5696 var point = coordinates[mid];
5697 if (point[0] < minimumPoint[0] || point[0] === minimumPoint[0] && point[1] < minimumPoint[1]) {
5698 minimum = mid;
5699 minimumPoint = point;
5700 }
5701 }
5702 return minimum - start;
5703 }
5704
5705 return topology;
5706};
5707
5708// Given an array of arcs in absolute (but already quantized!) coordinates,
5709// converts to fixed-point delta encoding.
5710// This is a destructive operation that modifies the given arcs!
5711var delta = function(arcs) {
5712 var i = -1,
5713 n = arcs.length;
5714
5715 while (++i < n) {
5716 var arc = arcs[i],
5717 j = 0,
5718 k = 1,
5719 m = arc.length,
5720 point = arc[0],
5721 x0 = point[0],
5722 y0 = point[1],
5723 x1,
5724 y1;
5725
5726 while (++j < m) {
5727 point = arc[j], x1 = point[0], y1 = point[1];
5728 if (x1 !== x0 || y1 !== y0) arc[k++] = [x1 - x0, y1 - y0], x0 = x1, y0 = y1;
5729 }
5730
5731 if (k === 1) arc[k++] = [0, 0]; // Each arc must be an array of two or more positions.
5732
5733 arc.length = k;
5734 }
5735
5736 return arcs;
5737};
5738
5739// Extracts the lines and rings from the specified hash of geometry objects.
5740//
5741// Returns an object with three properties:
5742//
5743// * coordinates - shared buffer of [x, y] coordinates
5744// * lines - lines extracted from the hash, of the form [start, end]
5745// * rings - rings extracted from the hash, of the form [start, end]
5746//
5747// For each ring or line, start and end represent inclusive indexes into the
5748// coordinates buffer. For rings (and closed lines), coordinates[start] equals
5749// coordinates[end].
5750//
5751// For each line or polygon geometry in the input hash, including nested
5752// geometries as in geometry collections, the `coordinates` array is replaced
5753// with an equivalent `arcs` array that, for each line (for line string
5754// geometries) or ring (for polygon geometries), points to one of the above
5755// lines or rings.
5756var extract = function(objects) {
5757 var index = -1,
5758 lines = [],
5759 rings = [],
5760 coordinates = [];
5761
5762 function extractGeometry(geometry) {
5763 if (geometry && extractGeometryType.hasOwnProperty(geometry.type)) extractGeometryType[geometry.type](geometry);
5764 }
5765
5766 var extractGeometryType = {
5767 GeometryCollection: function(o) { o.geometries.forEach(extractGeometry); },
5768 LineString: function(o) { o.arcs = extractLine(o.arcs); },
5769 MultiLineString: function(o) { o.arcs = o.arcs.map(extractLine); },
5770 Polygon: function(o) { o.arcs = o.arcs.map(extractRing); },
5771 MultiPolygon: function(o) { o.arcs = o.arcs.map(extractMultiRing); }
5772 };
5773
5774 function extractLine(line) {
5775 for (var i = 0, n = line.length; i < n; ++i) coordinates[++index] = line[i];
5776 var arc = {0: index - n + 1, 1: index};
5777 lines.push(arc);
5778 return arc;
5779 }
5780
5781 function extractRing(ring) {
5782 for (var i = 0, n = ring.length; i < n; ++i) coordinates[++index] = ring[i];
5783 var arc = {0: index - n + 1, 1: index};
5784 rings.push(arc);
5785 return arc;
5786 }
5787
5788 function extractMultiRing(rings) {
5789 return rings.map(extractRing);
5790 }
5791
5792 for (var key in objects) {
5793 extractGeometry(objects[key]);
5794 }
5795
5796 return {
5797 type: "Topology",
5798 coordinates: coordinates,
5799 lines: lines,
5800 rings: rings,
5801 objects: objects
5802 };
5803};
5804
5805// Given a hash of GeoJSON objects, returns a hash of GeoJSON geometry objects.
5806// Any null input geometry objects are represented as {type: null} in the output.
5807// Any feature.{id,properties,bbox} are transferred to the output geometry object.
5808// Each output geometry object is a shallow copy of the input (e.g., properties, coordinates)!
5809var geometry$1 = function(inputs) {
5810 var outputs = {}, key;
5811 for (key in inputs) outputs[key] = geomifyObject(inputs[key]);
5812 return outputs;
5813};
5814
5815function geomifyObject(input) {
5816 return input == null ? {type: null}
5817 : (input.type === "FeatureCollection" ? geomifyFeatureCollection
5818 : input.type === "Feature" ? geomifyFeature
5819 : geomifyGeometry)(input);
5820}
5821
5822function geomifyFeatureCollection(input) {
5823 var output = {type: "GeometryCollection", geometries: input.features.map(geomifyFeature)};
5824 if (input.bbox != null) output.bbox = input.bbox;
5825 return output;
5826}
5827
5828function geomifyFeature(input) {
5829 var output = geomifyGeometry(input.geometry), key; // eslint-disable-line no-unused-vars
5830 if (input.id != null) output.id = input.id;
5831 if (input.bbox != null) output.bbox = input.bbox;
5832 for (key in input.properties) { output.properties = input.properties; break; }
5833 return output;
5834}
5835
5836function geomifyGeometry(input) {
5837 if (input == null) return {type: null};
5838 var output = input.type === "GeometryCollection" ? {type: "GeometryCollection", geometries: input.geometries.map(geomifyGeometry)}
5839 : input.type === "Point" || input.type === "MultiPoint" ? {type: input.type, coordinates: input.coordinates}
5840 : {type: input.type, arcs: input.coordinates}; // TODO Check for unknown types?
5841 if (input.bbox != null) output.bbox = input.bbox;
5842 return output;
5843}
5844
5845var prequantize = function(objects, bbox, n) {
5846 var x0 = bbox[0],
5847 y0 = bbox[1],
5848 x1 = bbox[2],
5849 y1 = bbox[3],
5850 kx = x1 - x0 ? (n - 1) / (x1 - x0) : 1,
5851 ky = y1 - y0 ? (n - 1) / (y1 - y0) : 1;
5852
5853 function quantizePoint(input) {
5854 return [Math.round((input[0] - x0) * kx), Math.round((input[1] - y0) * ky)];
5855 }
5856
5857 function quantizePoints(input, m) {
5858 var i = -1,
5859 j = 0,
5860 n = input.length,
5861 output = new Array(n), // pessimistic
5862 pi,
5863 px,
5864 py,
5865 x,
5866 y;
5867
5868 while (++i < n) {
5869 pi = input[i];
5870 x = Math.round((pi[0] - x0) * kx);
5871 y = Math.round((pi[1] - y0) * ky);
5872 if (x !== px || y !== py) output[j++] = [px = x, py = y]; // non-coincident points
5873 }
5874
5875 output.length = j;
5876 while (j < m) j = output.push([output[0][0], output[0][1]]);
5877 return output;
5878 }
5879
5880 function quantizeLine(input) {
5881 return quantizePoints(input, 2);
5882 }
5883
5884 function quantizeRing(input) {
5885 return quantizePoints(input, 4);
5886 }
5887
5888 function quantizePolygon(input) {
5889 return input.map(quantizeRing);
5890 }
5891
5892 function quantizeGeometry(o) {
5893 if (o != null && quantizeGeometryType.hasOwnProperty(o.type)) quantizeGeometryType[o.type](o);
5894 }
5895
5896 var quantizeGeometryType = {
5897 GeometryCollection: function(o) { o.geometries.forEach(quantizeGeometry); },
5898 Point: function(o) { o.coordinates = quantizePoint(o.coordinates); },
5899 MultiPoint: function(o) { o.coordinates = o.coordinates.map(quantizePoint); },
5900 LineString: function(o) { o.arcs = quantizeLine(o.arcs); },
5901 MultiLineString: function(o) { o.arcs = o.arcs.map(quantizeLine); },
5902 Polygon: function(o) { o.arcs = quantizePolygon(o.arcs); },
5903 MultiPolygon: function(o) { o.arcs = o.arcs.map(quantizePolygon); }
5904 };
5905
5906 for (var key in objects) {
5907 quantizeGeometry(objects[key]);
5908 }
5909
5910 return {
5911 scale: [1 / kx, 1 / ky],
5912 translate: [x0, y0]
5913 };
5914};
5915
5916// Constructs the TopoJSON Topology for the specified hash of features.
5917// Each object in the specified hash must be a GeoJSON object,
5918// meaning FeatureCollection, a Feature or a geometry object.
5919var topology = function(objects, quantization) {
5920 var bbox = bounds(objects = geometry$1(objects)),
5921 transform = quantization > 0 && bbox && prequantize(objects, bbox, quantization),
5922 topology = dedup$1(cut(extract(objects))),
5923 coordinates = topology.coordinates,
5924 indexByArc = hashmap(topology.arcs.length * 1.4, hashArc, equalArc);
5925
5926 objects = topology.objects; // for garbage collection
5927 topology.bbox = bbox;
5928 topology.arcs = topology.arcs.map(function(arc, i) {
5929 indexByArc.set(arc, i);
5930 return coordinates.slice(arc[0], arc[1] + 1);
5931 });
5932
5933 delete topology.coordinates;
5934 coordinates = null;
5935
5936 function indexGeometry(geometry) {
5937 if (geometry && indexGeometryType.hasOwnProperty(geometry.type)) indexGeometryType[geometry.type](geometry);
5938 }
5939
5940 var indexGeometryType = {
5941 GeometryCollection: function(o) { o.geometries.forEach(indexGeometry); },
5942 LineString: function(o) { o.arcs = indexArcs(o.arcs); },
5943 MultiLineString: function(o) { o.arcs = o.arcs.map(indexArcs); },
5944 Polygon: function(o) { o.arcs = o.arcs.map(indexArcs); },
5945 MultiPolygon: function(o) { o.arcs = o.arcs.map(indexMultiArcs); }
5946 };
5947
5948 function indexArcs(arc) {
5949 var indexes = [];
5950 do {
5951 var index = indexByArc.get(arc);
5952 indexes.push(arc[0] < arc[1] ? index : ~index);
5953 } while (arc = arc.next);
5954 return indexes;
5955 }
5956
5957 function indexMultiArcs(arcs) {
5958 return arcs.map(indexArcs);
5959 }
5960
5961 for (var key in objects) {
5962 indexGeometry(objects[key]);
5963 }
5964
5965 if (transform) {
5966 topology.transform = transform;
5967 topology.arcs = delta(topology.arcs);
5968 }
5969
5970 return topology;
5971};
5972
5973function hashArc(arc) {
5974 var i = arc[0], j = arc[1], t;
5975 if (j < i) t = i, i = j, j = t;
5976 return i + 31 * j;
5977}
5978
5979function equalArc(arcA, arcB) {
5980 var ia = arcA[0], ja = arcA[1],
5981 ib = arcB[0], jb = arcB[1], t;
5982 if (ja < ia) t = ia, ia = ja, ja = t;
5983 if (jb < ib) t = ib, ib = jb, jb = t;
5984 return ia === ib && ja === jb;
5985}
5986
5987/**
5988 * Merges all connected (non-forking, non-junctioning) line strings into single lineStrings.
5989 * [LineString] -> LineString|MultiLineString
5990 *
5991 * @param {FeatureCollection<LineString|MultiLineString>} geojson Lines to dissolve
5992 * @param {Object} [options={}] Optional parameters
5993 * @param {boolean} [options.mutate=false] Prevent input mutation
5994 * @returns {Feature<LineString|MultiLineString>} Dissolved lines
5995 */
5996function lineDissolve(geojson, options) {
5997 // Optional parameters
5998 options = options || {};
5999 if (!isObject(options)) throw new Error('options is invalid');
6000 var mutate = options.mutate;
6001
6002 // Validation
6003 if (getType(geojson) !== 'FeatureCollection') throw new Error('geojson must be a FeatureCollection');
6004 if (!geojson.features.length) throw new Error('geojson is empty');
6005
6006 // Clone geojson to avoid side effects
6007 if (mutate === false || mutate === undefined) geojson = clone(geojson);
6008
6009 var result = [];
6010 var lastLine = lineReduce(geojson, function (previousLine, currentLine) {
6011 // Attempt to merge this LineString with the other LineStrings, updating
6012 // the reference as it is merged with others and grows.
6013 var merged = mergeLineStrings(previousLine, currentLine);
6014
6015 // Accumulate the merged LineString
6016 if (merged) return merged;
6017
6018 // Put the unmerged LineString back into the list
6019 else {
6020 result.push(previousLine);
6021 return currentLine;
6022 }
6023 });
6024 // Append the last line
6025 if (lastLine) result.push(lastLine);
6026
6027 // Return null if no lines were dissolved
6028 if (!result.length) return null;
6029 // Return LineString if only 1 line was dissolved
6030 else if (result.length === 1) return result[0];
6031 // Return MultiLineString if multiple lines were dissolved with gaps
6032 else return multiLineString(result.map(function (line) { return line.coordinates; }));
6033}
6034
6035// [Number, Number] -> String
6036function coordId(coord) {
6037 return coord[0].toString() + ',' + coord[1].toString();
6038}
6039
6040/**
6041 * LineString, LineString -> LineString
6042 *
6043 * @private
6044 * @param {Feature<LineString>} a line1
6045 * @param {Feature<LineString>} b line2
6046 * @returns {Feature<LineString>|null} Merged LineString
6047 */
6048function mergeLineStrings(a, b) {
6049 var coords1 = a.geometry.coordinates;
6050 var coords2 = b.geometry.coordinates;
6051
6052 var s1 = coordId(coords1[0]);
6053 var e1 = coordId(coords1[coords1.length - 1]);
6054 var s2 = coordId(coords2[0]);
6055 var e2 = coordId(coords2[coords2.length - 1]);
6056
6057 // TODO: handle case where more than one of these is true!
6058 var coords;
6059 if (s1 === e2) coords = coords2.concat(coords1.slice(1));
6060 else if (s2 === e1) coords = coords1.concat(coords2.slice(1));
6061 else if (s1 === s2) coords = coords1.slice(1).reverse().concat(coords2);
6062 else if (e1 === e2) coords = coords1.concat(coords2.reverse().slice(1));
6063 else return null;
6064
6065 return lineString(coords);
6066}
6067
6068/**
6069 * Dissolves all overlapping (Multi)Polygon
6070 *
6071 * @param {FeatureCollection<Polygon|MultiPolygon>} geojson Polygons to dissolve
6072 * @param {Object} [options={}] Optional parameters
6073 * @param {boolean} [options.mutate=false] Prevent input mutation
6074 * @returns {Feature<Polygon|MultiPolygon>} Dissolved Polygons
6075 */
6076function polygonDissolve(geojson, options) {
6077 // Optional parameters
6078 options = options || {};
6079 if (!isObject(options)) throw new Error('options is invalid');
6080 var mutate = options.mutate;
6081
6082 // Validation
6083 if (getType(geojson) !== 'FeatureCollection') throw new Error('geojson must be a FeatureCollection');
6084 if (!geojson.features.length) throw new Error('geojson is empty');
6085
6086 // Clone geojson to avoid side effects
6087 // Topojson modifies in place, so we need to deep clone first
6088 if (mutate === false || mutate === undefined) geojson = clone(geojson);
6089
6090 var geoms = [];
6091 flattenEach(geojson, function (feature$$1) {
6092 geoms.push(feature$$1.geometry);
6093 });
6094 var topo = topology({geoms: geometryCollection(geoms).geometry});
6095 return merge(topo, topo.objects.geoms.geometries);
6096}
6097
6098/**
6099 * Transform function: attempts to dissolve geojson objects where possible
6100 * [GeoJSON] -> GeoJSON geometry
6101 *
6102 * @private
6103 * @param {FeatureCollection<LineString|MultiLineString|Polygon|MultiPolygon>} geojson Features to dissolved
6104 * @param {Object} [options={}] Optional parameters
6105 * @param {boolean} [options.mutate=false] Prevent input mutation
6106 * @returns {Feature<MultiLineString|MultiPolygon>} Dissolved Features
6107 */
6108function dissolve(geojson, options) {
6109 // Optional parameters
6110 options = options || {};
6111 if (!isObject(options)) throw new Error('options is invalid');
6112 var mutate = options.mutate;
6113
6114 // Validation
6115 if (getType(geojson) !== 'FeatureCollection') throw new Error('geojson must be a FeatureCollection');
6116 if (!geojson.features.length) throw new Error('geojson is empty');
6117
6118 // Clone geojson to avoid side effects
6119 // Topojson modifies in place, so we need to deep clone first
6120 if (mutate === false || mutate === undefined) geojson = clone(geojson);
6121
6122 // Assert homogenity
6123 var type = getHomogenousType(geojson);
6124 if (!type) throw new Error('geojson must be homogenous');
6125
6126 switch (type) {
6127 case 'LineString':
6128 return lineDissolve(geojson, options);
6129 case 'Polygon':
6130 return polygonDissolve(geojson, options);
6131 default:
6132 throw new Error(type + ' is not supported');
6133 }
6134}
6135
6136/**
6137 * Checks if GeoJSON is Homogenous
6138 *
6139 * @private
6140 * @param {GeoJSON} geojson GeoJSON
6141 * @returns {string|null} Homogenous type or null if multiple types
6142 */
6143function getHomogenousType(geojson) {
6144 var types = {};
6145 flattenEach(geojson, function (feature$$1) {
6146 types[feature$$1.geometry.type] = true;
6147 });
6148 var keys = Object.keys(types);
6149 if (keys.length === 1) return keys[0];
6150 return null;
6151}
6152
6153/**
6154 * Takes a set of {@link Point|points} and returns a concave hull Polygon or MultiPolygon.
6155 * Internally, this uses [turf-tin](https://github.com/Turfjs/turf-tin) to generate geometries.
6156 *
6157 * @name concave
6158 * @param {FeatureCollection<Point>} points input points
6159 * @param {Object} [options={}] Optional parameters
6160 * @param {number} [options.maxEdge=Infinity] the length (in 'units') of an edge necessary for part of the hull to become concave.
6161 * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers
6162 * @returns {Feature<(Polygon|MultiPolygon)>|null} a concave hull (null value is returned if unable to compute hull)
6163 * @example
6164 * var points = turf.featureCollection([
6165 * turf.point([-63.601226, 44.642643]),
6166 * turf.point([-63.591442, 44.651436]),
6167 * turf.point([-63.580799, 44.648749]),
6168 * turf.point([-63.573589, 44.641788]),
6169 * turf.point([-63.587665, 44.64533]),
6170 * turf.point([-63.595218, 44.64765])
6171 * ]);
6172 * var options = {units: 'miles', maxEdge: 1};
6173 *
6174 * var hull = turf.concave(points, options);
6175 *
6176 * //addToMap
6177 * var addToMap = [points, hull]
6178 */
6179function concave(points$$1, options) {
6180 // Optional parameters
6181 options = options || {};
6182 if (!isObject(options)) throw new Error('options is invalid');
6183
6184 // validation
6185 if (!points$$1) throw new Error('points is required');
6186 var maxEdge = options.maxEdge || Infinity;
6187 if (!isNumber(maxEdge)) throw new Error('maxEdge is invalid');
6188
6189 var cleaned = removeDuplicates(points$$1);
6190
6191 var tinPolys = tin(cleaned);
6192 // calculate length of all edges and area of all triangles
6193 // and remove triangles that fail the max length test
6194 tinPolys.features = tinPolys.features.filter(function (triangle) {
6195 var pt1 = triangle.geometry.coordinates[0][0];
6196 var pt2 = triangle.geometry.coordinates[0][1];
6197 var pt3 = triangle.geometry.coordinates[0][2];
6198 var dist1 = distance(pt1, pt2, options);
6199 var dist2 = distance(pt2, pt3, options);
6200 var dist3 = distance(pt1, pt3, options);
6201 return (dist1 <= maxEdge && dist2 <= maxEdge && dist3 <= maxEdge);
6202 });
6203
6204 if (tinPolys.features.length < 1) return null;
6205
6206 // merge the adjacent triangles
6207 var dissolved = dissolve(tinPolys, options);
6208
6209 // geojson-dissolve always returns a MultiPolygon
6210 if (dissolved.coordinates.length === 1) {
6211 dissolved.coordinates = dissolved.coordinates[0];
6212 dissolved.type = 'Polygon';
6213 }
6214 return feature(dissolved);
6215}
6216
6217/**
6218 * Removes duplicated points in a collection returning a new collection
6219 *
6220 * @private
6221 * @param {FeatureCollection<Point>} points to be cleaned
6222 * @returns {FeatureCollection<Point>} cleaned set of points
6223 */
6224function removeDuplicates(points$$1) {
6225 var cleaned = [];
6226 var existing = {};
6227
6228 featureEach(points$$1, function (pt) {
6229 if (!pt.geometry) return;
6230 var key = pt.geometry.coordinates.join('-');
6231 if (!existing.hasOwnProperty(key)) {
6232 cleaned.push(pt);
6233 existing[key] = true;
6234 }
6235 });
6236 return featureCollection(cleaned);
6237}
6238
6239/**
6240 * Merges a specified property from a FeatureCollection of points into a
6241 * FeatureCollection of polygons. Given an `inProperty` on points and an `outProperty`
6242 * for polygons, this finds every point that lies within each polygon, collects the
6243 * `inProperty` values from those points, and adds them as an array to `outProperty`
6244 * on the polygon.
6245 *
6246 * @name collect
6247 * @param {FeatureCollection<Polygon>} polygons polygons with values on which to aggregate
6248 * @param {FeatureCollection<Point>} points points to be aggregated
6249 * @param {string} inProperty property to be nested from
6250 * @param {string} outProperty property to be nested into
6251 * @returns {FeatureCollection<Polygon>} polygons with properties listed based on `outField`
6252 * @example
6253 * var poly1 = turf.polygon([[[0,0],[10,0],[10,10],[0,10],[0,0]]]);
6254 * var poly2 = turf.polygon([[[10,0],[20,10],[20,20],[20,0],[10,0]]]);
6255 * var polyFC = turf.featureCollection([poly1, poly2]);
6256 * var pt1 = turf.point([5,5], {population: 200});
6257 * var pt2 = turf.point([1,3], {population: 600});
6258 * var pt3 = turf.point([14,2], {population: 100});
6259 * var pt4 = turf.point([13,1], {population: 200});
6260 * var pt5 = turf.point([19,7], {population: 300});
6261 * var pointFC = turf.featureCollection([pt1, pt2, pt3, pt4, pt5]);
6262 * var collected = turf.collect(polyFC, pointFC, 'population', 'values');
6263 * var values = collected.features[0].properties.values
6264 * //=values => [200, 600]
6265 *
6266 * //addToMap
6267 * var addToMap = [pointFC, collected]
6268 */
6269function collect(polygons, points, inProperty, outProperty) {
6270 var rtree = rbush_1(6);
6271
6272 var treeItems = points.features.map(function (item) {
6273 return {
6274 minX: item.geometry.coordinates[0],
6275 minY: item.geometry.coordinates[1],
6276 maxX: item.geometry.coordinates[0],
6277 maxY: item.geometry.coordinates[1],
6278 property: item.properties[inProperty]
6279 };
6280 });
6281
6282 rtree.load(treeItems);
6283 polygons.features.forEach(function (poly) {
6284
6285 if (!poly.properties) {
6286 poly.properties = {};
6287 }
6288 var bbox$$1 = bbox(poly);
6289 var potentialPoints = rtree.search({minX: bbox$$1[0], minY: bbox$$1[1], maxX: bbox$$1[2], maxY: bbox$$1[3]});
6290 var values = [];
6291 potentialPoints.forEach(function (pt) {
6292 if (booleanPointInPolygon([pt.minX, pt.minY], poly)) {
6293 values.push(pt.property);
6294 }
6295 });
6296
6297 poly.properties[outProperty] = values;
6298 });
6299
6300 return polygons;
6301}
6302
6303/**
6304 * Takes input features and flips all of their coordinates from `[x, y]` to `[y, x]`.
6305 *
6306 * @name flip
6307 * @param {GeoJSON} geojson input features
6308 * @param {Object} [options={}] Optional parameters
6309 * @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated (significant performance increase if true)
6310 * @returns {GeoJSON} a feature or set of features of the same type as `input` with flipped coordinates
6311 * @example
6312 * var serbia = turf.point([20.566406, 43.421008]);
6313 *
6314 * var saudiArabia = turf.flip(serbia);
6315 *
6316 * //addToMap
6317 * var addToMap = [serbia, saudiArabia];
6318 */
6319function flip(geojson, options) {
6320 // Optional parameters
6321 options = options || {};
6322 if (!isObject(options)) throw new Error('options is invalid');
6323 var mutate = options.mutate;
6324
6325 if (!geojson) throw new Error('geojson is required');
6326 // ensure that we don't modify features in-place and changes to the
6327 // output do not change the previous feature, including changes to nested
6328 // properties.
6329 if (mutate === false || mutate === undefined) geojson = clone(geojson);
6330
6331 coordEach(geojson, function (coord) {
6332 var x = coord[0];
6333 var y = coord[1];
6334 coord[0] = y;
6335 coord[1] = x;
6336 });
6337 return geojson;
6338}
6339
6340/**
6341 * Removes redundant coordinates from any GeoJSON Geometry.
6342 *
6343 * @name cleanCoords
6344 * @param {Geometry|Feature} geojson Feature or Geometry
6345 * @param {Object} [options={}] Optional parameters
6346 * @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated
6347 * @returns {Geometry|Feature} the cleaned input Feature/Geometry
6348 * @example
6349 * var line = turf.lineString([[0, 0], [0, 2], [0, 5], [0, 8], [0, 8], [0, 10]]);
6350 * var multiPoint = turf.multiPoint([[0, 0], [0, 0], [2, 2]]);
6351 *
6352 * turf.cleanCoords(line).geometry.coordinates;
6353 * //= [[0, 0], [0, 10]]
6354 *
6355 * turf.cleanCoords(multiPoint).geometry.coordinates;
6356 * //= [[0, 0], [2, 2]]
6357 */
6358function cleanCoords(geojson, options) {
6359 // Backwards compatible with v4.0
6360 var mutate = (typeof options === 'object') ? options.mutate : options;
6361 if (!geojson) throw new Error('geojson is required');
6362 var type = getType(geojson);
6363
6364 // Store new "clean" points in this Array
6365 var newCoords = [];
6366
6367 switch (type) {
6368 case 'LineString':
6369 newCoords = cleanLine(geojson);
6370 break;
6371 case 'MultiLineString':
6372 case 'Polygon':
6373 getCoords(geojson).forEach(function (line) {
6374 newCoords.push(cleanLine(line));
6375 });
6376 break;
6377 case 'MultiPolygon':
6378 getCoords(geojson).forEach(function (polygons$$1) {
6379 var polyPoints = [];
6380 polygons$$1.forEach(function (ring) {
6381 polyPoints.push(cleanLine(ring));
6382 });
6383 newCoords.push(polyPoints);
6384 });
6385 break;
6386 case 'Point':
6387 return geojson;
6388 case 'MultiPoint':
6389 var existing = {};
6390 getCoords(geojson).forEach(function (coord) {
6391 var key = coord.join('-');
6392 if (!existing.hasOwnProperty(key)) {
6393 newCoords.push(coord);
6394 existing[key] = true;
6395 }
6396 });
6397 break;
6398 default:
6399 throw new Error(type + ' geometry not supported');
6400 }
6401
6402 // Support input mutation
6403 if (geojson.coordinates) {
6404 if (mutate === true) {
6405 geojson.coordinates = newCoords;
6406 return geojson;
6407 }
6408 return {type: type, coordinates: newCoords};
6409 } else {
6410 if (mutate === true) {
6411 geojson.geometry.coordinates = newCoords;
6412 return geojson;
6413 }
6414 return feature({type: type, coordinates: newCoords}, geojson.properties, geojson.bbox, geojson.id);
6415 }
6416}
6417
6418/**
6419 * Clean Coords
6420 *
6421 * @private
6422 * @param {Array<number>|LineString} line Line
6423 * @returns {Array<number>} Cleaned coordinates
6424 */
6425function cleanLine(line) {
6426 var points$$1 = getCoords(line);
6427 // handle "clean" segment
6428 if (points$$1.length === 2 && !equals(points$$1[0], points$$1[1])) return points$$1;
6429
6430 var prevPoint, point$$1, nextPoint;
6431 var newPoints = [];
6432 var secondToLast = points$$1.length - 1;
6433
6434 newPoints.push(points$$1[0]);
6435 for (var i = 1; i < secondToLast; i++) {
6436 prevPoint = points$$1[i - 1];
6437 point$$1 = points$$1[i];
6438 nextPoint = points$$1[i + 1];
6439
6440 if (!isPointOnLineSegment(prevPoint, nextPoint, point$$1)) {
6441 newPoints.push(point$$1);
6442 }
6443 }
6444 newPoints.push(nextPoint);
6445 return newPoints;
6446}
6447
6448/**
6449 * Compares two points and returns if they are equals
6450 *
6451 * @private
6452 * @param {Position} pt1 point
6453 * @param {Position} pt2 point
6454 * @returns {boolean} true if they are equals
6455 */
6456function equals(pt1, pt2) {
6457 return pt1[0] === pt2[0] && pt1[1] === pt2[1];
6458}
6459
6460/**
6461 * Returns if `point` is on the segment between `start` and `end`.
6462 * Borrowed from `@turf/boolean-point-on-line` to speed up the evaluation (instead of using the module as dependency)
6463 *
6464 * @private
6465 * @param {Position} start coord pair of start of line
6466 * @param {Position} end coord pair of end of line
6467 * @param {Position} point coord pair of point to check
6468 * @returns {boolean} true/false
6469 */
6470function isPointOnLineSegment(start, end, point$$1) {
6471 var x = point$$1[0], y = point$$1[1];
6472 var startX = start[0], startY = start[1];
6473 var endX = end[0], endY = end[1];
6474
6475 var dxc = x - startX;
6476 var dyc = y - startY;
6477 var dxl = endX - startX;
6478 var dyl = endY - startY;
6479 var cross = dxc * dyl - dyc * dxl;
6480
6481 if (cross !== 0) return false;
6482 else if (Math.abs(dxl) >= Math.abs(dyl)) return dxl > 0 ? startX <= x && x <= endX : endX <= x && x <= startX;
6483 else return dyl > 0 ? startY <= y && y <= endY : endY <= y && y <= startY;
6484}
6485
6486/*
6487 (c) 2013, Vladimir Agafonkin
6488 Simplify.js, a high-performance JS polyline simplification library
6489 mourner.github.io/simplify-js
6490*/
6491
6492// to suit your point format, run search/replace for '.x' and '.y';
6493// for 3D version, see 3d branch (configurability would draw significant performance overhead)
6494
6495// square distance between 2 points
6496function getSqDist$1(p1, p2) {
6497
6498 var dx = p1.x - p2.x,
6499 dy = p1.y - p2.y;
6500
6501 return dx * dx + dy * dy;
6502}
6503
6504// square distance from a point to a segment
6505function getSqSegDist(p, p1, p2) {
6506
6507 var x = p1.x,
6508 y = p1.y,
6509 dx = p2.x - x,
6510 dy = p2.y - y;
6511
6512 if (dx !== 0 || dy !== 0) {
6513
6514 var t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);
6515
6516 if (t > 1) {
6517 x = p2.x;
6518 y = p2.y;
6519
6520 } else if (t > 0) {
6521 x += dx * t;
6522 y += dy * t;
6523 }
6524 }
6525
6526 dx = p.x - x;
6527 dy = p.y - y;
6528
6529 return dx * dx + dy * dy;
6530}
6531// rest of the code doesn't care about point format
6532
6533// basic distance-based simplification
6534function simplifyRadialDist(points$$1, sqTolerance) {
6535
6536 var prevPoint = points$$1[0],
6537 newPoints = [prevPoint],
6538 point$$1;
6539
6540 for (var i = 1, len = points$$1.length; i < len; i++) {
6541 point$$1 = points$$1[i];
6542
6543 if (getSqDist$1(point$$1, prevPoint) > sqTolerance) {
6544 newPoints.push(point$$1);
6545 prevPoint = point$$1;
6546 }
6547 }
6548
6549 if (prevPoint !== point$$1) newPoints.push(point$$1);
6550
6551 return newPoints;
6552}
6553
6554function simplifyDPStep(points$$1, first, last, sqTolerance, simplified) {
6555 var maxSqDist = sqTolerance,
6556 index;
6557
6558 for (var i = first + 1; i < last; i++) {
6559 var sqDist = getSqSegDist(points$$1[i], points$$1[first], points$$1[last]);
6560
6561 if (sqDist > maxSqDist) {
6562 index = i;
6563 maxSqDist = sqDist;
6564 }
6565 }
6566
6567 if (maxSqDist > sqTolerance) {
6568 if (index - first > 1) simplifyDPStep(points$$1, first, index, sqTolerance, simplified);
6569 simplified.push(points$$1[index]);
6570 if (last - index > 1) simplifyDPStep(points$$1, index, last, sqTolerance, simplified);
6571 }
6572}
6573
6574// simplification using Ramer-Douglas-Peucker algorithm
6575function simplifyDouglasPeucker(points$$1, sqTolerance) {
6576 var last = points$$1.length - 1;
6577
6578 var simplified = [points$$1[0]];
6579 simplifyDPStep(points$$1, 0, last, sqTolerance, simplified);
6580 simplified.push(points$$1[last]);
6581
6582 return simplified;
6583}
6584
6585// both algorithms combined for awesome performance
6586function simplify$2(points$$1, tolerance, highestQuality) {
6587
6588 if (points$$1.length <= 2) return points$$1;
6589
6590 var sqTolerance = tolerance !== undefined ? tolerance * tolerance : 1;
6591
6592 points$$1 = highestQuality ? points$$1 : simplifyRadialDist(points$$1, sqTolerance);
6593 points$$1 = simplifyDouglasPeucker(points$$1, sqTolerance);
6594
6595 return points$$1;
6596}
6597
6598/**
6599 * Takes a {@link GeoJSON} object and returns a simplified version. Internally uses
6600 * [simplify-js](http://mourner.github.io/simplify-js/) to perform simplification using the Ramer-Douglas-Peucker algorithm.
6601 *
6602 * @name simplify
6603 * @param {GeoJSON} geojson object to be simplified
6604 * @param {Object} [options={}] Optional parameters
6605 * @param {number} [options.tolerance=1] simplification tolerance
6606 * @param {boolean} [options.highQuality=false] whether or not to spend more time to create a higher-quality simplification with a different algorithm
6607 * @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated (significant performance increase if true)
6608 * @returns {GeoJSON} a simplified GeoJSON
6609 * @example
6610 * var geojson = turf.polygon([[
6611 * [-70.603637, -33.399918],
6612 * [-70.614624, -33.395332],
6613 * [-70.639343, -33.392466],
6614 * [-70.659942, -33.394759],
6615 * [-70.683975, -33.404504],
6616 * [-70.697021, -33.419406],
6617 * [-70.701141, -33.434306],
6618 * [-70.700454, -33.446339],
6619 * [-70.694274, -33.458369],
6620 * [-70.682601, -33.465816],
6621 * [-70.668869, -33.472117],
6622 * [-70.646209, -33.473835],
6623 * [-70.624923, -33.472117],
6624 * [-70.609817, -33.468107],
6625 * [-70.595397, -33.458369],
6626 * [-70.587158, -33.442901],
6627 * [-70.587158, -33.426283],
6628 * [-70.590591, -33.414248],
6629 * [-70.594711, -33.406224],
6630 * [-70.603637, -33.399918]
6631 * ]]);
6632 * var options = {tolerance: 0.01, highQuality: false};
6633 * var simplified = turf.simplify(geojson, options);
6634 *
6635 * //addToMap
6636 * var addToMap = [geojson, simplified]
6637 */
6638function simplify(geojson, options) {
6639 // Optional parameters
6640 options = options || {};
6641 if (!isObject(options)) throw new Error('options is invalid');
6642 var tolerance = options.tolerance !== undefined ? options.tolerance : 1;
6643 var highQuality = options.highQuality || false;
6644 var mutate = options.mutate || false;
6645
6646 if (!geojson) throw new Error('geojson is required');
6647 if (tolerance && tolerance < 0) throw new Error('invalid tolerance');
6648
6649 // Clone geojson to avoid side effects
6650 if (mutate !== true) geojson = clone(geojson);
6651
6652 geomEach(geojson, function (geom) {
6653 simplifyGeom(geom, tolerance, highQuality);
6654 });
6655 return geojson;
6656}
6657
6658/**
6659 * Simplifies a feature's coordinates
6660 *
6661 * @private
6662 * @param {Geometry} geometry to be simplified
6663 * @param {number} [tolerance=1] simplification tolerance
6664 * @param {boolean} [highQuality=false] whether or not to spend more time to create a higher-quality simplification with a different algorithm
6665 * @returns {Geometry} output
6666 */
6667function simplifyGeom(geometry$$1, tolerance, highQuality) {
6668 var type = geometry$$1.type;
6669
6670 // "unsimplyfiable" geometry types
6671 if (type === 'Point' || type === 'MultiPoint') return geometry$$1;
6672
6673 // Remove any extra coordinates
6674 cleanCoords(geometry$$1, true);
6675
6676 var coordinates = geometry$$1.coordinates;
6677 switch (type) {
6678 case 'LineString':
6679 geometry$$1['coordinates'] = simplifyLine(coordinates, tolerance, highQuality);
6680 break;
6681 case 'MultiLineString':
6682 geometry$$1['coordinates'] = coordinates.map(function (lines) {
6683 return simplifyLine(lines, tolerance, highQuality);
6684 });
6685 break;
6686 case 'Polygon':
6687 geometry$$1['coordinates'] = simplifyPolygon(coordinates, tolerance, highQuality);
6688 break;
6689 case 'MultiPolygon':
6690 geometry$$1['coordinates'] = coordinates.map(function (rings) {
6691 return simplifyPolygon(rings, tolerance, highQuality);
6692 });
6693 }
6694 return geometry$$1;
6695}
6696
6697
6698/**
6699 * Simplifies the coordinates of a LineString with simplify-js
6700 *
6701 * @private
6702 * @param {Array<number>} coordinates to be processed
6703 * @param {number} tolerance simplification tolerance
6704 * @param {boolean} highQuality whether or not to spend more time to create a higher-quality
6705 * @returns {Array<Array<number>>} simplified coords
6706 */
6707function simplifyLine(coordinates, tolerance, highQuality) {
6708 return simplify$2(coordinates.map(function (coord) {
6709 return {x: coord[0], y: coord[1], z: coord[2]};
6710 }), tolerance, highQuality).map(function (coords) {
6711 return (coords.z) ? [coords.x, coords.y, coords.z] : [coords.x, coords.y];
6712 });
6713}
6714
6715
6716/**
6717 * Simplifies the coordinates of a Polygon with simplify-js
6718 *
6719 * @private
6720 * @param {Array<number>} coordinates to be processed
6721 * @param {number} tolerance simplification tolerance
6722 * @param {boolean} highQuality whether or not to spend more time to create a higher-quality
6723 * @returns {Array<Array<Array<number>>>} simplified coords
6724 */
6725function simplifyPolygon(coordinates, tolerance, highQuality) {
6726 return coordinates.map(function (ring) {
6727 var pts = ring.map(function (coord) {
6728 return {x: coord[0], y: coord[1]};
6729 });
6730 if (pts.length < 4) {
6731 throw new Error('invalid polygon');
6732 }
6733 var simpleRing = simplify$2(pts, tolerance, highQuality).map(function (coords) {
6734 return [coords.x, coords.y];
6735 });
6736 //remove 1 percent of tolerance until enough points to make a triangle
6737 while (!checkValidity(simpleRing)) {
6738 tolerance -= tolerance * 0.01;
6739 simpleRing = simplify$2(pts, tolerance, highQuality).map(function (coords) {
6740 return [coords.x, coords.y];
6741 });
6742 }
6743 if (
6744 (simpleRing[simpleRing.length - 1][0] !== simpleRing[0][0]) ||
6745 (simpleRing[simpleRing.length - 1][1] !== simpleRing[0][1])) {
6746 simpleRing.push(simpleRing[0]);
6747 }
6748 return simpleRing;
6749 });
6750}
6751
6752
6753/**
6754 * Returns true if ring has at least 3 coordinates and its first coordinate is the same as its last
6755 *
6756 * @private
6757 * @param {Array<number>} ring coordinates to be checked
6758 * @returns {boolean} true if valid
6759 */
6760function checkValidity(ring) {
6761 if (ring.length < 3) return false;
6762 //if the last point is the same as the first, it's not a triangle
6763 return !(ring.length === 3 && ((ring[2][0] === ring[0][0]) && (ring[2][1] === ring[0][1])));
6764}
6765
6766/* eslint-disable */
6767
6768 /**
6769 * BezierSpline
6770 * https://github.com/leszekr/bezier-spline-js
6771 *
6772 * @private
6773 * @copyright
6774 * Copyright (c) 2013 Leszek Rybicki
6775 *
6776 * Permission is hereby granted, free of charge, to any person obtaining a copy
6777 * of this software and associated documentation files (the "Software"), to deal
6778 * in the Software without restriction, including without limitation the rights
6779 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6780 * copies of the Software, and to permit persons to whom the Software is
6781 * furnished to do so, subject to the following conditions:
6782 *
6783 * The above copyright notice and this permission notice shall be included in all
6784 * copies or substantial portions of the Software.
6785 *
6786 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6787 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6788 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6789 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6790 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6791 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
6792 * SOFTWARE.
6793 */
6794var Spline = function (options) {
6795 this.points = options.points || [];
6796 this.duration = options.duration || 10000;
6797 this.sharpness = options.sharpness || 0.85;
6798 this.centers = [];
6799 this.controls = [];
6800 this.stepLength = options.stepLength || 60;
6801 this.length = this.points.length;
6802 this.delay = 0;
6803 // this is to ensure compatibility with the 2d version
6804 for (var i = 0; i < this.length; i++) this.points[i].z = this.points[i].z || 0;
6805 for (var i = 0; i < this.length - 1; i++) {
6806 var p1 = this.points[i];
6807 var p2 = this.points[i + 1];
6808 this.centers.push({
6809 x: (p1.x + p2.x) / 2,
6810 y: (p1.y + p2.y) / 2,
6811 z: (p1.z + p2.z) / 2
6812 });
6813 }
6814 this.controls.push([this.points[0], this.points[0]]);
6815 for (var i = 0; i < this.centers.length - 1; i++) {
6816 var p1 = this.centers[i];
6817 var p2 = this.centers[i + 1];
6818 var dx = this.points[i + 1].x - (this.centers[i].x + this.centers[i + 1].x) / 2;
6819 var dy = this.points[i + 1].y - (this.centers[i].y + this.centers[i + 1].y) / 2;
6820 var dz = this.points[i + 1].z - (this.centers[i].y + this.centers[i + 1].z) / 2;
6821 this.controls.push([{
6822 x: (1.0 - this.sharpness) * this.points[i + 1].x + this.sharpness * (this.centers[i].x + dx),
6823 y: (1.0 - this.sharpness) * this.points[i + 1].y + this.sharpness * (this.centers[i].y + dy),
6824 z: (1.0 - this.sharpness) * this.points[i + 1].z + this.sharpness * (this.centers[i].z + dz)},
6825 {
6826 x: (1.0 - this.sharpness) * this.points[i + 1].x + this.sharpness * (this.centers[i + 1].x + dx),
6827 y: (1.0 - this.sharpness) * this.points[i + 1].y + this.sharpness * (this.centers[i + 1].y + dy),
6828 z: (1.0 - this.sharpness) * this.points[i + 1].z + this.sharpness * (this.centers[i + 1].z + dz)}]);
6829 }
6830 this.controls.push([this.points[this.length - 1], this.points[this.length - 1]]);
6831 this.steps = this.cacheSteps(this.stepLength);
6832 return this;
6833};
6834
6835 /*
6836 Caches an array of equidistant (more or less) points on the curve.
6837 */
6838Spline.prototype.cacheSteps = function (mindist) {
6839 var steps = [];
6840 var laststep = this.pos(0);
6841 steps.push(0);
6842 for (var t = 0; t < this.duration; t += 10) {
6843 var step = this.pos(t);
6844 var dist = Math.sqrt((step.x - laststep.x) * (step.x - laststep.x) + (step.y - laststep.y) * (step.y - laststep.y) + (step.z - laststep.z) * (step.z - laststep.z));
6845 if (dist > mindist) {
6846 steps.push(t);
6847 laststep = step;
6848 }
6849 }
6850 return steps;
6851};
6852
6853 /*
6854 returns angle and speed in the given point in the curve
6855 */
6856Spline.prototype.vector = function (t) {
6857 var p1 = this.pos(t + 10);
6858 var p2 = this.pos(t - 10);
6859 return {
6860 angle:180 * Math.atan2(p1.y - p2.y, p1.x - p2.x) / 3.14,
6861 speed:Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y) + (p2.z - p1.z) * (p2.z - p1.z))
6862 };
6863};
6864
6865 /*
6866 Gets the position of the point, given time.
6867
6868 WARNING: The speed is not constant. The time it takes between control points is constant.
6869
6870 For constant speed, use Spline.steps[i];
6871 */
6872Spline.prototype.pos = function (time) {
6873
6874 function bezier(t, p1, c1, c2, p2) {
6875 var B = function (t) {
6876 var t2 = t * t, t3 = t2 * t;
6877 return [(t3), (3 * t2 * (1 - t)), (3 * t * (1 - t) * (1 - t)), ((1 - t) * (1 - t) * (1 - t))];
6878 };
6879 var b = B(t);
6880 var pos = {
6881 x : p2.x * b[0] + c2.x * b[1] + c1.x * b[2] + p1.x * b[3],
6882 y : p2.y * b[0] + c2.y * b[1] + c1.y * b[2] + p1.y * b[3],
6883 z : p2.z * b[0] + c2.z * b[1] + c1.z * b[2] + p1.z * b[3]
6884 };
6885 return pos;
6886 }
6887 var t = time - this.delay;
6888 if (t < 0) t = 0;
6889 if (t > this.duration) t = this.duration - 1;
6890 //t = t-this.delay;
6891 var t2 = (t) / this.duration;
6892 if (t2 >= 1) return this.points[this.length - 1];
6893
6894 var n = Math.floor((this.points.length - 1) * t2);
6895 var t1 = (this.length - 1) * t2 - n;
6896 return bezier(t1, this.points[n], this.controls[n][1], this.controls[n + 1][0], this.points[n + 1]);
6897};
6898
6899/**
6900 * Takes a {@link LineString|line} and returns a curved version
6901 * by applying a [Bezier spline](http://en.wikipedia.org/wiki/B%C3%A9zier_spline)
6902 * algorithm.
6903 *
6904 * The bezier spline implementation is by [Leszek Rybicki](http://leszek.rybicki.cc/).
6905 *
6906 * @name bezierSpline
6907 * @param {Feature<LineString>} line input LineString
6908 * @param {Object} [options={}] Optional parameters
6909 * @param {number} [options.resolution=10000] time in milliseconds between points
6910 * @param {number} [options.sharpness=0.85] a measure of how curvy the path should be between splines
6911 * @returns {Feature<LineString>} curved line
6912 * @example
6913 * var line = turf.lineString([
6914 * [-76.091308, 18.427501],
6915 * [-76.695556, 18.729501],
6916 * [-76.552734, 19.40443],
6917 * [-74.61914, 19.134789],
6918 * [-73.652343, 20.07657],
6919 * [-73.157958, 20.210656]
6920 * ]);
6921 *
6922 * var curved = turf.bezierSpline(line);
6923 *
6924 * //addToMap
6925 * var addToMap = [line, curved]
6926 * curved.properties = { stroke: '#0F0' };
6927 */
6928function bezier(line, options) {
6929 // Optional params
6930 options = options || {};
6931 if (!isObject(options)) throw new Error('options is invalid');
6932 var resolution = options.resolution || 10000;
6933 var sharpness = options.sharpness || 0.85;
6934
6935 // validation
6936 if (!line) throw new Error('line is required');
6937 if (!isNumber(resolution)) throw new Error('resolution must be an number');
6938 if (!isNumber(sharpness)) throw new Error('sharpness must be an number');
6939
6940 var coords = [];
6941 var spline = new Spline({
6942 points: getGeom(line).coordinates.map(function (pt) {
6943 return {x: pt[0], y: pt[1]};
6944 }),
6945 duration: resolution,
6946 sharpness: sharpness
6947 });
6948
6949 for (var i = 0; i < spline.duration; i += 10) {
6950 var pos = spline.pos(i);
6951 if (Math.floor(i / 100) % 2 === 0) {
6952 coords.push([pos.x, pos.y]);
6953 }
6954 }
6955
6956 return lineString(coords, line.properties);
6957}
6958
6959/**
6960 * Takes a set of {@link Point|points} and a set of {@link Polygon|polygons} and performs a spatial join.
6961 *
6962 * @name tag
6963 * @param {FeatureCollection<Point>} points input points
6964 * @param {FeatureCollection<Polygon>} polygons input polygons
6965 * @param {string} field property in `polygons` to add to joined {<Point>} features
6966 * @param {string} outField property in `points` in which to store joined property from `polygons`
6967 * @returns {FeatureCollection<Point>} points with `containingPolyId` property containing values from `polyId`
6968 * @example
6969 * var pt1 = turf.point([-77, 44]);
6970 * var pt2 = turf.point([-77, 38]);
6971 * var poly1 = turf.polygon([[
6972 * [-81, 41],
6973 * [-81, 47],
6974 * [-72, 47],
6975 * [-72, 41],
6976 * [-81, 41]
6977 * ]], {pop: 3000});
6978 * var poly2 = turf.polygon([[
6979 * [-81, 35],
6980 * [-81, 41],
6981 * [-72, 41],
6982 * [-72, 35],
6983 * [-81, 35]
6984 * ]], {pop: 1000});
6985 *
6986 * var points = turf.featureCollection([pt1, pt2]);
6987 * var polygons = turf.featureCollection([poly1, poly2]);
6988 *
6989 * var tagged = turf.tag(points, polygons, 'pop', 'population');
6990 *
6991 * //addToMap
6992 * var addToMap = [tagged, polygons]
6993 */
6994function tag(points, polygons, field, outField) {
6995 // prevent mutations
6996 points = clone(points);
6997 polygons = clone(polygons);
6998 featureEach(points, function (pt) {
6999 if (!pt.properties) pt.properties = {};
7000 featureEach(polygons, function (poly) {
7001 if (pt.properties[outField] === undefined) {
7002 if (booleanPointInPolygon(pt, poly)) pt.properties[outField] = poly.properties[field];
7003 }
7004 });
7005 });
7006 return points;
7007}
7008
7009// http://stackoverflow.com/questions/11935175/sampling-a-random-subset-from-an-array
7010/**
7011 * Takes a {@link FeatureCollection} and returns a FeatureCollection with given number of {@link Feature|features} at random.
7012 *
7013 * @name sample
7014 * @param {FeatureCollection} featurecollection set of input features
7015 * @param {number} num number of features to select
7016 * @returns {FeatureCollection} a FeatureCollection with `n` features
7017 * @example
7018 * var points = turf.randomPoint(100, {bbox: [-80, 30, -60, 60]});
7019 *
7020 * var sample = turf.sample(points, 5);
7021 *
7022 * //addToMap
7023 * var addToMap = [points, sample]
7024 * turf.featureEach(sample, function (currentFeature) {
7025 * currentFeature.properties['marker-size'] = 'large';
7026 * currentFeature.properties['marker-color'] = '#000';
7027 * });
7028 */
7029function sample(featurecollection, num) {
7030 if (!featurecollection) throw new Error('featurecollection is required');
7031 if (num === null || num === undefined) throw new Error('num is required');
7032 if (typeof num !== 'number') throw new Error('num must be a number');
7033
7034 var outFC = featureCollection(getRandomSubarray(featurecollection.features, num));
7035 return outFC;
7036}
7037
7038function getRandomSubarray(arr, size) {
7039 var shuffled = arr.slice(0), i = arr.length, min = i - size, temp, index;
7040 while (i-- > min) {
7041 index = Math.floor((i + 1) * Math.random());
7042 temp = shuffled[index];
7043 shuffled[index] = shuffled[i];
7044 shuffled[i] = temp;
7045 }
7046 return shuffled.slice(min);
7047}
7048
7049/**
7050 * Takes a bbox and returns an equivalent {@link Polygon|polygon}.
7051 *
7052 * @name bboxPolygon
7053 * @param {BBox} bbox extent in [minX, minY, maxX, maxY] order
7054 * @returns {Feature<Polygon>} a Polygon representation of the bounding box
7055 * @example
7056 * var bbox = [0, 0, 10, 10];
7057 *
7058 * var poly = turf.bboxPolygon(bbox);
7059 *
7060 * //addToMap
7061 * var addToMap = [poly]
7062 */
7063function bboxPolygon(bbox) {
7064 validateBBox(bbox);
7065 // Convert BBox positions to Numbers
7066 // No performance loss for including Number()
7067 // https://github.com/Turfjs/turf/issues/1119
7068 var west = Number(bbox[0]);
7069 var south = Number(bbox[1]);
7070 var east = Number(bbox[2]);
7071 var north = Number(bbox[3]);
7072
7073 if (bbox.length === 6) throw new Error('@turf/bbox-polygon does not support BBox with 6 positions');
7074
7075 var lowLeft = [west, south];
7076 var topLeft = [west, north];
7077 var topRight = [east, north];
7078 var lowRight = [east, south];
7079
7080 return polygon([[
7081 lowLeft,
7082 lowRight,
7083 topRight,
7084 topLeft,
7085 lowLeft
7086 ]]);
7087}
7088
7089/**
7090 * Takes any number of features and returns a rectangular {@link Polygon} that encompasses all vertices.
7091 *
7092 * @name envelope
7093 * @param {GeoJSON} geojson input features
7094 * @returns {Feature<Polygon>} a rectangular Polygon feature that encompasses all vertices
7095 * @example
7096 * var features = turf.featureCollection([
7097 * turf.point([-75.343, 39.984], {"name": "Location A"}),
7098 * turf.point([-75.833, 39.284], {"name": "Location B"}),
7099 * turf.point([-75.534, 39.123], {"name": "Location C"})
7100 * ]);
7101 *
7102 * var enveloped = turf.envelope(features);
7103 *
7104 * //addToMap
7105 * var addToMap = [features, enveloped];
7106 */
7107function envelope(geojson) {
7108 return bboxPolygon(bbox(geojson));
7109}
7110
7111/**
7112 * Takes a bounding box and calculates the minimum square bounding box that
7113 * would contain the input.
7114 *
7115 * @name square
7116 * @param {BBox} bbox extent in [west, south, east, north] order
7117 * @returns {BBox} a square surrounding `bbox`
7118 * @example
7119 * var bbox = [-20, -20, -15, 0];
7120 * var squared = turf.square(bbox);
7121 *
7122 * //addToMap
7123 * var addToMap = [turf.bboxPolygon(bbox), turf.bboxPolygon(squared)]
7124 */
7125function square(bbox) {
7126 var west = bbox[0];
7127 var south = bbox[1];
7128 var east = bbox[2];
7129 var north = bbox[3];
7130
7131 var horizontalDistance = distance(bbox.slice(0, 2), [east, south]);
7132 var verticalDistance = distance(bbox.slice(0, 2), [west, north]);
7133 if (horizontalDistance >= verticalDistance) {
7134 var verticalMidpoint = (south + north) / 2;
7135 return [
7136 west,
7137 verticalMidpoint - ((east - west) / 2),
7138 east,
7139 verticalMidpoint + ((east - west) / 2)
7140 ];
7141 } else {
7142 var horizontalMidpoint = (west + east) / 2;
7143 return [
7144 horizontalMidpoint - ((north - south) / 2),
7145 south,
7146 horizontalMidpoint + ((north - south) / 2),
7147 north
7148 ];
7149 }
7150}
7151
7152//http://en.wikipedia.org/wiki/Haversine_formula
7153//http://www.movable-type.co.uk/scripts/latlong.html
7154/**
7155 * Takes a {@link Point} and calculates the location of a destination point given a distance in degrees, radians, miles, or kilometers; and bearing in degrees. This uses the [Haversine formula](http://en.wikipedia.org/wiki/Haversine_formula) to account for global curvature.
7156 *
7157 * @name destination
7158 * @param {Coord} origin starting point
7159 * @param {number} distance distance from the origin point
7160 * @param {number} bearing ranging from -180 to 180
7161 * @param {Object} [options={}] Optional parameters
7162 * @param {string} [options.units='kilometers'] miles, kilometers, degrees, or radians
7163 * @param {Object} [options.properties={}] Translate properties to Point
7164 * @returns {Feature<Point>} destination point
7165 * @example
7166 * var point = turf.point([-75.343, 39.984]);
7167 * var distance = 50;
7168 * var bearing = 90;
7169 * var options = {units: 'miles'};
7170 *
7171 * var destination = turf.destination(point, distance, bearing, options);
7172 *
7173 * //addToMap
7174 * var addToMap = [point, destination]
7175 * destination.properties['marker-color'] = '#f00';
7176 * point.properties['marker-color'] = '#0f0';
7177 */
7178function destination(origin, distance, bearing, options) {
7179 // Optional parameters
7180 options = options || {};
7181 if (!isObject(options)) throw new Error('options is invalid');
7182 var units = options.units;
7183 var properties = options.properties;
7184
7185 // Handle input
7186 var coordinates1 = getCoord(origin);
7187 var longitude1 = degreesToRadians(coordinates1[0]);
7188 var latitude1 = degreesToRadians(coordinates1[1]);
7189 var bearing_rad = degreesToRadians(bearing);
7190 var radians = lengthToRadians(distance, units);
7191
7192 // Main
7193 var latitude2 = Math.asin(Math.sin(latitude1) * Math.cos(radians) +
7194 Math.cos(latitude1) * Math.sin(radians) * Math.cos(bearing_rad));
7195 var longitude2 = longitude1 + Math.atan2(Math.sin(bearing_rad) * Math.sin(radians) * Math.cos(latitude1),
7196 Math.cos(radians) - Math.sin(latitude1) * Math.sin(latitude2));
7197 var lng = radiansToDegrees(longitude2);
7198 var lat = radiansToDegrees(latitude2);
7199
7200 return point([lng, lat], properties);
7201}
7202
7203/**
7204 * Takes a {@link Point} and calculates the circle polygon given a radius in degrees, radians, miles, or kilometers; and steps for precision.
7205 *
7206 * @name circle
7207 * @param {Feature<Point>|number[]} center center point
7208 * @param {number} radius radius of the circle
7209 * @param {Object} [options={}] Optional parameters
7210 * @param {number} [options.steps=64] number of steps
7211 * @param {string} [options.units='kilometers'] miles, kilometers, degrees, or radians
7212 * @param {Object} [options.properties={}] properties
7213 * @returns {Feature<Polygon>} circle polygon
7214 * @example
7215 * var center = [-75.343, 39.984];
7216 * var radius = 5;
7217 * var options = {steps: 10, units: 'kilometers', properties: {foo: 'bar'}};
7218 * var circle = turf.circle(center, radius, options);
7219 *
7220 * //addToMap
7221 * var addToMap = [turf.point(center), circle]
7222 */
7223function circle(center, radius, options) {
7224 // Optional params
7225 options = options || {};
7226 var steps = options.steps || 64;
7227 var properties = options.properties;
7228
7229 // validation
7230 if (!center) throw new Error('center is required');
7231 if (!radius) throw new Error('radius is required');
7232 if (typeof options !== 'object') throw new Error('options must be an object');
7233 if (typeof steps !== 'number') throw new Error('steps must be a number');
7234
7235 // default params
7236 steps = steps || 64;
7237 properties = properties || center.properties || {};
7238
7239 var coordinates = [];
7240 for (var i = 0; i < steps; i++) {
7241 coordinates.push(destination(center, radius, i * -360 / steps, options).geometry.coordinates);
7242 }
7243 coordinates.push(coordinates[0]);
7244
7245 return polygon([coordinates], properties);
7246}
7247
7248//http://en.wikipedia.org/wiki/Haversine_formula
7249//http://www.movable-type.co.uk/scripts/latlong.html
7250
7251/**
7252 * Takes two {@link Point|points} and finds the geographic bearing between them,
7253 * i.e. the angle measured in degrees from the north line (0 degrees)
7254 *
7255 * @name bearing
7256 * @param {Coord} start starting Point
7257 * @param {Coord} end ending Point
7258 * @param {Object} [options={}] Optional parameters
7259 * @param {boolean} [options.final=false] calculates the final bearing if true
7260 * @returns {number} bearing in decimal degrees, between -180 and 180 degrees (positive clockwise)
7261 * @example
7262 * var point1 = turf.point([-75.343, 39.984]);
7263 * var point2 = turf.point([-75.534, 39.123]);
7264 *
7265 * var bearing = turf.bearing(point1, point2);
7266 *
7267 * //addToMap
7268 * var addToMap = [point1, point2]
7269 * point1.properties['marker-color'] = '#f00'
7270 * point2.properties['marker-color'] = '#0f0'
7271 * point1.properties.bearing = bearing
7272 */
7273function bearing(start, end, options) {
7274 // Optional parameters
7275 options = options || {};
7276 if (!isObject(options)) throw new Error('options is invalid');
7277 var final = options.final;
7278
7279 // Reverse calculation
7280 if (final === true) return calculateFinalBearing(start, end);
7281
7282 var coordinates1 = getCoord(start);
7283 var coordinates2 = getCoord(end);
7284
7285 var lon1 = degreesToRadians(coordinates1[0]);
7286 var lon2 = degreesToRadians(coordinates2[0]);
7287 var lat1 = degreesToRadians(coordinates1[1]);
7288 var lat2 = degreesToRadians(coordinates2[1]);
7289 var a = Math.sin(lon2 - lon1) * Math.cos(lat2);
7290 var b = Math.cos(lat1) * Math.sin(lat2) -
7291 Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1);
7292
7293 return radiansToDegrees(Math.atan2(a, b));
7294}
7295
7296/**
7297 * Calculates Final Bearing
7298 *
7299 * @private
7300 * @param {Coord} start starting Point
7301 * @param {Coord} end ending Point
7302 * @returns {number} bearing
7303 */
7304function calculateFinalBearing(start, end) {
7305 // Swap start & end
7306 var bear = bearing(end, start);
7307 bear = (bear + 180) % 360;
7308 return bear;
7309}
7310
7311/**
7312 * Takes two {@link Point|points} and returns a point midway between them.
7313 * The midpoint is calculated geodesically, meaning the curvature of the earth is taken into account.
7314 *
7315 * @name midpoint
7316 * @param {Coord} point1 first point
7317 * @param {Coord} point2 second point
7318 * @returns {Feature<Point>} a point midway between `pt1` and `pt2`
7319 * @example
7320 * var point1 = turf.point([144.834823, -37.771257]);
7321 * var point2 = turf.point([145.14244, -37.830937]);
7322 *
7323 * var midpoint = turf.midpoint(point1, point2);
7324 *
7325 * //addToMap
7326 * var addToMap = [point1, point2, midpoint];
7327 * midpoint.properties['marker-color'] = '#f00';
7328 */
7329function midpoint(point1, point2) {
7330 var dist = distance(point1, point2);
7331 var heading = bearing(point1, point2);
7332 var midpoint = destination(point1, dist / 2, heading);
7333
7334 return midpoint;
7335}
7336
7337/**
7338 * Takes a {@link Feature} or {@link FeatureCollection} and returns the absolute center point of all features.
7339 *
7340 * @name center
7341 * @param {GeoJSON} geojson GeoJSON to be centered
7342 * @param {Object} [options={}] Optional parameters
7343 * @param {Object} [options.properties={}] an Object that is used as the {@link Feature}'s properties
7344 * @returns {Feature<Point>} a Point feature at the absolute center point of all input features
7345 * @example
7346 * var features = turf.featureCollection([
7347 * turf.point( [-97.522259, 35.4691]),
7348 * turf.point( [-97.502754, 35.463455]),
7349 * turf.point( [-97.508269, 35.463245])
7350 * ]);
7351 *
7352 * var center = turf.center(features);
7353 *
7354 * //addToMap
7355 * var addToMap = [features, center]
7356 * center.properties['marker-size'] = 'large';
7357 * center.properties['marker-color'] = '#000';
7358 */
7359function center(geojson, options) {
7360 // Optional parameters
7361 options = options || {};
7362 if (!isObject(options)) throw new Error('options is invalid');
7363 var properties = options.properties;
7364
7365 // Input validation
7366 if (!geojson) throw new Error('geojson is required');
7367
7368 var ext = bbox(geojson);
7369 var x = (ext[0] + ext[2]) / 2;
7370 var y = (ext[1] + ext[3]) / 2;
7371 return point([x, y], properties);
7372}
7373
7374/**
7375 * Takes one or more features and calculates the centroid using the mean of all vertices.
7376 * This lessens the effect of small islands and artifacts when calculating the centroid of a set of polygons.
7377 *
7378 * @name centroid
7379 * @param {GeoJSON} geojson GeoJSON to be centered
7380 * @param {Object} [properties={}] an Object that is used as the {@link Feature}'s properties
7381 * @returns {Feature<Point>} the centroid of the input features
7382 * @example
7383 * var polygon = turf.polygon([[[-81, 41], [-88, 36], [-84, 31], [-80, 33], [-77, 39], [-81, 41]]]);
7384 *
7385 * var centroid = turf.centroid(polygon);
7386 *
7387 * //addToMap
7388 * var addToMap = [polygon, centroid]
7389 */
7390function centroid(geojson, properties) {
7391 var xSum = 0;
7392 var ySum = 0;
7393 var len = 0;
7394 coordEach(geojson, function (coord) {
7395 xSum += coord[0];
7396 ySum += coord[1];
7397 len++;
7398 }, true);
7399 return point([xSum / len, ySum / len], properties);
7400}
7401
7402/**
7403 * Takes any {@link Feature} or a {@link FeatureCollection} and returns its [center of mass](https://en.wikipedia.org/wiki/Center_of_mass) using this formula: [Centroid of Polygon](https://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon).
7404 *
7405 * @name centerOfMass
7406 * @param {GeoJSON} geojson GeoJSON to be centered
7407 * @param {Object} [properties={}] an Object that is used as the {@link Feature}'s properties
7408 * @returns {Feature<Point>} the center of mass
7409 * @example
7410 * var polygon = turf.polygon([[[-81, 41], [-88, 36], [-84, 31], [-80, 33], [-77, 39], [-81, 41]]]);
7411 *
7412 * var center = turf.centerOfMass(polygon);
7413 *
7414 * //addToMap
7415 * var addToMap = [polygon, center]
7416 */
7417function centerOfMass(geojson, properties) {
7418 switch (getType(geojson)) {
7419 case 'Point':
7420 return geojson;
7421 case 'Polygon':
7422 var coords = [];
7423 coordEach(geojson, function (coord) {
7424 coords.push(coord);
7425 });
7426
7427 // First, we neutralize the feature (set it around coordinates [0,0]) to prevent rounding errors
7428 // We take any point to translate all the points around 0
7429 var centre = centroid(geojson, properties);
7430 var translation = centre.geometry.coordinates;
7431 var sx = 0;
7432 var sy = 0;
7433 var sArea = 0;
7434 var i, pi, pj, xi, xj, yi, yj, a;
7435
7436 var neutralizedPoints = coords.map(function (point$$1) {
7437 return [
7438 point$$1[0] - translation[0],
7439 point$$1[1] - translation[1]
7440 ];
7441 });
7442
7443 for (i = 0; i < coords.length - 1; i++) {
7444 // pi is the current point
7445 pi = neutralizedPoints[i];
7446 xi = pi[0];
7447 yi = pi[1];
7448
7449 // pj is the next point (pi+1)
7450 pj = neutralizedPoints[i + 1];
7451 xj = pj[0];
7452 yj = pj[1];
7453
7454 // a is the common factor to compute the signed area and the final coordinates
7455 a = xi * yj - xj * yi;
7456
7457 // sArea is the sum used to compute the signed area
7458 sArea += a;
7459
7460 // sx and sy are the sums used to compute the final coordinates
7461 sx += (xi + xj) * a;
7462 sy += (yi + yj) * a;
7463 }
7464
7465 // Shape has no area: fallback on turf.centroid
7466 if (sArea === 0) {
7467 return centre;
7468 } else {
7469 // Compute the signed area, and factorize 1/6A
7470 var area = sArea * 0.5;
7471 var areaFactor = 1 / (6 * area);
7472
7473 // Compute the final coordinates, adding back the values that have been neutralized
7474 return point([
7475 translation[0] + areaFactor * sx,
7476 translation[1] + areaFactor * sy
7477 ], properties);
7478 }
7479 default:
7480 // Not a polygon: Compute the convex hull and work with that
7481 var hull = convex(geojson);
7482
7483 if (hull) return centerOfMass(hull, properties);
7484 // Hull is empty: fallback on the centroid
7485 else return centroid(geojson, properties);
7486 }
7487}
7488
7489/**
7490 * Combines a {@link FeatureCollection} of {@link Point}, {@link LineString}, or {@link Polygon} features
7491 * into {@link MultiPoint}, {@link MultiLineString}, or {@link MultiPolygon} features.
7492 *
7493 * @name combine
7494 * @param {FeatureCollection<Point|LineString|Polygon>} fc a FeatureCollection of any type
7495 * @returns {FeatureCollection<MultiPoint|MultiLineString|MultiPolygon>} a FeatureCollection of corresponding type to input
7496 * @example
7497 * var fc = turf.featureCollection([
7498 * turf.point([19.026432, 47.49134]),
7499 * turf.point([19.074497, 47.509548])
7500 * ]);
7501 *
7502 * var combined = turf.combine(fc);
7503 *
7504 * //addToMap
7505 * var addToMap = [combined]
7506 */
7507function combine(fc) {
7508 var groups = {
7509 MultiPoint: {coordinates: [], properties: []},
7510 MultiLineString: {coordinates: [], properties: []},
7511 MultiPolygon: {coordinates: [], properties: []}
7512 };
7513
7514 var multiMapping = Object.keys(groups).reduce(function (memo, item) {
7515 memo[item.replace('Multi', '')] = item;
7516 return memo;
7517 }, {});
7518
7519 function addToGroup(feature$$1, key, multi) {
7520 if (!multi) {
7521 groups[key].coordinates.push(feature$$1.geometry.coordinates);
7522 } else {
7523 groups[key].coordinates = groups[key].coordinates.concat(feature$$1.geometry.coordinates);
7524 }
7525 groups[key].properties.push(feature$$1.properties);
7526 }
7527
7528 featureEach(fc, function (feature$$1) {
7529 if (!feature$$1.geometry) return;
7530 if (groups[feature$$1.geometry.type]) {
7531 addToGroup(feature$$1, feature$$1.geometry.type, true);
7532 } else if (multiMapping[feature$$1.geometry.type]) {
7533 addToGroup(feature$$1, multiMapping[feature$$1.geometry.type], false);
7534 }
7535 });
7536
7537 return featureCollection(Object.keys(groups)
7538 .filter(function (key) {
7539 return groups[key].coordinates.length;
7540 })
7541 .sort()
7542 .map(function (key) {
7543 var geometry$$1 = { type: key, coordinates: groups[key].coordinates };
7544 var properties = { collectedProperties: groups[key].properties };
7545 return feature(geometry$$1, properties);
7546 }));
7547}
7548
7549/**
7550 * Takes a feature or set of features and returns all positions as {@link Point|points}.
7551 *
7552 * @name explode
7553 * @param {GeoJSON} geojson input features
7554 * @returns {FeatureCollection<point>} points representing the exploded input features
7555 * @throws {Error} if it encounters an unknown geometry type
7556 * @example
7557 * var polygon = turf.polygon([[[-81, 41], [-88, 36], [-84, 31], [-80, 33], [-77, 39], [-81, 41]]]);
7558 *
7559 * var explode = turf.explode(polygon);
7560 *
7561 * //addToMap
7562 * var addToMap = [polygon, explode]
7563 */
7564function explode(geojson) {
7565 var points$$1 = [];
7566 if (geojson.type === 'FeatureCollection') {
7567 featureEach(geojson, function (feature$$1) {
7568 coordEach(feature$$1, function (coord) {
7569 points$$1.push(point(coord, feature$$1.properties));
7570 });
7571 });
7572 } else {
7573 coordEach(geojson, function (coord) {
7574 points$$1.push(point(coord, geojson.properties));
7575 });
7576 }
7577 return featureCollection(points$$1);
7578}
7579
7580var earcut_1 = earcut;
7581var default_1$2 = earcut;
7582
7583function earcut(data, holeIndices, dim) {
7584
7585 dim = dim || 2;
7586
7587 var hasHoles = holeIndices && holeIndices.length,
7588 outerLen = hasHoles ? holeIndices[0] * dim : data.length,
7589 outerNode = linkedList(data, 0, outerLen, dim, true),
7590 triangles = [];
7591
7592 if (!outerNode) return triangles;
7593
7594 var minX, minY, maxX, maxY, x, y, invSize;
7595
7596 if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
7597
7598 // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
7599 if (data.length > 80 * dim) {
7600 minX = maxX = data[0];
7601 minY = maxY = data[1];
7602
7603 for (var i = dim; i < outerLen; i += dim) {
7604 x = data[i];
7605 y = data[i + 1];
7606 if (x < minX) minX = x;
7607 if (y < minY) minY = y;
7608 if (x > maxX) maxX = x;
7609 if (y > maxY) maxY = y;
7610 }
7611
7612 // minX, minY and invSize are later used to transform coords into integers for z-order calculation
7613 invSize = Math.max(maxX - minX, maxY - minY);
7614 invSize = invSize !== 0 ? 1 / invSize : 0;
7615 }
7616
7617 earcutLinked(outerNode, triangles, dim, minX, minY, invSize);
7618
7619 return triangles;
7620}
7621
7622// create a circular doubly linked list from polygon points in the specified winding order
7623function linkedList(data, start, end, dim, clockwise) {
7624 var i, last;
7625
7626 if (clockwise === (signedArea(data, start, end, dim) > 0)) {
7627 for (i = start; i < end; i += dim) last = insertNode$1(i, data[i], data[i + 1], last);
7628 } else {
7629 for (i = end - dim; i >= start; i -= dim) last = insertNode$1(i, data[i], data[i + 1], last);
7630 }
7631
7632 if (last && equals$1(last, last.next)) {
7633 removeNode(last);
7634 last = last.next;
7635 }
7636
7637 return last;
7638}
7639
7640// eliminate colinear or duplicate points
7641function filterPoints(start, end) {
7642 if (!start) return start;
7643 if (!end) end = start;
7644
7645 var p = start,
7646 again;
7647 do {
7648 again = false;
7649
7650 if (!p.steiner && (equals$1(p, p.next) || area(p.prev, p, p.next) === 0)) {
7651 removeNode(p);
7652 p = end = p.prev;
7653 if (p === p.next) break;
7654 again = true;
7655
7656 } else {
7657 p = p.next;
7658 }
7659 } while (again || p !== end);
7660
7661 return end;
7662}
7663
7664// main ear slicing loop which triangulates a polygon (given as a linked list)
7665function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
7666 if (!ear) return;
7667
7668 // interlink polygon nodes in z-order
7669 if (!pass && invSize) indexCurve(ear, minX, minY, invSize);
7670
7671 var stop = ear,
7672 prev, next;
7673
7674 // iterate through ears, slicing them one by one
7675 while (ear.prev !== ear.next) {
7676 prev = ear.prev;
7677 next = ear.next;
7678
7679 if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {
7680 // cut off the triangle
7681 triangles.push(prev.i / dim);
7682 triangles.push(ear.i / dim);
7683 triangles.push(next.i / dim);
7684
7685 removeNode(ear);
7686
7687 // skipping the next vertice leads to less sliver triangles
7688 ear = next.next;
7689 stop = next.next;
7690
7691 continue;
7692 }
7693
7694 ear = next;
7695
7696 // if we looped through the whole remaining polygon and can't find any more ears
7697 if (ear === stop) {
7698 // try filtering points and slicing again
7699 if (!pass) {
7700 earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1);
7701
7702 // if this didn't work, try curing all small self-intersections locally
7703 } else if (pass === 1) {
7704 ear = cureLocalIntersections(ear, triangles, dim);
7705 earcutLinked(ear, triangles, dim, minX, minY, invSize, 2);
7706
7707 // as a last resort, try splitting the remaining polygon into two
7708 } else if (pass === 2) {
7709 splitEarcut(ear, triangles, dim, minX, minY, invSize);
7710 }
7711
7712 break;
7713 }
7714 }
7715}
7716
7717// check whether a polygon node forms a valid ear with adjacent nodes
7718function isEar(ear) {
7719 var a = ear.prev,
7720 b = ear,
7721 c = ear.next;
7722
7723 if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
7724
7725 // now make sure we don't have other points inside the potential ear
7726 var p = ear.next.next;
7727
7728 while (p !== ear.prev) {
7729 if (pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
7730 area(p.prev, p, p.next) >= 0) return false;
7731 p = p.next;
7732 }
7733
7734 return true;
7735}
7736
7737function isEarHashed(ear, minX, minY, invSize) {
7738 var a = ear.prev,
7739 b = ear,
7740 c = ear.next;
7741
7742 if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
7743
7744 // triangle bbox; min & max are calculated like this for speed
7745 var minTX = a.x < b.x ? (a.x < c.x ? a.x : c.x) : (b.x < c.x ? b.x : c.x),
7746 minTY = a.y < b.y ? (a.y < c.y ? a.y : c.y) : (b.y < c.y ? b.y : c.y),
7747 maxTX = a.x > b.x ? (a.x > c.x ? a.x : c.x) : (b.x > c.x ? b.x : c.x),
7748 maxTY = a.y > b.y ? (a.y > c.y ? a.y : c.y) : (b.y > c.y ? b.y : c.y);
7749
7750 // z-order range for the current triangle bbox;
7751 var minZ = zOrder(minTX, minTY, minX, minY, invSize),
7752 maxZ = zOrder(maxTX, maxTY, minX, minY, invSize);
7753
7754 // first look for points inside the triangle in increasing z-order
7755 var p = ear.nextZ;
7756
7757 while (p && p.z <= maxZ) {
7758 if (p !== ear.prev && p !== ear.next &&
7759 pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
7760 area(p.prev, p, p.next) >= 0) return false;
7761 p = p.nextZ;
7762 }
7763
7764 // then look for points in decreasing z-order
7765 p = ear.prevZ;
7766
7767 while (p && p.z >= minZ) {
7768 if (p !== ear.prev && p !== ear.next &&
7769 pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
7770 area(p.prev, p, p.next) >= 0) return false;
7771 p = p.prevZ;
7772 }
7773
7774 return true;
7775}
7776
7777// go through all polygon nodes and cure small local self-intersections
7778function cureLocalIntersections(start, triangles, dim) {
7779 var p = start;
7780 do {
7781 var a = p.prev,
7782 b = p.next.next;
7783
7784 if (!equals$1(a, b) && intersects$2(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
7785
7786 triangles.push(a.i / dim);
7787 triangles.push(p.i / dim);
7788 triangles.push(b.i / dim);
7789
7790 // remove two nodes involved
7791 removeNode(p);
7792 removeNode(p.next);
7793
7794 p = start = b;
7795 }
7796 p = p.next;
7797 } while (p !== start);
7798
7799 return p;
7800}
7801
7802// try splitting polygon into two and triangulate them independently
7803function splitEarcut(start, triangles, dim, minX, minY, invSize) {
7804 // look for a valid diagonal that divides the polygon into two
7805 var a = start;
7806 do {
7807 var b = a.next.next;
7808 while (b !== a.prev) {
7809 if (a.i !== b.i && isValidDiagonal(a, b)) {
7810 // split the polygon in two by the diagonal
7811 var c = splitPolygon(a, b);
7812
7813 // filter colinear points around the cuts
7814 a = filterPoints(a, a.next);
7815 c = filterPoints(c, c.next);
7816
7817 // run earcut on each half
7818 earcutLinked(a, triangles, dim, minX, minY, invSize);
7819 earcutLinked(c, triangles, dim, minX, minY, invSize);
7820 return;
7821 }
7822 b = b.next;
7823 }
7824 a = a.next;
7825 } while (a !== start);
7826}
7827
7828// link every hole into the outer loop, producing a single-ring polygon without holes
7829function eliminateHoles(data, holeIndices, outerNode, dim) {
7830 var queue = [],
7831 i, len, start, end, list;
7832
7833 for (i = 0, len = holeIndices.length; i < len; i++) {
7834 start = holeIndices[i] * dim;
7835 end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
7836 list = linkedList(data, start, end, dim, false);
7837 if (list === list.next) list.steiner = true;
7838 queue.push(getLeftmost(list));
7839 }
7840
7841 queue.sort(compareX);
7842
7843 // process holes from left to right
7844 for (i = 0; i < queue.length; i++) {
7845 eliminateHole(queue[i], outerNode);
7846 outerNode = filterPoints(outerNode, outerNode.next);
7847 }
7848
7849 return outerNode;
7850}
7851
7852function compareX(a, b) {
7853 return a.x - b.x;
7854}
7855
7856// find a bridge between vertices that connects hole with an outer ring and and link it
7857function eliminateHole(hole, outerNode) {
7858 outerNode = findHoleBridge(hole, outerNode);
7859 if (outerNode) {
7860 var b = splitPolygon(outerNode, hole);
7861 filterPoints(b, b.next);
7862 }
7863}
7864
7865// David Eberly's algorithm for finding a bridge between hole and outer polygon
7866function findHoleBridge(hole, outerNode) {
7867 var p = outerNode,
7868 hx = hole.x,
7869 hy = hole.y,
7870 qx = -Infinity,
7871 m;
7872
7873 // find a segment intersected by a ray from the hole's leftmost point to the left;
7874 // segment's endpoint with lesser x will be potential connection point
7875 do {
7876 if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
7877 var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
7878 if (x <= hx && x > qx) {
7879 qx = x;
7880 if (x === hx) {
7881 if (hy === p.y) return p;
7882 if (hy === p.next.y) return p.next;
7883 }
7884 m = p.x < p.next.x ? p : p.next;
7885 }
7886 }
7887 p = p.next;
7888 } while (p !== outerNode);
7889
7890 if (!m) return null;
7891
7892 if (hx === qx) return m.prev; // hole touches outer segment; pick lower endpoint
7893
7894 // look for points inside the triangle of hole point, segment intersection and endpoint;
7895 // if there are no points found, we have a valid connection;
7896 // otherwise choose the point of the minimum angle with the ray as connection point
7897
7898 var stop = m,
7899 mx = m.x,
7900 my = m.y,
7901 tanMin = Infinity,
7902 tan;
7903
7904 p = m.next;
7905
7906 while (p !== stop) {
7907 if (hx >= p.x && p.x >= mx && hx !== p.x &&
7908 pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
7909
7910 tan = Math.abs(hy - p.y) / (hx - p.x); // tangential
7911
7912 if ((tan < tanMin || (tan === tanMin && p.x > m.x)) && locallyInside(p, hole)) {
7913 m = p;
7914 tanMin = tan;
7915 }
7916 }
7917
7918 p = p.next;
7919 }
7920
7921 return m;
7922}
7923
7924// interlink polygon nodes in z-order
7925function indexCurve(start, minX, minY, invSize) {
7926 var p = start;
7927 do {
7928 if (p.z === null) p.z = zOrder(p.x, p.y, minX, minY, invSize);
7929 p.prevZ = p.prev;
7930 p.nextZ = p.next;
7931 p = p.next;
7932 } while (p !== start);
7933
7934 p.prevZ.nextZ = null;
7935 p.prevZ = null;
7936
7937 sortLinked(p);
7938}
7939
7940// Simon Tatham's linked list merge sort algorithm
7941// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
7942function sortLinked(list) {
7943 var i, p, q, e, tail, numMerges, pSize, qSize,
7944 inSize = 1;
7945
7946 do {
7947 p = list;
7948 list = null;
7949 tail = null;
7950 numMerges = 0;
7951
7952 while (p) {
7953 numMerges++;
7954 q = p;
7955 pSize = 0;
7956 for (i = 0; i < inSize; i++) {
7957 pSize++;
7958 q = q.nextZ;
7959 if (!q) break;
7960 }
7961 qSize = inSize;
7962
7963 while (pSize > 0 || (qSize > 0 && q)) {
7964
7965 if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) {
7966 e = p;
7967 p = p.nextZ;
7968 pSize--;
7969 } else {
7970 e = q;
7971 q = q.nextZ;
7972 qSize--;
7973 }
7974
7975 if (tail) tail.nextZ = e;
7976 else list = e;
7977
7978 e.prevZ = tail;
7979 tail = e;
7980 }
7981
7982 p = q;
7983 }
7984
7985 tail.nextZ = null;
7986 inSize *= 2;
7987
7988 } while (numMerges > 1);
7989
7990 return list;
7991}
7992
7993// z-order of a point given coords and inverse of the longer side of data bbox
7994function zOrder(x, y, minX, minY, invSize) {
7995 // coords are transformed into non-negative 15-bit integer range
7996 x = 32767 * (x - minX) * invSize;
7997 y = 32767 * (y - minY) * invSize;
7998
7999 x = (x | (x << 8)) & 0x00FF00FF;
8000 x = (x | (x << 4)) & 0x0F0F0F0F;
8001 x = (x | (x << 2)) & 0x33333333;
8002 x = (x | (x << 1)) & 0x55555555;
8003
8004 y = (y | (y << 8)) & 0x00FF00FF;
8005 y = (y | (y << 4)) & 0x0F0F0F0F;
8006 y = (y | (y << 2)) & 0x33333333;
8007 y = (y | (y << 1)) & 0x55555555;
8008
8009 return x | (y << 1);
8010}
8011
8012// find the leftmost node of a polygon ring
8013function getLeftmost(start) {
8014 var p = start,
8015 leftmost = start;
8016 do {
8017 if (p.x < leftmost.x) leftmost = p;
8018 p = p.next;
8019 } while (p !== start);
8020
8021 return leftmost;
8022}
8023
8024// check if a point lies within a convex triangle
8025function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
8026 return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 &&
8027 (ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 &&
8028 (bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
8029}
8030
8031// check if a diagonal between two polygon nodes is valid (lies in polygon interior)
8032function isValidDiagonal(a, b) {
8033 return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) &&
8034 locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b);
8035}
8036
8037// signed area of a triangle
8038function area(p, q, r) {
8039 return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
8040}
8041
8042// check if two points are equal
8043function equals$1(p1, p2) {
8044 return p1.x === p2.x && p1.y === p2.y;
8045}
8046
8047// check if two segments intersect
8048function intersects$2(p1, q1, p2, q2) {
8049 if ((equals$1(p1, q1) && equals$1(p2, q2)) ||
8050 (equals$1(p1, q2) && equals$1(p2, q1))) return true;
8051 return area(p1, q1, p2) > 0 !== area(p1, q1, q2) > 0 &&
8052 area(p2, q2, p1) > 0 !== area(p2, q2, q1) > 0;
8053}
8054
8055// check if a polygon diagonal intersects any polygon segments
8056function intersectsPolygon(a, b) {
8057 var p = a;
8058 do {
8059 if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
8060 intersects$2(p, p.next, a, b)) return true;
8061 p = p.next;
8062 } while (p !== a);
8063
8064 return false;
8065}
8066
8067// check if a polygon diagonal is locally inside the polygon
8068function locallyInside(a, b) {
8069 return area(a.prev, a, a.next) < 0 ?
8070 area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 :
8071 area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;
8072}
8073
8074// check if the middle point of a polygon diagonal is inside the polygon
8075function middleInside(a, b) {
8076 var p = a,
8077 inside = false,
8078 px = (a.x + b.x) / 2,
8079 py = (a.y + b.y) / 2;
8080 do {
8081 if (((p.y > py) !== (p.next.y > py)) && p.next.y !== p.y &&
8082 (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x))
8083 inside = !inside;
8084 p = p.next;
8085 } while (p !== a);
8086
8087 return inside;
8088}
8089
8090// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
8091// if one belongs to the outer ring and another to a hole, it merges it into a single ring
8092function splitPolygon(a, b) {
8093 var a2 = new Node(a.i, a.x, a.y),
8094 b2 = new Node(b.i, b.x, b.y),
8095 an = a.next,
8096 bp = b.prev;
8097
8098 a.next = b;
8099 b.prev = a;
8100
8101 a2.next = an;
8102 an.prev = a2;
8103
8104 b2.next = a2;
8105 a2.prev = b2;
8106
8107 bp.next = b2;
8108 b2.prev = bp;
8109
8110 return b2;
8111}
8112
8113// create a node and optionally link it with previous one (in a circular doubly linked list)
8114function insertNode$1(i, x, y, last) {
8115 var p = new Node(i, x, y);
8116
8117 if (!last) {
8118 p.prev = p;
8119 p.next = p;
8120
8121 } else {
8122 p.next = last.next;
8123 p.prev = last;
8124 last.next.prev = p;
8125 last.next = p;
8126 }
8127 return p;
8128}
8129
8130function removeNode(p) {
8131 p.next.prev = p.prev;
8132 p.prev.next = p.next;
8133
8134 if (p.prevZ) p.prevZ.nextZ = p.nextZ;
8135 if (p.nextZ) p.nextZ.prevZ = p.prevZ;
8136}
8137
8138function Node(i, x, y) {
8139 // vertice index in coordinates array
8140 this.i = i;
8141
8142 // vertex coordinates
8143 this.x = x;
8144 this.y = y;
8145
8146 // previous and next vertice nodes in a polygon ring
8147 this.prev = null;
8148 this.next = null;
8149
8150 // z-order curve value
8151 this.z = null;
8152
8153 // previous and next nodes in z-order
8154 this.prevZ = null;
8155 this.nextZ = null;
8156
8157 // indicates whether this is a steiner point
8158 this.steiner = false;
8159}
8160
8161// return a percentage difference between the polygon area and its triangulation area;
8162// used to verify correctness of triangulation
8163earcut.deviation = function (data, holeIndices, dim, triangles) {
8164 var hasHoles = holeIndices && holeIndices.length;
8165 var outerLen = hasHoles ? holeIndices[0] * dim : data.length;
8166
8167 var polygonArea = Math.abs(signedArea(data, 0, outerLen, dim));
8168 if (hasHoles) {
8169 for (var i = 0, len = holeIndices.length; i < len; i++) {
8170 var start = holeIndices[i] * dim;
8171 var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
8172 polygonArea -= Math.abs(signedArea(data, start, end, dim));
8173 }
8174 }
8175
8176 var trianglesArea = 0;
8177 for (i = 0; i < triangles.length; i += 3) {
8178 var a = triangles[i] * dim;
8179 var b = triangles[i + 1] * dim;
8180 var c = triangles[i + 2] * dim;
8181 trianglesArea += Math.abs(
8182 (data[a] - data[c]) * (data[b + 1] - data[a + 1]) -
8183 (data[a] - data[b]) * (data[c + 1] - data[a + 1]));
8184 }
8185
8186 return polygonArea === 0 && trianglesArea === 0 ? 0 :
8187 Math.abs((trianglesArea - polygonArea) / polygonArea);
8188};
8189
8190function signedArea(data, start, end, dim) {
8191 var sum = 0;
8192 for (var i = start, j = end - dim; i < end; i += dim) {
8193 sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
8194 j = i;
8195 }
8196 return sum;
8197}
8198
8199// turn a polygon in a multi-dimensional array form (e.g. as in GeoJSON) into a form Earcut accepts
8200earcut.flatten = function (data) {
8201 var dim = data[0][0].length,
8202 result = {vertices: [], holes: [], dimensions: dim},
8203 holeIndex = 0;
8204
8205 for (var i = 0; i < data.length; i++) {
8206 for (var j = 0; j < data[i].length; j++) {
8207 for (var d = 0; d < dim; d++) result.vertices.push(data[i][j][d]);
8208 }
8209 if (i > 0) {
8210 holeIndex += data[i - 1].length;
8211 result.holes.push(holeIndex);
8212 }
8213 }
8214 return result;
8215};
8216
8217earcut_1.default = default_1$2;
8218
8219/**
8220 * Tesselates a {@link Feature<Polygon>} into a {@link FeatureCollection<Polygon>} of triangles
8221 * using [earcut](https://github.com/mapbox/earcut).
8222 *
8223 * @name tesselate
8224 * @param {Feature<Polygon>} poly the polygon to tesselate
8225 * @returns {FeatureCollection<Polygon>} a geometrycollection feature
8226 * @example
8227 * var poly = turf.polygon([[[11, 0], [22, 4], [31, 0], [31, 11], [21, 15], [11, 11], [11, 0]]]);
8228 * var triangles = turf.tesselate(poly);
8229 *
8230 * //addToMap
8231 * var addToMap = [poly, triangles]
8232 */
8233function tesselate(poly) {
8234 if (!poly.geometry || (poly.geometry.type !== 'Polygon' && poly.geometry.type !== 'MultiPolygon')) {
8235 throw new Error('input must be a Polygon or MultiPolygon');
8236 }
8237
8238 var fc = {type: 'FeatureCollection', features: []};
8239
8240 if (poly.geometry.type === 'Polygon') {
8241 fc.features = processPolygon(poly.geometry.coordinates);
8242 } else {
8243 poly.geometry.coordinates.forEach(function (coordinates) {
8244 fc.features = fc.features.concat(processPolygon(coordinates));
8245 });
8246 }
8247
8248 return fc;
8249}
8250
8251function processPolygon(coordinates) {
8252 var data = flattenCoords(coordinates);
8253 var dim = 2;
8254 var result = earcut_1(data.vertices, data.holes, dim);
8255
8256 var features = [];
8257 var vertices = [];
8258
8259 result.forEach(function (vert, i) {
8260 var index = result[i];
8261 vertices.push([data.vertices[index * dim], data.vertices[index * dim + 1]]);
8262 });
8263
8264 for (var i = 0; i < vertices.length; i += 3) {
8265 var coords = vertices.slice(i, i + 3);
8266 coords.push(vertices[i]);
8267 features.push(polygon([coords]));
8268 }
8269
8270 return features;
8271}
8272
8273function flattenCoords(data) {
8274 var dim = data[0][0].length,
8275 result = {vertices: [], holes: [], dimensions: dim},
8276 holeIndex = 0;
8277
8278 for (var i = 0; i < data.length; i++) {
8279 for (var j = 0; j < data[i].length; j++) {
8280 for (var d = 0; d < dim; d++) result.vertices.push(data[i][j][d]);
8281 }
8282 if (i > 0) {
8283 holeIndex += data[i - 1].length;
8284 result.holes.push(holeIndex);
8285 }
8286 }
8287
8288 return result;
8289}
8290
8291/**
8292 * Takes a reference {@link Point|point} and a FeatureCollection of Features
8293 * with Point geometries and returns the
8294 * point from the FeatureCollection closest to the reference. This calculation
8295 * is geodesic.
8296 *
8297 * @name nearestPoint
8298 * @param {Coord} targetPoint the reference point
8299 * @param {FeatureCollection<Point>} points against input point set
8300 * @returns {Feature<Point>} the closest point in the set to the reference point
8301 * @example
8302 * var targetPoint = turf.point([28.965797, 41.010086], {"marker-color": "#0F0"});
8303 * var points = turf.featureCollection([
8304 * turf.point([28.973865, 41.011122]),
8305 * turf.point([28.948459, 41.024204]),
8306 * turf.point([28.938674, 41.013324])
8307 * ]);
8308 *
8309 * var nearest = turf.nearestPoint(targetPoint, points);
8310 *
8311 * //addToMap
8312 * var addToMap = [targetPoint, points, nearest];
8313 * nearest.properties['marker-color'] = '#F00';
8314 */
8315function nearestPoint(targetPoint, points) {
8316 // Input validation
8317 if (!targetPoint) throw new Error('targetPoint is required');
8318 if (!points) throw new Error('points is required');
8319
8320 var nearest;
8321 var minDist = Infinity;
8322 featureEach(points, function (pt, featureIndex) {
8323 var distanceToPoint = distance(targetPoint, pt);
8324 if (distanceToPoint < minDist) {
8325 nearest = clone(pt);
8326 nearest.properties.featureIndex = featureIndex;
8327 nearest.properties.distanceToPoint = distanceToPoint;
8328 minDist = distanceToPoint;
8329 }
8330
8331 });
8332 return nearest;
8333}
8334
8335function quickselect$3(arr, k, left, right, compare) {
8336 quickselectStep(arr, k, left || 0, right || (arr.length - 1), compare || defaultCompare$2);
8337}
8338
8339function quickselectStep(arr, k, left, right, compare) {
8340
8341 while (right > left) {
8342 if (right - left > 600) {
8343 var n = right - left + 1;
8344 var m = k - left + 1;
8345 var z = Math.log(n);
8346 var s = 0.5 * Math.exp(2 * z / 3);
8347 var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
8348 var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
8349 var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
8350 quickselectStep(arr, k, newLeft, newRight, compare);
8351 }
8352
8353 var t = arr[k];
8354 var i = left;
8355 var j = right;
8356
8357 swap$1(arr, left, k);
8358 if (compare(arr[right], t) > 0) swap$1(arr, left, right);
8359
8360 while (i < j) {
8361 swap$1(arr, i, j);
8362 i++;
8363 j--;
8364 while (compare(arr[i], t) < 0) i++;
8365 while (compare(arr[j], t) > 0) j--;
8366 }
8367
8368 if (compare(arr[left], t) === 0) swap$1(arr, left, j);
8369 else {
8370 j++;
8371 swap$1(arr, j, right);
8372 }
8373
8374 if (j <= k) left = j + 1;
8375 if (k <= j) right = j - 1;
8376 }
8377}
8378
8379function swap$1(arr, i, j) {
8380 var tmp = arr[i];
8381 arr[i] = arr[j];
8382 arr[j] = tmp;
8383}
8384
8385function defaultCompare$2(a, b) {
8386 return a < b ? -1 : a > b ? 1 : 0;
8387}
8388
8389function rbush$4(maxEntries, format) {
8390 if (!(this instanceof rbush$4)) return new rbush$4(maxEntries, format);
8391
8392 // max entries in a node is 9 by default; min node fill is 40% for best performance
8393 this._maxEntries = Math.max(4, maxEntries || 9);
8394 this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
8395
8396 if (format) {
8397 this._initFormat(format);
8398 }
8399
8400 this.clear();
8401}
8402
8403rbush$4.prototype = {
8404
8405 all: function () {
8406 return this._all(this.data, []);
8407 },
8408
8409 search: function (bbox) {
8410
8411 var node = this.data,
8412 result = [],
8413 toBBox = this.toBBox;
8414
8415 if (!intersects$4(bbox, node)) return result;
8416
8417 var nodesToSearch = [],
8418 i, len, child, childBBox;
8419
8420 while (node) {
8421 for (i = 0, len = node.children.length; i < len; i++) {
8422
8423 child = node.children[i];
8424 childBBox = node.leaf ? toBBox(child) : child;
8425
8426 if (intersects$4(bbox, childBBox)) {
8427 if (node.leaf) result.push(child);
8428 else if (contains$1(bbox, childBBox)) this._all(child, result);
8429 else nodesToSearch.push(child);
8430 }
8431 }
8432 node = nodesToSearch.pop();
8433 }
8434
8435 return result;
8436 },
8437
8438 collides: function (bbox) {
8439
8440 var node = this.data,
8441 toBBox = this.toBBox;
8442
8443 if (!intersects$4(bbox, node)) return false;
8444
8445 var nodesToSearch = [],
8446 i, len, child, childBBox;
8447
8448 while (node) {
8449 for (i = 0, len = node.children.length; i < len; i++) {
8450
8451 child = node.children[i];
8452 childBBox = node.leaf ? toBBox(child) : child;
8453
8454 if (intersects$4(bbox, childBBox)) {
8455 if (node.leaf || contains$1(bbox, childBBox)) return true;
8456 nodesToSearch.push(child);
8457 }
8458 }
8459 node = nodesToSearch.pop();
8460 }
8461
8462 return false;
8463 },
8464
8465 load: function (data) {
8466 if (!(data && data.length)) return this;
8467
8468 if (data.length < this._minEntries) {
8469 for (var i = 0, len = data.length; i < len; i++) {
8470 this.insert(data[i]);
8471 }
8472 return this;
8473 }
8474
8475 // recursively build the tree with the given data from scratch using OMT algorithm
8476 var node = this._build(data.slice(), 0, data.length - 1, 0);
8477
8478 if (!this.data.children.length) {
8479 // save as is if tree is empty
8480 this.data = node;
8481
8482 } else if (this.data.height === node.height) {
8483 // split root if trees have the same height
8484 this._splitRoot(this.data, node);
8485
8486 } else {
8487 if (this.data.height < node.height) {
8488 // swap trees if inserted one is bigger
8489 var tmpNode = this.data;
8490 this.data = node;
8491 node = tmpNode;
8492 }
8493
8494 // insert the small tree into the large tree at appropriate level
8495 this._insert(node, this.data.height - node.height - 1, true);
8496 }
8497
8498 return this;
8499 },
8500
8501 insert: function (item) {
8502 if (item) this._insert(item, this.data.height - 1);
8503 return this;
8504 },
8505
8506 clear: function () {
8507 this.data = createNode$1([]);
8508 return this;
8509 },
8510
8511 remove: function (item, equalsFn) {
8512 if (!item) return this;
8513
8514 var node = this.data,
8515 bbox = this.toBBox(item),
8516 path = [],
8517 indexes = [],
8518 i, parent, index, goingUp;
8519
8520 // depth-first iterative tree traversal
8521 while (node || path.length) {
8522
8523 if (!node) { // go up
8524 node = path.pop();
8525 parent = path[path.length - 1];
8526 i = indexes.pop();
8527 goingUp = true;
8528 }
8529
8530 if (node.leaf) { // check current node
8531 index = findItem$1(item, node.children, equalsFn);
8532
8533 if (index !== -1) {
8534 // item found, remove the item and condense tree upwards
8535 node.children.splice(index, 1);
8536 path.push(node);
8537 this._condense(path);
8538 return this;
8539 }
8540 }
8541
8542 if (!goingUp && !node.leaf && contains$1(node, bbox)) { // go down
8543 path.push(node);
8544 indexes.push(i);
8545 i = 0;
8546 parent = node;
8547 node = node.children[0];
8548
8549 } else if (parent) { // go right
8550 i++;
8551 node = parent.children[i];
8552 goingUp = false;
8553
8554 } else node = null; // nothing found
8555 }
8556
8557 return this;
8558 },
8559
8560 toBBox: function (item) { return item; },
8561
8562 compareMinX: compareNodeMinX$1,
8563 compareMinY: compareNodeMinY$1,
8564
8565 toJSON: function () { return this.data; },
8566
8567 fromJSON: function (data) {
8568 this.data = data;
8569 return this;
8570 },
8571
8572 _all: function (node, result) {
8573 var nodesToSearch = [];
8574 while (node) {
8575 if (node.leaf) result.push.apply(result, node.children);
8576 else nodesToSearch.push.apply(nodesToSearch, node.children);
8577
8578 node = nodesToSearch.pop();
8579 }
8580 return result;
8581 },
8582
8583 _build: function (items, left, right, height) {
8584
8585 var N = right - left + 1,
8586 M = this._maxEntries,
8587 node;
8588
8589 if (N <= M) {
8590 // reached leaf level; return leaf
8591 node = createNode$1(items.slice(left, right + 1));
8592 calcBBox$1(node, this.toBBox);
8593 return node;
8594 }
8595
8596 if (!height) {
8597 // target height of the bulk-loaded tree
8598 height = Math.ceil(Math.log(N) / Math.log(M));
8599
8600 // target number of root entries to maximize storage utilization
8601 M = Math.ceil(N / Math.pow(M, height - 1));
8602 }
8603
8604 node = createNode$1([]);
8605 node.leaf = false;
8606 node.height = height;
8607
8608 // split the items into M mostly square tiles
8609
8610 var N2 = Math.ceil(N / M),
8611 N1 = N2 * Math.ceil(Math.sqrt(M)),
8612 i, j, right2, right3;
8613
8614 multiSelect$1(items, left, right, N1, this.compareMinX);
8615
8616 for (i = left; i <= right; i += N1) {
8617
8618 right2 = Math.min(i + N1 - 1, right);
8619
8620 multiSelect$1(items, i, right2, N2, this.compareMinY);
8621
8622 for (j = i; j <= right2; j += N2) {
8623
8624 right3 = Math.min(j + N2 - 1, right2);
8625
8626 // pack each entry recursively
8627 node.children.push(this._build(items, j, right3, height - 1));
8628 }
8629 }
8630
8631 calcBBox$1(node, this.toBBox);
8632
8633 return node;
8634 },
8635
8636 _chooseSubtree: function (bbox, node, level, path) {
8637
8638 var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
8639
8640 while (true) {
8641 path.push(node);
8642
8643 if (node.leaf || path.length - 1 === level) break;
8644
8645 minArea = minEnlargement = Infinity;
8646
8647 for (i = 0, len = node.children.length; i < len; i++) {
8648 child = node.children[i];
8649 area = bboxArea$1(child);
8650 enlargement = enlargedArea$1(bbox, child) - area;
8651
8652 // choose entry with the least area enlargement
8653 if (enlargement < minEnlargement) {
8654 minEnlargement = enlargement;
8655 minArea = area < minArea ? area : minArea;
8656 targetNode = child;
8657
8658 } else if (enlargement === minEnlargement) {
8659 // otherwise choose one with the smallest area
8660 if (area < minArea) {
8661 minArea = area;
8662 targetNode = child;
8663 }
8664 }
8665 }
8666
8667 node = targetNode || node.children[0];
8668 }
8669
8670 return node;
8671 },
8672
8673 _insert: function (item, level, isNode) {
8674
8675 var toBBox = this.toBBox,
8676 bbox = isNode ? item : toBBox(item),
8677 insertPath = [];
8678
8679 // find the best node for accommodating the item, saving all nodes along the path too
8680 var node = this._chooseSubtree(bbox, this.data, level, insertPath);
8681
8682 // put the item into the node
8683 node.children.push(item);
8684 extend$1(node, bbox);
8685
8686 // split on node overflow; propagate upwards if necessary
8687 while (level >= 0) {
8688 if (insertPath[level].children.length > this._maxEntries) {
8689 this._split(insertPath, level);
8690 level--;
8691 } else break;
8692 }
8693
8694 // adjust bboxes along the insertion path
8695 this._adjustParentBBoxes(bbox, insertPath, level);
8696 },
8697
8698 // split overflowed node into two
8699 _split: function (insertPath, level) {
8700
8701 var node = insertPath[level],
8702 M = node.children.length,
8703 m = this._minEntries;
8704
8705 this._chooseSplitAxis(node, m, M);
8706
8707 var splitIndex = this._chooseSplitIndex(node, m, M);
8708
8709 var newNode = createNode$1(node.children.splice(splitIndex, node.children.length - splitIndex));
8710 newNode.height = node.height;
8711 newNode.leaf = node.leaf;
8712
8713 calcBBox$1(node, this.toBBox);
8714 calcBBox$1(newNode, this.toBBox);
8715
8716 if (level) insertPath[level - 1].children.push(newNode);
8717 else this._splitRoot(node, newNode);
8718 },
8719
8720 _splitRoot: function (node, newNode) {
8721 // split root node
8722 this.data = createNode$1([node, newNode]);
8723 this.data.height = node.height + 1;
8724 this.data.leaf = false;
8725 calcBBox$1(this.data, this.toBBox);
8726 },
8727
8728 _chooseSplitIndex: function (node, m, M) {
8729
8730 var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
8731
8732 minOverlap = minArea = Infinity;
8733
8734 for (i = m; i <= M - m; i++) {
8735 bbox1 = distBBox$1(node, 0, i, this.toBBox);
8736 bbox2 = distBBox$1(node, i, M, this.toBBox);
8737
8738 overlap = intersectionArea$1(bbox1, bbox2);
8739 area = bboxArea$1(bbox1) + bboxArea$1(bbox2);
8740
8741 // choose distribution with minimum overlap
8742 if (overlap < minOverlap) {
8743 minOverlap = overlap;
8744 index = i;
8745
8746 minArea = area < minArea ? area : minArea;
8747
8748 } else if (overlap === minOverlap) {
8749 // otherwise choose distribution with minimum area
8750 if (area < minArea) {
8751 minArea = area;
8752 index = i;
8753 }
8754 }
8755 }
8756
8757 return index;
8758 },
8759
8760 // sorts node children by the best axis for split
8761 _chooseSplitAxis: function (node, m, M) {
8762
8763 var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX$1,
8764 compareMinY = node.leaf ? this.compareMinY : compareNodeMinY$1,
8765 xMargin = this._allDistMargin(node, m, M, compareMinX),
8766 yMargin = this._allDistMargin(node, m, M, compareMinY);
8767
8768 // if total distributions margin value is minimal for x, sort by minX,
8769 // otherwise it's already sorted by minY
8770 if (xMargin < yMargin) node.children.sort(compareMinX);
8771 },
8772
8773 // total margin of all possible split distributions where each node is at least m full
8774 _allDistMargin: function (node, m, M, compare) {
8775
8776 node.children.sort(compare);
8777
8778 var toBBox = this.toBBox,
8779 leftBBox = distBBox$1(node, 0, m, toBBox),
8780 rightBBox = distBBox$1(node, M - m, M, toBBox),
8781 margin = bboxMargin$1(leftBBox) + bboxMargin$1(rightBBox),
8782 i, child;
8783
8784 for (i = m; i < M - m; i++) {
8785 child = node.children[i];
8786 extend$1(leftBBox, node.leaf ? toBBox(child) : child);
8787 margin += bboxMargin$1(leftBBox);
8788 }
8789
8790 for (i = M - m - 1; i >= m; i--) {
8791 child = node.children[i];
8792 extend$1(rightBBox, node.leaf ? toBBox(child) : child);
8793 margin += bboxMargin$1(rightBBox);
8794 }
8795
8796 return margin;
8797 },
8798
8799 _adjustParentBBoxes: function (bbox, path, level) {
8800 // adjust bboxes along the given tree path
8801 for (var i = level; i >= 0; i--) {
8802 extend$1(path[i], bbox);
8803 }
8804 },
8805
8806 _condense: function (path) {
8807 // go through the path, removing empty nodes and updating bboxes
8808 for (var i = path.length - 1, siblings; i >= 0; i--) {
8809 if (path[i].children.length === 0) {
8810 if (i > 0) {
8811 siblings = path[i - 1].children;
8812 siblings.splice(siblings.indexOf(path[i]), 1);
8813
8814 } else this.clear();
8815
8816 } else calcBBox$1(path[i], this.toBBox);
8817 }
8818 },
8819
8820 _initFormat: function (format) {
8821 // data format (minX, minY, maxX, maxY accessors)
8822
8823 // uses eval-type function compilation instead of just accepting a toBBox function
8824 // because the algorithms are very sensitive to sorting functions performance,
8825 // so they should be dead simple and without inner calls
8826
8827 var compareArr = ['return a', ' - b', ';'];
8828
8829 this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
8830 this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
8831
8832 this.toBBox = new Function('a',
8833 'return {minX: a' + format[0] +
8834 ', minY: a' + format[1] +
8835 ', maxX: a' + format[2] +
8836 ', maxY: a' + format[3] + '};');
8837 }
8838};
8839
8840function findItem$1(item, items, equalsFn) {
8841 if (!equalsFn) return items.indexOf(item);
8842
8843 for (var i = 0; i < items.length; i++) {
8844 if (equalsFn(item, items[i])) return i;
8845 }
8846 return -1;
8847}
8848
8849// calculate node's bbox from bboxes of its children
8850function calcBBox$1(node, toBBox) {
8851 distBBox$1(node, 0, node.children.length, toBBox, node);
8852}
8853
8854// min bounding rectangle of node children from k to p-1
8855function distBBox$1(node, k, p, toBBox, destNode) {
8856 if (!destNode) destNode = createNode$1(null);
8857 destNode.minX = Infinity;
8858 destNode.minY = Infinity;
8859 destNode.maxX = -Infinity;
8860 destNode.maxY = -Infinity;
8861
8862 for (var i = k, child; i < p; i++) {
8863 child = node.children[i];
8864 extend$1(destNode, node.leaf ? toBBox(child) : child);
8865 }
8866
8867 return destNode;
8868}
8869
8870function extend$1(a, b) {
8871 a.minX = Math.min(a.minX, b.minX);
8872 a.minY = Math.min(a.minY, b.minY);
8873 a.maxX = Math.max(a.maxX, b.maxX);
8874 a.maxY = Math.max(a.maxY, b.maxY);
8875 return a;
8876}
8877
8878function compareNodeMinX$1(a, b) { return a.minX - b.minX; }
8879function compareNodeMinY$1(a, b) { return a.minY - b.minY; }
8880
8881function bboxArea$1(a) { return (a.maxX - a.minX) * (a.maxY - a.minY); }
8882function bboxMargin$1(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); }
8883
8884function enlargedArea$1(a, b) {
8885 return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) *
8886 (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
8887}
8888
8889function intersectionArea$1(a, b) {
8890 var minX = Math.max(a.minX, b.minX),
8891 minY = Math.max(a.minY, b.minY),
8892 maxX = Math.min(a.maxX, b.maxX),
8893 maxY = Math.min(a.maxY, b.maxY);
8894
8895 return Math.max(0, maxX - minX) *
8896 Math.max(0, maxY - minY);
8897}
8898
8899function contains$1(a, b) {
8900 return a.minX <= b.minX &&
8901 a.minY <= b.minY &&
8902 b.maxX <= a.maxX &&
8903 b.maxY <= a.maxY;
8904}
8905
8906function intersects$4(a, b) {
8907 return b.minX <= a.maxX &&
8908 b.minY <= a.maxY &&
8909 b.maxX >= a.minX &&
8910 b.maxY >= a.minY;
8911}
8912
8913function createNode$1(children) {
8914 return {
8915 children: children,
8916 height: 1,
8917 leaf: true,
8918 minX: Infinity,
8919 minY: Infinity,
8920 maxX: -Infinity,
8921 maxY: -Infinity
8922 };
8923}
8924
8925// sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
8926// combines selection algorithm with binary divide & conquer approach
8927
8928function multiSelect$1(arr, left, right, n, compare) {
8929 var stack = [left, right],
8930 mid;
8931
8932 while (stack.length) {
8933 right = stack.pop();
8934 left = stack.pop();
8935
8936 if (right - left <= n) continue;
8937
8938 mid = left + Math.ceil((right - left) / n / 2) * n;
8939 quickselect$3(arr, mid, left, right, compare);
8940
8941 stack.push(left, mid, mid, right);
8942 }
8943}
8944
8945/**
8946 * GeoJSON implementation of [RBush](https://github.com/mourner/rbush#rbush) spatial index.
8947 *
8948 * @name rbush
8949 * @param {number} [maxEntries=9] defines the maximum number of entries in a tree node. 9 (used by default) is a
8950 * reasonable choice for most applications. Higher value means faster insertion and slower search, and vice versa.
8951 * @returns {RBush} GeoJSON RBush
8952 * @example
8953 * import geojsonRbush from 'geojson-rbush';
8954 * var tree = geojsonRbush();
8955 */
8956function geojsonRbush(maxEntries) {
8957 var tree = rbush$4(maxEntries);
8958 /**
8959 * [insert](https://github.com/mourner/rbush#data-format)
8960 *
8961 * @param {Feature<any>} feature insert single GeoJSON Feature
8962 * @returns {RBush} GeoJSON RBush
8963 * @example
8964 * var polygon = {
8965 * "type": "Feature",
8966 * "properties": {},
8967 * "geometry": {
8968 * "type": "Polygon",
8969 * "coordinates": [[[-78, 41], [-67, 41], [-67, 48], [-78, 48], [-78, 41]]]
8970 * }
8971 * }
8972 * tree.insert(polygon)
8973 */
8974 tree.insert = function (feature) {
8975 if (Array.isArray(feature)) {
8976 var bbox = feature;
8977 feature = bboxPolygon$2(bbox);
8978 feature.bbox = bbox;
8979 } else {
8980 feature.bbox = feature.bbox ? feature.bbox : turfBBox(feature);
8981 }
8982 return rbush$4.prototype.insert.call(this, feature);
8983 };
8984
8985 /**
8986 * [load](https://github.com/mourner/rbush#bulk-inserting-data)
8987 *
8988 * @param {BBox[]|FeatureCollection<any>} features load entire GeoJSON FeatureCollection
8989 * @returns {RBush} GeoJSON RBush
8990 * @example
8991 * var polygons = {
8992 * "type": "FeatureCollection",
8993 * "features": [
8994 * {
8995 * "type": "Feature",
8996 * "properties": {},
8997 * "geometry": {
8998 * "type": "Polygon",
8999 * "coordinates": [[[-78, 41], [-67, 41], [-67, 48], [-78, 48], [-78, 41]]]
9000 * }
9001 * },
9002 * {
9003 * "type": "Feature",
9004 * "properties": {},
9005 * "geometry": {
9006 * "type": "Polygon",
9007 * "coordinates": [[[-93, 32], [-83, 32], [-83, 39], [-93, 39], [-93, 32]]]
9008 * }
9009 * }
9010 * ]
9011 * }
9012 * tree.load(polygons)
9013 */
9014 tree.load = function (features) {
9015 var load = [];
9016 // Load an Array of BBox
9017 if (Array.isArray(features)) {
9018 features.forEach(function (bbox) {
9019 var feature = bboxPolygon$2(bbox);
9020 feature.bbox = bbox;
9021 load.push(feature);
9022 });
9023 } else {
9024 // Load FeatureCollection
9025 featureEach(features, function (feature) {
9026 feature.bbox = feature.bbox ? feature.bbox : turfBBox(feature);
9027 load.push(feature);
9028 });
9029 }
9030 return rbush$4.prototype.load.call(this, load);
9031 };
9032
9033 /**
9034 * [remove](https://github.com/mourner/rbush#removing-data)
9035 *
9036 * @param {BBox|Feature<any>} feature remove single GeoJSON Feature
9037 * @returns {RBush} GeoJSON RBush
9038 * @example
9039 * var polygon = {
9040 * "type": "Feature",
9041 * "properties": {},
9042 * "geometry": {
9043 * "type": "Polygon",
9044 * "coordinates": [[[-78, 41], [-67, 41], [-67, 48], [-78, 48], [-78, 41]]]
9045 * }
9046 * }
9047 * tree.remove(polygon)
9048 */
9049 tree.remove = function (feature) {
9050 if (Array.isArray(feature)) {
9051 var bbox = feature;
9052 feature = bboxPolygon$2(bbox);
9053 feature.bbox = bbox;
9054 }
9055 return rbush$4.prototype.remove.call(this, feature);
9056 };
9057
9058 /**
9059 * [clear](https://github.com/mourner/rbush#removing-data)
9060 *
9061 * @returns {RBush} GeoJSON Rbush
9062 * @example
9063 * tree.clear()
9064 */
9065 tree.clear = function () {
9066 return rbush$4.prototype.clear.call(this);
9067 };
9068
9069 /**
9070 * [search](https://github.com/mourner/rbush#search)
9071 *
9072 * @param {BBox|FeatureCollection|Feature<any>} geojson search with GeoJSON
9073 * @returns {FeatureCollection<any>} all features that intersects with the given GeoJSON.
9074 * @example
9075 * var polygon = {
9076 * "type": "Feature",
9077 * "properties": {},
9078 * "geometry": {
9079 * "type": "Polygon",
9080 * "coordinates": [[[-78, 41], [-67, 41], [-67, 48], [-78, 48], [-78, 41]]]
9081 * }
9082 * }
9083 * tree.search(polygon)
9084 */
9085 tree.search = function (geojson) {
9086 var features = rbush$4.prototype.search.call(this, this.toBBox(geojson));
9087 return {
9088 type: 'FeatureCollection',
9089 features: features
9090 };
9091 };
9092
9093 /**
9094 * [collides](https://github.com/mourner/rbush#collisions)
9095 *
9096 * @param {BBox|FeatureCollection|Feature<any>} geojson collides with GeoJSON
9097 * @returns {boolean} true if there are any items intersecting the given GeoJSON, otherwise false.
9098 * @example
9099 * var polygon = {
9100 * "type": "Feature",
9101 * "properties": {},
9102 * "geometry": {
9103 * "type": "Polygon",
9104 * "coordinates": [[[-78, 41], [-67, 41], [-67, 48], [-78, 48], [-78, 41]]]
9105 * }
9106 * }
9107 * tree.collides(polygon)
9108 */
9109 tree.collides = function (geojson) {
9110 return rbush$4.prototype.collides.call(this, this.toBBox(geojson));
9111 };
9112
9113 /**
9114 * [all](https://github.com/mourner/rbush#search)
9115 *
9116 * @returns {FeatureCollection<any>} all the features in RBush
9117 * @example
9118 * tree.all()
9119 * //=FeatureCollection
9120 */
9121 tree.all = function () {
9122 var features = rbush$4.prototype.all.call(this);
9123 return {
9124 type: 'FeatureCollection',
9125 features: features
9126 };
9127 };
9128
9129 /**
9130 * [toJSON](https://github.com/mourner/rbush#export-and-import)
9131 *
9132 * @returns {any} export data as JSON object
9133 * @example
9134 * var exported = tree.toJSON()
9135 * //=JSON object
9136 */
9137 tree.toJSON = function () {
9138 return rbush$4.prototype.toJSON.call(this);
9139 };
9140
9141 /**
9142 * [fromJSON](https://github.com/mourner/rbush#export-and-import)
9143 *
9144 * @param {any} json import previously exported data
9145 * @returns {RBush} GeoJSON RBush
9146 * @example
9147 * var exported = {
9148 * "children": [
9149 * {
9150 * "type": "Feature",
9151 * "geometry": {
9152 * "type": "Point",
9153 * "coordinates": [110, 50]
9154 * },
9155 * "properties": {},
9156 * "bbox": [110, 50, 110, 50]
9157 * }
9158 * ],
9159 * "height": 1,
9160 * "leaf": true,
9161 * "minX": 110,
9162 * "minY": 50,
9163 * "maxX": 110,
9164 * "maxY": 50
9165 * }
9166 * tree.fromJSON(exported)
9167 */
9168 tree.fromJSON = function (json) {
9169 return rbush$4.prototype.fromJSON.call(this, json);
9170 };
9171
9172 /**
9173 * Converts GeoJSON to {minX, minY, maxX, maxY} schema
9174 *
9175 * @private
9176 * @param {BBox|FeatureCollectio|Feature<any>} geojson feature(s) to retrieve BBox from
9177 * @returns {Object} converted to {minX, minY, maxX, maxY}
9178 */
9179 tree.toBBox = function (geojson) {
9180 var bbox;
9181 if (geojson.bbox) bbox = geojson.bbox;
9182 else if (Array.isArray(geojson) && geojson.length === 4) bbox = geojson;
9183 else bbox = turfBBox(geojson);
9184
9185 return {
9186 minX: bbox[0],
9187 minY: bbox[1],
9188 maxX: bbox[2],
9189 maxY: bbox[3]
9190 };
9191 };
9192 return tree;
9193}
9194
9195/**
9196 * Takes a bbox and returns an equivalent {@link Polygon|polygon}.
9197 *
9198 * @private
9199 * @name bboxPolygon
9200 * @param {Array<number>} bbox extent in [minX, minY, maxX, maxY] order
9201 * @returns {Feature<Polygon>} a Polygon representation of the bounding box
9202 * @example
9203 * var bbox = [0, 0, 10, 10];
9204 *
9205 * var poly = turf.bboxPolygon(bbox);
9206 *
9207 * //addToMap
9208 * var addToMap = [poly]
9209 */
9210function bboxPolygon$2(bbox) {
9211 var lowLeft = [bbox[0], bbox[1]];
9212 var topLeft = [bbox[0], bbox[3]];
9213 var topRight = [bbox[2], bbox[3]];
9214 var lowRight = [bbox[2], bbox[1]];
9215 var coordinates = [[lowLeft, lowRight, topRight, topLeft, lowLeft]];
9216
9217 return {
9218 type: 'Feature',
9219 bbox: bbox,
9220 properties: {},
9221 geometry: {
9222 type: 'Polygon',
9223 coordinates: coordinates
9224 }
9225 };
9226}
9227
9228/**
9229 * Takes a set of features, calculates the bbox of all input features, and returns a bounding box.
9230 *
9231 * @private
9232 * @name bbox
9233 * @param {FeatureCollection|Feature<any>} geojson input features
9234 * @returns {Array<number>} bbox extent in [minX, minY, maxX, maxY] order
9235 * @example
9236 * var line = turf.lineString([[-74, 40], [-78, 42], [-82, 35]]);
9237 * var bbox = turf.bbox(line);
9238 * var bboxPolygon = turf.bboxPolygon(bbox);
9239 *
9240 * //addToMap
9241 * var addToMap = [line, bboxPolygon]
9242 */
9243function turfBBox(geojson) {
9244 var bbox = [Infinity, Infinity, -Infinity, -Infinity];
9245 coordEach(geojson, function (coord) {
9246 if (bbox[0] > coord[0]) bbox[0] = coord[0];
9247 if (bbox[1] > coord[1]) bbox[1] = coord[1];
9248 if (bbox[2] < coord[0]) bbox[2] = coord[0];
9249 if (bbox[3] < coord[1]) bbox[3] = coord[1];
9250 });
9251 return bbox;
9252}
9253
9254/**
9255 * Creates a {@link FeatureCollection} of 2-vertex {@link LineString} segments from a {@link LineString|(Multi)LineString} or {@link Polygon|(Multi)Polygon}.
9256 *
9257 * @name lineSegment
9258 * @param {Geometry|FeatureCollection|Feature<LineString|MultiLineString|MultiPolygon|Polygon>} geojson GeoJSON Polygon or LineString
9259 * @returns {FeatureCollection<LineString>} 2-vertex line segments
9260 * @example
9261 * var polygon = turf.polygon([[[-50, 5], [-40, -10], [-50, -10], [-40, 5], [-50, 5]]]);
9262 * var segments = turf.lineSegment(polygon);
9263 *
9264 * //addToMap
9265 * var addToMap = [polygon, segments]
9266 */
9267function lineSegment(geojson) {
9268 if (!geojson) throw new Error('geojson is required');
9269
9270 var results = [];
9271 flattenEach(geojson, function (feature$$1) {
9272 lineSegmentFeature(feature$$1, results);
9273 });
9274 return featureCollection(results);
9275}
9276
9277/**
9278 * Line Segment
9279 *
9280 * @private
9281 * @param {Feature<LineString|Polygon>} geojson Line or polygon feature
9282 * @param {Array} results push to results
9283 * @returns {void}
9284 */
9285function lineSegmentFeature(geojson, results) {
9286 var coords = [];
9287 var geometry$$1 = geojson.geometry;
9288 switch (geometry$$1.type) {
9289 case 'Polygon':
9290 coords = getCoords(geometry$$1);
9291 break;
9292 case 'LineString':
9293 coords = [getCoords(geometry$$1)];
9294 }
9295 coords.forEach(function (coord) {
9296 var segments = createSegments(coord, geojson.properties);
9297 segments.forEach(function (segment) {
9298 segment.id = results.length;
9299 results.push(segment);
9300 });
9301 });
9302}
9303
9304/**
9305 * Create Segments from LineString coordinates
9306 *
9307 * @private
9308 * @param {LineString} coords LineString coordinates
9309 * @param {*} properties GeoJSON properties
9310 * @returns {Array<Feature<LineString>>} line segments
9311 */
9312function createSegments(coords, properties) {
9313 var segments = [];
9314 coords.reduce(function (previousCoords, currentCoords) {
9315 var segment = lineString([previousCoords, currentCoords], properties);
9316 segment.bbox = bbox$3(previousCoords, currentCoords);
9317 segments.push(segment);
9318 return currentCoords;
9319 });
9320 return segments;
9321}
9322
9323/**
9324 * Create BBox between two coordinates (faster than @turf/bbox)
9325 *
9326 * @private
9327 * @param {Array<number>} coords1 Point coordinate
9328 * @param {Array<number>} coords2 Point coordinate
9329 * @returns {BBox} [west, south, east, north]
9330 */
9331function bbox$3(coords1, coords2) {
9332 var x1 = coords1[0];
9333 var y1 = coords1[1];
9334 var x2 = coords2[0];
9335 var y2 = coords2[1];
9336 var west = (x1 < x2) ? x1 : x2;
9337 var south = (y1 < y2) ? y1 : y2;
9338 var east = (x1 > x2) ? x1 : x2;
9339 var north = (y1 > y2) ? y1 : y2;
9340 return [west, south, east, north];
9341}
9342
9343/**
9344 * Takes any LineString or Polygon GeoJSON and returns the intersecting point(s).
9345 *
9346 * @name lineIntersect
9347 * @param {Geometry|FeatureCollection|Feature<LineString|MultiLineString|Polygon|MultiPolygon>} line1 any LineString or Polygon
9348 * @param {Geometry|FeatureCollection|Feature<LineString|MultiLineString|Polygon|MultiPolygon>} line2 any LineString or Polygon
9349 * @returns {FeatureCollection<Point>} point(s) that intersect both
9350 * @example
9351 * var line1 = turf.lineString([[126, -11], [129, -21]]);
9352 * var line2 = turf.lineString([[123, -18], [131, -14]]);
9353 * var intersects = turf.lineIntersect(line1, line2);
9354 *
9355 * //addToMap
9356 * var addToMap = [line1, line2, intersects]
9357 */
9358function lineIntersect(line1, line2) {
9359 var unique = {};
9360 var results = [];
9361
9362 // First, normalize geometries to features
9363 // Then, handle simple 2-vertex segments
9364 if (line1.type === 'LineString') line1 = feature(line1);
9365 if (line2.type === 'LineString') line2 = feature(line2);
9366 if (line1.type === 'Feature' &&
9367 line2.type === 'Feature' &&
9368 line1.geometry.type === 'LineString' &&
9369 line2.geometry.type === 'LineString' &&
9370 line1.geometry.coordinates.length === 2 &&
9371 line2.geometry.coordinates.length === 2) {
9372 var intersect = intersects$3(line1, line2);
9373 if (intersect) results.push(intersect);
9374 return featureCollection(results);
9375 }
9376
9377 // Handles complex GeoJSON Geometries
9378 var tree = geojsonRbush();
9379 tree.load(lineSegment(line2));
9380 featureEach(lineSegment(line1), function (segment) {
9381 featureEach(tree.search(segment), function (match) {
9382 var intersect = intersects$3(segment, match);
9383 if (intersect) {
9384 // prevent duplicate points https://github.com/Turfjs/turf/issues/688
9385 var key = getCoords(intersect).join(',');
9386 if (!unique[key]) {
9387 unique[key] = true;
9388 results.push(intersect);
9389 }
9390 }
9391 });
9392 });
9393 return featureCollection(results);
9394}
9395
9396/**
9397 * Find a point that intersects LineStrings with two coordinates each
9398 *
9399 * @private
9400 * @param {Feature<LineString>} line1 GeoJSON LineString (Must only contain 2 coordinates)
9401 * @param {Feature<LineString>} line2 GeoJSON LineString (Must only contain 2 coordinates)
9402 * @returns {Feature<Point>} intersecting GeoJSON Point
9403 */
9404function intersects$3(line1, line2) {
9405 var coords1 = getCoords(line1);
9406 var coords2 = getCoords(line2);
9407 if (coords1.length !== 2) {
9408 throw new Error('<intersects> line1 must only contain 2 coordinates');
9409 }
9410 if (coords2.length !== 2) {
9411 throw new Error('<intersects> line2 must only contain 2 coordinates');
9412 }
9413 var x1 = coords1[0][0];
9414 var y1 = coords1[0][1];
9415 var x2 = coords1[1][0];
9416 var y2 = coords1[1][1];
9417 var x3 = coords2[0][0];
9418 var y3 = coords2[0][1];
9419 var x4 = coords2[1][0];
9420 var y4 = coords2[1][1];
9421 var denom = ((y4 - y3) * (x2 - x1)) - ((x4 - x3) * (y2 - y1));
9422 var numeA = ((x4 - x3) * (y1 - y3)) - ((y4 - y3) * (x1 - x3));
9423 var numeB = ((x2 - x1) * (y1 - y3)) - ((y2 - y1) * (x1 - x3));
9424
9425 if (denom === 0) {
9426 if (numeA === 0 && numeB === 0) {
9427 return null;
9428 }
9429 return null;
9430 }
9431
9432 var uA = numeA / denom;
9433 var uB = numeB / denom;
9434
9435 if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) {
9436 var x = x1 + (uA * (x2 - x1));
9437 var y = y1 + (uA * (y2 - y1));
9438 return point([x, y]);
9439 }
9440 return null;
9441}
9442
9443/**
9444 * Takes a {@link Point} and a {@link LineString} and calculates the closest Point on the (Multi)LineString.
9445 *
9446 * @name nearestPointOnLine
9447 * @param {Geometry|Feature<LineString|MultiLineString>} lines lines to snap to
9448 * @param {Geometry|Feature<Point>|number[]} pt point to snap from
9449 * @param {Object} [options={}] Optional parameters
9450 * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers
9451 * @returns {Feature<Point>} closest point on the `line` to `point`. The properties object will contain three values: `index`: closest point was found on nth line part, `dist`: distance between pt and the closest point, `location`: distance along the line between start and the closest point.
9452 * @example
9453 * var line = turf.lineString([
9454 * [-77.031669, 38.878605],
9455 * [-77.029609, 38.881946],
9456 * [-77.020339, 38.884084],
9457 * [-77.025661, 38.885821],
9458 * [-77.021884, 38.889563],
9459 * [-77.019824, 38.892368]
9460 * ]);
9461 * var pt = turf.point([-77.037076, 38.884017]);
9462 *
9463 * var snapped = turf.nearestPointOnLine(line, pt, {units: 'miles'});
9464 *
9465 * //addToMap
9466 * var addToMap = [line, pt, snapped];
9467 * snapped.properties['marker-color'] = '#00f';
9468 */
9469function nearestPointOnLine(lines, pt, options) {
9470 // Optional parameters
9471 options = options || {};
9472 if (!isObject(options)) throw new Error('options is invalid');
9473
9474 // validation
9475 var type = (lines.geometry) ? lines.geometry.type : lines.type;
9476 if (type !== 'LineString' && type !== 'MultiLineString') {
9477 throw new Error('lines must be LineString or MultiLineString');
9478 }
9479
9480 var closestPt = point([Infinity, Infinity], {
9481 dist: Infinity
9482 });
9483
9484 var length = 0.0;
9485 flattenEach(lines, function (line) {
9486 var coords = getCoords(line);
9487
9488 for (var i = 0; i < coords.length - 1; i++) {
9489 //start
9490 var start = point(coords[i]);
9491 start.properties.dist = distance(pt, start, options);
9492 //stop
9493 var stop = point(coords[i + 1]);
9494 stop.properties.dist = distance(pt, stop, options);
9495 // sectionLength
9496 var sectionLength = distance(start, stop, options);
9497 //perpendicular
9498 var heightDistance = Math.max(start.properties.dist, stop.properties.dist);
9499 var direction = bearing(start, stop);
9500 var perpendicularPt1 = destination(pt, heightDistance, direction + 90, options);
9501 var perpendicularPt2 = destination(pt, heightDistance, direction - 90, options);
9502 var intersect = lineIntersect(
9503 lineString([perpendicularPt1.geometry.coordinates, perpendicularPt2.geometry.coordinates]),
9504 lineString([start.geometry.coordinates, stop.geometry.coordinates])
9505 );
9506 var intersectPt = null;
9507 if (intersect.features.length > 0) {
9508 intersectPt = intersect.features[0];
9509 intersectPt.properties.dist = distance(pt, intersectPt, options);
9510 intersectPt.properties.location = length + distance(start, intersectPt, options);
9511 }
9512
9513 if (start.properties.dist < closestPt.properties.dist) {
9514 closestPt = start;
9515 closestPt.properties.index = i;
9516 closestPt.properties.location = length;
9517 }
9518 if (stop.properties.dist < closestPt.properties.dist) {
9519 closestPt = stop;
9520 closestPt.properties.index = i + 1;
9521 closestPt.properties.location = length + sectionLength;
9522 }
9523 if (intersectPt && intersectPt.properties.dist < closestPt.properties.dist) {
9524 closestPt = intersectPt;
9525 closestPt.properties.index = i;
9526 }
9527 // update length
9528 length += sectionLength;
9529 }
9530
9531 });
9532
9533 return closestPt;
9534}
9535
9536// https://en.wikipedia.org/wiki/Rhumb_line
9537/**
9538 * Takes two {@link Point|points} and finds the bearing angle between them along a Rhumb line
9539 * i.e. the angle measured in degrees start the north line (0 degrees)
9540 *
9541 * @name rhumbBearing
9542 * @param {Coord} start starting Point
9543 * @param {Coord} end ending Point
9544 * @param {Object} [options] Optional parameters
9545 * @param {boolean} [options.final=false] calculates the final bearing if true
9546 * @returns {number} bearing from north in decimal degrees, between -180 and 180 degrees (positive clockwise)
9547 * @example
9548 * var point1 = turf.point([-75.343, 39.984], {"marker-color": "#F00"});
9549 * var point2 = turf.point([-75.534, 39.123], {"marker-color": "#00F"});
9550 *
9551 * var bearing = turf.rhumbBearing(point1, point2);
9552 *
9553 * //addToMap
9554 * var addToMap = [point1, point2];
9555 * point1.properties.bearing = bearing;
9556 * point2.properties.bearing = bearing;
9557 */
9558function rhumbBearing(start, end, options) {
9559 // Optional parameters
9560 options = options || {};
9561 if (!isObject(options)) throw new Error('options is invalid');
9562 var final = options.final;
9563
9564 // validation
9565 if (!start) throw new Error('start point is required');
9566 if (!end) throw new Error('end point is required');
9567
9568 var bear360;
9569
9570 if (final) bear360 = calculateRhumbBearing(getCoord(end), getCoord(start));
9571 else bear360 = calculateRhumbBearing(getCoord(start), getCoord(end));
9572
9573 var bear180 = (bear360 > 180) ? -(360 - bear360) : bear360;
9574
9575 return bear180;
9576}
9577
9578/**
9579 * Returns the bearing from ‘this’ point to destination point along a rhumb line.
9580 * Adapted from Geodesy: https://github.com/chrisveness/geodesy/blob/master/latlon-spherical.js
9581 *
9582 * @private
9583 * @param {Array<number>} from - origin point.
9584 * @param {Array<number>} to - destination point.
9585 * @returns {number} Bearing in degrees from north.
9586 * @example
9587 * var p1 = new LatLon(51.127, 1.338);
9588 * var p2 = new LatLon(50.964, 1.853);
9589 * var d = p1.rhumbBearingTo(p2); // 116.7 m
9590 */
9591function calculateRhumbBearing(from, to) {
9592 // φ => phi
9593 // Δλ => deltaLambda
9594 // Δψ => deltaPsi
9595 // θ => theta
9596 var phi1 = degreesToRadians(from[1]);
9597 var phi2 = degreesToRadians(to[1]);
9598 var deltaLambda = degreesToRadians((to[0] - from[0]));
9599 // if deltaLambdaon over 180° take shorter rhumb line across the anti-meridian:
9600 if (deltaLambda > Math.PI) deltaLambda -= 2 * Math.PI;
9601 if (deltaLambda < -Math.PI) deltaLambda += 2 * Math.PI;
9602
9603 var deltaPsi = Math.log(Math.tan(phi2 / 2 + Math.PI / 4) / Math.tan(phi1 / 2 + Math.PI / 4));
9604
9605 var theta = Math.atan2(deltaLambda, deltaPsi);
9606
9607 return (radiansToDegrees(theta) + 360) % 360;
9608}
9609
9610// https://en.wikipedia.org/wiki/Rhumb_line
9611/**
9612 * Calculates the distance along a rhumb line between two {@link Point|points} in degrees, radians,
9613 * miles, or kilometers.
9614 *
9615 * @name rhumbDistance
9616 * @param {Coord} from origin point
9617 * @param {Coord} to destination point
9618 * @param {Object} [options] Optional parameters
9619 * @param {string} [options.units="kilometers"] can be degrees, radians, miles, or kilometers
9620 * @returns {number} distance between the two points
9621 * @example
9622 * var from = turf.point([-75.343, 39.984]);
9623 * var to = turf.point([-75.534, 39.123]);
9624 * var options = {units: 'miles'};
9625 *
9626 * var distance = turf.rhumbDistance(from, to, options);
9627 *
9628 * //addToMap
9629 * var addToMap = [from, to];
9630 * from.properties.distance = distance;
9631 * to.properties.distance = distance;
9632 */
9633function rhumbDistance(from, to, options) {
9634 // Optional parameters
9635 options = options || {};
9636 if (!isObject(options)) throw new Error('options is invalid');
9637 var units = options.units;
9638
9639 // validation
9640 if (!from) throw new Error('from point is required');
9641 if (!to) throw new Error('to point is required');
9642
9643 var origin = getCoord(from);
9644 var destination = getCoord(to);
9645
9646 // compensate the crossing of the 180th meridian (https://macwright.org/2016/09/26/the-180th-meridian.html)
9647 // solution from https://github.com/mapbox/mapbox-gl-js/issues/3250#issuecomment-294887678
9648 destination[0] += (destination[0] - origin[0] > 180) ? -360 : (origin[0] - destination[0] > 180) ? 360 : 0;
9649 var distanceInMeters = calculateRhumbDistance(origin, destination);
9650 var distance = convertLength(distanceInMeters, 'meters', units);
9651 return distance;
9652}
9653
9654/**
9655 * Returns the distance travelling from ‘this’ point to destination point along a rhumb line.
9656 * Adapted from Geodesy: https://github.com/chrisveness/geodesy/blob/master/latlon-spherical.js
9657 *
9658 * @private
9659 * @param {Array<number>} origin point.
9660 * @param {Array<number>} destination point.
9661 * @param {number} [radius=6371e3] - (Mean) radius of earth (defaults to radius in metres).
9662 * @returns {number} Distance in km between this point and destination point (same units as radius).
9663 *
9664 * @example
9665 * var p1 = new LatLon(51.127, 1.338);
9666 * var p2 = new LatLon(50.964, 1.853);
9667 * var d = p1.distanceTo(p2); // 40.31 km
9668 */
9669function calculateRhumbDistance(origin, destination, radius) {
9670 // φ => phi
9671 // λ => lambda
9672 // ψ => psi
9673 // Δ => Delta
9674 // δ => delta
9675 // θ => theta
9676
9677 radius = (radius === undefined) ? earthRadius : Number(radius);
9678 // see www.edwilliams.org/avform.htm#Rhumb
9679
9680 var R = radius;
9681 var phi1 = origin[1] * Math.PI / 180;
9682 var phi2 = destination[1] * Math.PI / 180;
9683 var DeltaPhi = phi2 - phi1;
9684 var DeltaLambda = Math.abs(destination[0] - origin[0]) * Math.PI / 180;
9685 // if dLon over 180° take shorter rhumb line across the anti-meridian:
9686 if (DeltaLambda > Math.PI) DeltaLambda -= 2 * Math.PI;
9687
9688 // on Mercator projection, longitude distances shrink by latitude; q is the 'stretch factor'
9689 // q becomes ill-conditioned along E-W line (0/0); use empirical tolerance to avoid it
9690 var DeltaPsi = Math.log(Math.tan(phi2 / 2 + Math.PI / 4) / Math.tan(phi1 / 2 + Math.PI / 4));
9691 var q = Math.abs(DeltaPsi) > 10e-12 ? DeltaPhi / DeltaPsi : Math.cos(phi1);
9692
9693 // distance is pythagoras on 'stretched' Mercator projection
9694 var delta = Math.sqrt(DeltaPhi * DeltaPhi + q * q * DeltaLambda * DeltaLambda); // angular distance in radians
9695 var dist = delta * R;
9696
9697 return dist;
9698}
9699
9700/**
9701 * Converts a WGS84 GeoJSON object into Mercator (EPSG:900913) projection
9702 *
9703 * @name toMercator
9704 * @param {GeoJSON|Position} geojson WGS84 GeoJSON object
9705 * @param {Object} [options] Optional parameters
9706 * @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated (significant performance increase if true)
9707 * @returns {GeoJSON} true/false
9708 * @example
9709 * var pt = turf.point([-71,41]);
9710 * var converted = turf.toMercator(pt);
9711 *
9712 * //addToMap
9713 * var addToMap = [pt, converted];
9714 */
9715function toMercator(geojson, options) {
9716 return convert(geojson, 'mercator', options);
9717}
9718
9719/**
9720 * Converts a Mercator (EPSG:900913) GeoJSON object into WGS84 projection
9721 *
9722 * @name toWgs84
9723 * @param {GeoJSON|Position} geojson Mercator GeoJSON object
9724 * @param {Object} [options] Optional parameters
9725 * @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated (significant performance increase if true)
9726 * @returns {GeoJSON} true/false
9727 * @example
9728 * var pt = turf.point([-7903683.846322424, 5012341.663847514]);
9729 * var converted = turf.toWgs84(pt);
9730 *
9731 * //addToMap
9732 * var addToMap = [pt, converted];
9733 */
9734function toWgs84(geojson, options) {
9735 return convert(geojson, 'wgs84', options);
9736}
9737
9738
9739/**
9740 * Converts a GeoJSON coordinates to the defined `projection`
9741 *
9742 * @private
9743 * @param {GeoJSON} geojson GeoJSON Feature or Geometry
9744 * @param {string} projection defines the projection system to convert the coordinates to
9745 * @param {Object} [options] Optional parameters
9746 * @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated (significant performance increase if true)
9747 * @returns {GeoJSON} true/false
9748 */
9749function convert(geojson, projection, options) {
9750 // Optional parameters
9751 options = options || {};
9752 if (!isObject(options)) throw new Error('options is invalid');
9753 var mutate = options.mutate;
9754
9755 // Validation
9756 if (!geojson) throw new Error('geojson is required');
9757
9758 // Handle Position
9759 if (Array.isArray(geojson) && isNumber(geojson[0])) geojson = (projection === 'mercator') ? convertToMercator(geojson) : convertToWgs84(geojson);
9760
9761 // Handle GeoJSON
9762 else {
9763 // Handle possible data mutation
9764 if (mutate !== true) geojson = clone(geojson);
9765
9766 coordEach(geojson, function (coord) {
9767 var newCoord = (projection === 'mercator') ? convertToMercator(coord) : convertToWgs84(coord);
9768 coord[0] = newCoord[0];
9769 coord[1] = newCoord[1];
9770 });
9771 }
9772 return geojson;
9773}
9774
9775/**
9776 * Convert lon/lat values to 900913 x/y.
9777 * (from https://github.com/mapbox/sphericalmercator)
9778 *
9779 * @private
9780 * @param {Array<number>} lonLat WGS84 point
9781 * @returns {Array<number>} Mercator [x, y] point
9782 */
9783function convertToMercator(lonLat) {
9784 var D2R = Math.PI / 180,
9785 // 900913 properties
9786 A = 6378137.0,
9787 MAXEXTENT = 20037508.342789244;
9788
9789 // compensate longitudes passing the 180th meridian
9790 // from https://github.com/proj4js/proj4js/blob/master/lib/common/adjust_lon.js
9791 var adjusted = (Math.abs(lonLat[0]) <= 180) ? lonLat[0] : (lonLat[0] - (sign(lonLat[0]) * 360));
9792 var xy = [
9793 A * adjusted * D2R,
9794 A * Math.log(Math.tan((Math.PI * 0.25) + (0.5 * lonLat[1] * D2R)))
9795 ];
9796
9797 // if xy value is beyond maxextent (e.g. poles), return maxextent
9798 if (xy[0] > MAXEXTENT) xy[0] = MAXEXTENT;
9799 if (xy[0] < -MAXEXTENT) xy[0] = -MAXEXTENT;
9800 if (xy[1] > MAXEXTENT) xy[1] = MAXEXTENT;
9801 if (xy[1] < -MAXEXTENT) xy[1] = -MAXEXTENT;
9802
9803 return xy;
9804}
9805
9806/**
9807 * Convert 900913 x/y values to lon/lat.
9808 * (from https://github.com/mapbox/sphericalmercator)
9809 *
9810 * @private
9811 * @param {Array<number>} xy Mercator [x, y] point
9812 * @returns {Array<number>} WGS84 [lon, lat] point
9813 */
9814function convertToWgs84(xy) {
9815 // 900913 properties.
9816 var R2D = 180 / Math.PI;
9817 var A = 6378137.0;
9818
9819 return [
9820 (xy[0] * R2D / A),
9821 ((Math.PI * 0.5) - 2.0 * Math.atan(Math.exp(-xy[1] / A))) * R2D
9822 ];
9823}
9824
9825/**
9826 * Returns the sign of the input, or zero
9827 *
9828 * @private
9829 * @param {number} x input
9830 * @returns {number} -1|0|1 output
9831 */
9832function sign(x) {
9833 return (x < 0) ? -1 : (x > 0) ? 1 : 0;
9834}
9835
9836
9837
9838
9839var main_es$3 = Object.freeze({
9840 toMercator: toMercator,
9841 toWgs84: toWgs84
9842});
9843
9844// (logic of computation inspired by:
9845// https://stackoverflow.com/questions/32771458/distance-from-lat-lng-point-to-minor-arc-segment)
9846
9847/**
9848 * Returns the minimum distance between a {@link Point} and a {@link LineString}, being the distance from a line the
9849 * minimum distance between the point and any segment of the `LineString`.
9850 *
9851 * @name pointToLineDistance
9852 * @param {Coord} pt Feature or Geometry
9853 * @param {Feature<LineString>} line GeoJSON Feature or Geometry
9854 * @param {Object} [options={}] Optional parameters
9855 * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers
9856 * @param {boolean} [options.mercator=false] if distance should be on Mercator or WGS84 projection
9857 * @returns {number} distance between point and line
9858 * @example
9859 * var pt = turf.point([0, 0]);
9860 * var line = turf.lineString([[1, 1],[-1, 1]]);
9861 *
9862 * var distance = turf.pointToLineDistance(pt, line, {units: 'miles'});
9863 * //=69.11854715938406
9864 */
9865function pointToLineDistance(pt, line, options) {
9866 // Optional parameters
9867 options = options || {};
9868 if (!isObject(options)) throw new Error('options is invalid');
9869
9870 // validation
9871 if (!pt) throw new Error('pt is required');
9872 if (Array.isArray(pt)) pt = point(pt);
9873 else if (pt.type === 'Point') pt = feature(pt);
9874 else featureOf(pt, 'Point', 'point');
9875
9876 if (!line) throw new Error('line is required');
9877 if (Array.isArray(line)) line = lineString(line);
9878 else if (line.type === 'LineString') line = feature(line);
9879 else featureOf(line, 'LineString', 'line');
9880
9881 var distance$$1 = Infinity;
9882 var p = pt.geometry.coordinates;
9883 segmentEach(line, function (segment) {
9884 var a = segment.geometry.coordinates[0];
9885 var b = segment.geometry.coordinates[1];
9886 var d = distanceToSegment(p, a, b, options);
9887 if (distance$$1 > d) distance$$1 = d;
9888 });
9889 return distance$$1;
9890}
9891
9892
9893/**
9894 * Returns the distance between a point P on a segment AB.
9895 *
9896 * @private
9897 * @param {Array<number>} p external point
9898 * @param {Array<number>} a first segment point
9899 * @param {Array<number>} b second segment point
9900 * @param {Object} [options={}] Optional parameters
9901 * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers
9902 * @param {boolean} [options.mercator=false] if distance should be on Mercator or WGS84 projection
9903 * @returns {number} distance
9904 */
9905function distanceToSegment(p, a, b, options) {
9906 var mercator = options.mercator;
9907 var distanceAP = (mercator !== true) ? distance(a, p, options) : euclideanDistance(a, p, options);
9908 var azimuthAP = bearingToAzimuth((mercator !== true) ? bearing(a, p) : rhumbBearing(a, p));
9909 var azimuthAB = bearingToAzimuth((mercator !== true) ? bearing(a, b) : rhumbBearing(a, b));
9910 var angleA = Math.abs(azimuthAP - azimuthAB);
9911 // if (angleA > 180) angleA = Math.abs(angleA - 360);
9912 // if the angle PAB is obtuse its projection on the line extending the segment falls outside the segment
9913 // thus return distance between P and the start point A
9914 /*
9915 P__
9916 |\ \____
9917 | \ \____
9918 | \ \____
9919 | \_____________\
9920 H A B
9921 */
9922 if (angleA > 90) return distanceAP;
9923
9924 var azimuthBA = (azimuthAB + 180) % 360;
9925 var azimuthBP = bearingToAzimuth((mercator !== true) ? bearing(b, p) : rhumbBearing(b, p));
9926 var angleB = Math.abs(azimuthBP - azimuthBA);
9927 if (angleB > 180) angleB = Math.abs(angleB - 360);
9928 // also if the angle ABP is acute the projection of P falls outside the segment, on the other side
9929 // so return the distance between P and the end point B
9930 /*
9931 ____P
9932 ____/ /|
9933 ____/ / |
9934 ____/ / |
9935 /______________/ |
9936 A B H
9937 */
9938 if (angleB > 90) return (mercator !== true) ? distance(p, b, options) : euclideanDistance(p, b, options);
9939 // finally if the projection falls inside the segment
9940 // return the distance between P and the segment
9941 /*
9942 P
9943 __/|\
9944 __/ | \
9945 __/ | \
9946 __/ | \
9947 /____________|____\
9948 A H B
9949 */
9950 if (mercator !== true) return distanceAP * Math.sin(degreesToRadians(angleA));
9951 return mercatorPH(a, b, p, options);
9952}
9953
9954/**
9955 * Returns the distance between a point P on a segment AB, on Mercator projection
9956 *
9957 * @private
9958 * @param {Array<number>} a first segment point
9959 * @param {Array<number>} b second segment point
9960 * @param {Array<number>} p external point
9961 * @param {Object} [options={}] Optional parameters
9962 * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers
9963 * @returns {number} distance
9964 */
9965function mercatorPH(a, b, p, options) {
9966 var delta = 0;
9967 // translate points if any is crossing the 180th meridian
9968 if (Math.abs(a[0]) >= 180 || Math.abs(b[0]) >= 180 || Math.abs(p[0]) >= 180) {
9969 delta = (a[0] > 0 || b[0] > 0 || p[0] > 0) ? -180 : 180;
9970 }
9971
9972 var origin = point(p);
9973 var A = toMercator([a[0] + delta, a[1]]);
9974 var B = toMercator([b[0] + delta, b[1]]);
9975 var P = toMercator([p[0] + delta, p[1]]);
9976 var h = toWgs84(euclideanIntersection(A, B, P));
9977
9978 if (delta !== 0) h[0] -= delta; // translate back to original position
9979 var distancePH = rhumbDistance(origin, h, options);
9980 return distancePH;
9981}
9982
9983/**
9984 * Returns the point H projection of a point P on a segment AB, on the euclidean plain
9985 * from https://stackoverflow.com/questions/10301001/perpendicular-on-a-line-segment-from-a-given-point#answer-12499474
9986 * P
9987 * |
9988 * |
9989 * _________|____
9990 * A H B
9991 *
9992 * @private
9993 * @param {Array<number>} a first segment point
9994 * @param {Array<number>} b second segment point
9995 * @param {Array<number>} p external point
9996 * @returns {Array<number>} projected point
9997 */
9998function euclideanIntersection(a, b, p) {
9999 var x1 = a[0], y1 = a[1],
10000 x2 = b[0], y2 = b[1],
10001 x3 = p[0], y3 = p[1];
10002 var px = x2 - x1, py = y2 - y1;
10003 var dab = px * px + py * py;
10004 var u = ((x3 - x1) * px + (y3 - y1) * py) / dab;
10005 var x = x1 + u * px, y = y1 + u * py;
10006 return [x, y]; // H
10007}
10008
10009/**
10010 * Returns euclidean distance between two points
10011 *
10012 * @private
10013 * @param {Object} from first point
10014 * @param {Object} to second point
10015 * @param {Object} [options={}] Optional parameters
10016 * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers
10017 * @returns {number} squared distance
10018 */
10019function euclideanDistance(from, to, options) {
10020 var units = options.units;
10021 // translate points if any is crossing the 180th meridian
10022 var delta = 0;
10023 if (Math.abs(from[0]) >= 180) {
10024 delta = (from[0] > 0) ? -180 : 180;
10025 }
10026 if (Math.abs(to[0]) >= 180) {
10027 delta = (to[0] > 0) ? -180 : 180;
10028 }
10029 var p1 = toMercator([from[0] + delta, from[1]]);
10030 var p2 = toMercator([to[0] + delta, to[1]]);
10031
10032 var sqr = function (n) { return n * n; };
10033 var squareD = sqr(p1[0] - p2[0]) + sqr(p1[1] - p2[1]);
10034 var d = Math.sqrt(squareD);
10035 return convertLength(d, 'meters', units);
10036}
10037
10038/**
10039 * Returns the closest {@link Point|point}, of a {@link FeatureCollection|collection} of points, to a {@link LineString|line}.
10040 * The returned point has a `dist` property indicating its distance to the line.
10041 *
10042 * @name nearestPointToLine
10043 * @param {FeatureCollection|GeometryCollection<Point>} points Point Collection
10044 * @param {Feature|Geometry<LineString>} line Line Feature
10045 * @param {Object} [options] Optional parameters
10046 * @param {string} [options.units='kilometers'] unit of the output distance property, can be degrees, radians, miles, or kilometers
10047 * @param {Object} [options.properties={}] Translate Properties to Point
10048 * @returns {Feature<Point>} the closest point
10049 * @example
10050 * var pt1 = turf.point([0, 0]);
10051 * var pt2 = turf.point([0.5, 0.5]);
10052 * var points = turf.featureCollection([pt1, pt2]);
10053 * var line = turf.lineString([[1,1], [-1,1]]);
10054 *
10055 * var nearest = turf.nearestPointToLine(points, line);
10056 *
10057 * //addToMap
10058 * var addToMap = [nearest, line];
10059 */
10060function nearestPointToLine(points$$1, line, options) {
10061 options = options || {};
10062 if (!isObject(options)) throw new Error('options is invalid');
10063 var units = options.units;
10064 var properties = options.properties || {};
10065
10066 // validation
10067 if (!points$$1) throw new Error('points is required');
10068 points$$1 = normalize(points$$1);
10069 if (!points$$1.features.length) throw new Error('points must contain features');
10070
10071 if (!line) throw new Error('line is required');
10072 if (getType(line) !== 'LineString') throw new Error('line must be a LineString');
10073
10074 var dist = Infinity;
10075 var pt = null;
10076
10077 featureEach(points$$1, function (point$$1) {
10078 var d = pointToLineDistance(point$$1, line, { units: units });
10079 if (d < dist) {
10080 dist = d;
10081 pt = point$$1;
10082 }
10083 });
10084 /**
10085 * Translate Properties to final Point, priorities:
10086 * 1. options.properties
10087 * 2. inherent Point properties
10088 * 3. dist custom properties created by NearestPointToLine
10089 */
10090 if (pt) pt.properties = Object.assign({dist: dist}, pt.properties, properties);
10091 return pt;
10092}
10093
10094/**
10095 * Convert Collection to FeatureCollection
10096 *
10097 * @private
10098 * @param {FeatureCollection|GeometryCollection<Point>} points Points
10099 * @returns {FeatureCollection<Point>} points
10100 */
10101function normalize(points$$1) {
10102 var features = [];
10103 var type = points$$1.geometry ? points$$1.geometry.type : points$$1.type;
10104 switch (type) {
10105 case 'GeometryCollection':
10106 geomEach(points$$1, function (geom) {
10107 if (geom.type === 'Point') features.push({type: 'Feature', properties: {}, geometry: geom});
10108 });
10109 return {type: 'FeatureCollection', features: features};
10110 case 'FeatureCollection':
10111 points$$1.features = points$$1.features.filter(function (feature$$1) {
10112 return feature$$1.geometry.type === 'Point';
10113 });
10114 return points$$1;
10115 default:
10116 throw new Error('points must be a Point Collection');
10117 }
10118}
10119
10120/**
10121 * Takes a triangular plane as a {@link Polygon}
10122 * and a {@link Point} within that triangle and returns the z-value
10123 * at that point. The Polygon should have properties `a`, `b`, and `c`
10124 * that define the values at its three corners. Alternatively, the z-values
10125 * of each triangle point can be provided by their respective 3rd coordinate
10126 * if their values are not provided as properties.
10127 *
10128 * @name planepoint
10129 * @param {Coord} point the Point for which a z-value will be calculated
10130 * @param {Feature<Polygon>} triangle a Polygon feature with three vertices
10131 * @returns {number} the z-value for `interpolatedPoint`
10132 * @example
10133 * var point = turf.point([-75.3221, 39.529]);
10134 * // "a", "b", and "c" values represent the values of the coordinates in order.
10135 * var triangle = turf.polygon([[
10136 * [-75.1221, 39.57],
10137 * [-75.58, 39.18],
10138 * [-75.97, 39.86],
10139 * [-75.1221, 39.57]
10140 * ]], {
10141 * "a": 11,
10142 * "b": 122,
10143 * "c": 44
10144 * });
10145 *
10146 * var zValue = turf.planepoint(point, triangle);
10147 * point.properties.zValue = zValue;
10148 *
10149 * //addToMap
10150 * var addToMap = [triangle, point];
10151 */
10152function planepoint(point, triangle) {
10153 // Normalize input
10154 var coord = getCoord(point);
10155 var geom = getGeom(triangle);
10156 var coords = geom.coordinates;
10157 var outer = coords[0];
10158 if (outer.length < 4) throw new Error('OuterRing of a Polygon must have 4 or more Positions.');
10159 var properties = triangle.properties || {};
10160 var a = properties.a;
10161 var b = properties.b;
10162 var c = properties.c;
10163
10164 // Planepoint
10165 var x = coord[0];
10166 var y = coord[1];
10167 var x1 = outer[0][0];
10168 var y1 = outer[0][1];
10169 var z1 = (a !== undefined ? a : outer[0][2]);
10170 var x2 = outer[1][0];
10171 var y2 = outer[1][1];
10172 var z2 = (b !== undefined ? b : outer[1][2]);
10173 var x3 = outer[2][0];
10174 var y3 = outer[2][1];
10175 var z3 = (c !== undefined ? c : outer[2][2]);
10176 var z = (z3 * (x - x1) * (y - y2) + z1 * (x - x2) * (y - y3) + z2 * (x - x3) * (y - y1) -
10177 z2 * (x - x1) * (y - y3) - z3 * (x - x2) * (y - y1) - z1 * (x - x3) * (y - y2)) /
10178 ((x - x1) * (y - y2) + (x - x2) * (y - y3) + (x - x3) * (y - y1) -
10179 (x - x1) * (y - y3) - (x - x2) * (y - y1) - (x - x3) * (y - y2));
10180
10181 return z;
10182}
10183
10184/**
10185 * Takes a {@link LineString|linestring}, {@link MultiLineString|multi-linestring}, {@link MultiPolygon|multi-polygon}, or {@link Polygon|polygon} and returns {@link Point|points} at all self-intersections.
10186 *
10187 * @name kinks
10188 * @param {Feature<LineString|MultiLineString|MultiPolygon|Polygon>} featureIn input feature
10189 * @returns {FeatureCollection<Point>} self-intersections
10190 * @example
10191 * var poly = turf.polygon([[
10192 * [-12.034835, 8.901183],
10193 * [-12.060413, 8.899826],
10194 * [-12.03638, 8.873199],
10195 * [-12.059383, 8.871418],
10196 * [-12.034835, 8.901183]
10197 * ]]);
10198 *
10199 * var kinks = turf.kinks(poly);
10200 *
10201 * //addToMap
10202 * var addToMap = [poly, kinks]
10203 */
10204function kinks(featureIn) {
10205 var coordinates;
10206 var feature$$1;
10207 var results = {
10208 type: 'FeatureCollection',
10209 features: []
10210 };
10211 if (featureIn.type === 'Feature') {
10212 feature$$1 = featureIn.geometry;
10213 } else {
10214 feature$$1 = featureIn;
10215 }
10216 if (feature$$1.type === 'LineString') {
10217 coordinates = [feature$$1.coordinates];
10218 } else if (feature$$1.type === 'MultiLineString') {
10219 coordinates = feature$$1.coordinates;
10220 } else if (feature$$1.type === 'MultiPolygon') {
10221 coordinates = [].concat.apply([], feature$$1.coordinates);
10222 } else if (feature$$1.type === 'Polygon') {
10223 coordinates = feature$$1.coordinates;
10224 } else {
10225 throw new Error('Input must be a LineString, MultiLineString, ' +
10226 'Polygon, or MultiPolygon Feature or Geometry');
10227 }
10228 coordinates.forEach(function (line1) {
10229 coordinates.forEach(function (line2) {
10230 for (var i = 0; i < line1.length - 1; i++) {
10231 // start iteration at i, intersections for k < i have already been checked in previous outer loop iterations
10232 for (var k = i; k < line2.length - 1; k++) {
10233 if (line1 === line2) {
10234 // segments are adjacent and always share a vertex, not a kink
10235 if (Math.abs(i - k) === 1) {
10236 continue;
10237 }
10238 // first and last segment in a closed lineString or ring always share a vertex, not a kink
10239 if (
10240 // segments are first and last segment of lineString
10241 i === 0 &&
10242 k === line1.length - 2 &&
10243 // lineString is closed
10244 line1[i][0] === line1[line1.length - 1][0] &&
10245 line1[i][1] === line1[line1.length - 1][1]
10246 ) {
10247 continue;
10248 }
10249 }
10250
10251 var intersection = lineIntersects(line1[i][0], line1[i][1], line1[i + 1][0], line1[i + 1][1],
10252 line2[k][0], line2[k][1], line2[k + 1][0], line2[k + 1][1]);
10253 if (intersection) {
10254 results.features.push(point([intersection[0], intersection[1]]));
10255 }
10256 }
10257 }
10258 });
10259 });
10260 return results;
10261}
10262
10263
10264// modified from http://jsfiddle.net/justin_c_rounds/Gd2S2/light/
10265function lineIntersects(line1StartX, line1StartY, line1EndX, line1EndY, line2StartX, line2StartY, line2EndX, line2EndY) {
10266 // if the lines intersect, the result contains the x and y of the intersection (treating the lines as infinite) and booleans for whether line segment 1 or line segment 2 contain the point
10267 var denominator, a, b, numerator1, numerator2,
10268 result = {
10269 x: null,
10270 y: null,
10271 onLine1: false,
10272 onLine2: false
10273 };
10274 denominator = ((line2EndY - line2StartY) * (line1EndX - line1StartX)) - ((line2EndX - line2StartX) * (line1EndY - line1StartY));
10275 if (denominator === 0) {
10276 if (result.x !== null && result.y !== null) {
10277 return result;
10278 } else {
10279 return false;
10280 }
10281 }
10282 a = line1StartY - line2StartY;
10283 b = line1StartX - line2StartX;
10284 numerator1 = ((line2EndX - line2StartX) * a) - ((line2EndY - line2StartY) * b);
10285 numerator2 = ((line1EndX - line1StartX) * a) - ((line1EndY - line1StartY) * b);
10286 a = numerator1 / denominator;
10287 b = numerator2 / denominator;
10288
10289 // if we cast these lines infinitely in both directions, they intersect here:
10290 result.x = line1StartX + (a * (line1EndX - line1StartX));
10291 result.y = line1StartY + (a * (line1EndY - line1StartY));
10292
10293 // if line1 is a segment and line2 is infinite, they intersect if:
10294 if (a >= 0 && a <= 1) {
10295 result.onLine1 = true;
10296 }
10297 // if line2 is a segment and line1 is infinite, they intersect if:
10298 if (b >= 0 && b <= 1) {
10299 result.onLine2 = true;
10300 }
10301 // if line1 and line2 are segments, they intersect if both of the above are true
10302 if (result.onLine1 && result.onLine2) {
10303 return [result.x, result.y];
10304 } else {
10305 return false;
10306 }
10307}
10308
10309/**
10310 * Takes a Feature or FeatureCollection and returns a {@link Point} guaranteed to be on the surface of the feature.
10311 *
10312 * * Given a {@link Polygon}, the point will be in the area of the polygon
10313 * * Given a {@link LineString}, the point will be along the string
10314 * * Given a {@link Point}, the point will the same as the input
10315 *
10316 * @name pointOnFeature
10317 * @param {GeoJSON} geojson any Feature or FeatureCollection
10318 * @returns {Feature<Point>} a point on the surface of `input`
10319 * @example
10320 * var polygon = turf.polygon([[
10321 * [116, -36],
10322 * [131, -32],
10323 * [146, -43],
10324 * [155, -25],
10325 * [133, -9],
10326 * [111, -22],
10327 * [116, -36]
10328 * ]]);
10329 *
10330 * var pointOnPolygon = turf.pointOnFeature(polygon);
10331 *
10332 * //addToMap
10333 * var addToMap = [polygon, pointOnPolygon];
10334 */
10335function pointOnFeature(geojson) {
10336 // normalize
10337 var fc = normalize$1(geojson);
10338
10339 // get centroid
10340 var cent = center(fc);
10341
10342 // check to see if centroid is on surface
10343 var onSurface = false;
10344 var i = 0;
10345 while (!onSurface && i < fc.features.length) {
10346 var geom = fc.features[i].geometry;
10347 var x, y, x1, y1, x2, y2, k;
10348 var onLine = false;
10349 if (geom.type === 'Point') {
10350 if (cent.geometry.coordinates[0] === geom.coordinates[0] &&
10351 cent.geometry.coordinates[1] === geom.coordinates[1]) {
10352 onSurface = true;
10353 }
10354 } else if (geom.type === 'MultiPoint') {
10355 var onMultiPoint = false;
10356 k = 0;
10357 while (!onMultiPoint && k < geom.coordinates.length) {
10358 if (cent.geometry.coordinates[0] === geom.coordinates[k][0] &&
10359 cent.geometry.coordinates[1] === geom.coordinates[k][1]) {
10360 onSurface = true;
10361 onMultiPoint = true;
10362 }
10363 k++;
10364 }
10365 } else if (geom.type === 'LineString') {
10366 k = 0;
10367 while (!onLine && k < geom.coordinates.length - 1) {
10368 x = cent.geometry.coordinates[0];
10369 y = cent.geometry.coordinates[1];
10370 x1 = geom.coordinates[k][0];
10371 y1 = geom.coordinates[k][1];
10372 x2 = geom.coordinates[k + 1][0];
10373 y2 = geom.coordinates[k + 1][1];
10374 if (pointOnSegment(x, y, x1, y1, x2, y2)) {
10375 onLine = true;
10376 onSurface = true;
10377 }
10378 k++;
10379 }
10380 } else if (geom.type === 'MultiLineString') {
10381 var j = 0;
10382 while (j < geom.coordinates.length) {
10383 onLine = false;
10384 k = 0;
10385 var line = geom.coordinates[j];
10386 while (!onLine && k < line.length - 1) {
10387 x = cent.geometry.coordinates[0];
10388 y = cent.geometry.coordinates[1];
10389 x1 = line[k][0];
10390 y1 = line[k][1];
10391 x2 = line[k + 1][0];
10392 y2 = line[k + 1][1];
10393 if (pointOnSegment(x, y, x1, y1, x2, y2)) {
10394 onLine = true;
10395 onSurface = true;
10396 }
10397 k++;
10398 }
10399 j++;
10400 }
10401 } else if (geom.type === 'Polygon' || geom.type === 'MultiPolygon') {
10402 if (booleanPointInPolygon(cent, geom)) {
10403 onSurface = true;
10404 }
10405 }
10406 i++;
10407 }
10408 if (onSurface) {
10409 return cent;
10410 } else {
10411 var vertices = featureCollection([]);
10412 for (i = 0; i < fc.features.length; i++) {
10413 vertices.features = vertices.features.concat(explode(fc.features[i]).features);
10414 }
10415 // Remove distanceToPoint properties from nearestPoint()
10416 return point(nearestPoint(cent, vertices).geometry.coordinates);
10417 }
10418}
10419
10420/**
10421 * Normalizes any GeoJSON to a FeatureCollection
10422 *
10423 * @private
10424 * @name normalize
10425 * @param {GeoJSON} geojson Any GeoJSON
10426 * @returns {FeatureCollection} FeatureCollection
10427 */
10428function normalize$1(geojson) {
10429 if (geojson.type !== 'FeatureCollection') {
10430 if (geojson.type !== 'Feature') {
10431 return featureCollection([feature(geojson)]);
10432 }
10433 return featureCollection([geojson]);
10434 }
10435 return geojson;
10436}
10437
10438function pointOnSegment(x, y, x1, y1, x2, y2) {
10439 var ab = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
10440 var ap = Math.sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1));
10441 var pb = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y));
10442 return ab === ap + pb;
10443}
10444
10445/**
10446 * Takes one or more features and returns their area in square meters.
10447 *
10448 * @name area
10449 * @param {GeoJSON} geojson input GeoJSON feature(s)
10450 * @returns {number} area in square meters
10451 * @example
10452 * var polygon = turf.polygon([[[125, -15], [113, -22], [154, -27], [144, -15], [125, -15]]]);
10453 *
10454 * var area = turf.area(polygon);
10455 *
10456 * //addToMap
10457 * var addToMap = [polygon]
10458 * polygon.properties.area = area
10459 */
10460function area$1(geojson) {
10461 return geomReduce(geojson, function (value, geom) {
10462 return value + calculateArea(geom);
10463 }, 0);
10464}
10465
10466var RADIUS = 6378137;
10467// var FLATTENING_DENOM = 298.257223563;
10468// var FLATTENING = 1 / FLATTENING_DENOM;
10469// var POLAR_RADIUS = RADIUS * (1 - FLATTENING);
10470
10471/**
10472 * Calculate Area
10473 *
10474 * @private
10475 * @param {GeoJSON} geojson GeoJSON
10476 * @returns {number} area
10477 */
10478function calculateArea(geojson) {
10479 var area = 0, i;
10480 switch (geojson.type) {
10481 case 'Polygon':
10482 return polygonArea(geojson.coordinates);
10483 case 'MultiPolygon':
10484 for (i = 0; i < geojson.coordinates.length; i++) {
10485 area += polygonArea(geojson.coordinates[i]);
10486 }
10487 return area;
10488 case 'Point':
10489 case 'MultiPoint':
10490 case 'LineString':
10491 case 'MultiLineString':
10492 return 0;
10493 case 'GeometryCollection':
10494 for (i = 0; i < geojson.geometries.length; i++) {
10495 area += calculateArea(geojson.geometries[i]);
10496 }
10497 return area;
10498 }
10499}
10500
10501function polygonArea(coords) {
10502 var area = 0;
10503 if (coords && coords.length > 0) {
10504 area += Math.abs(ringArea(coords[0]));
10505 for (var i = 1; i < coords.length; i++) {
10506 area -= Math.abs(ringArea(coords[i]));
10507 }
10508 }
10509 return area;
10510}
10511
10512/**
10513 * @private
10514 * Calculate the approximate area of the polygon were it projected onto the earth.
10515 * Note that this area will be positive if ring is oriented clockwise, otherwise it will be negative.
10516 *
10517 * Reference:
10518 * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
10519 * Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
10520 *
10521 * @param {Array<Array<number>>} coords Ring Coordinates
10522 * @returns {number} The approximate signed geodesic area of the polygon in square meters.
10523 */
10524function ringArea(coords) {
10525 var p1;
10526 var p2;
10527 var p3;
10528 var lowerIndex;
10529 var middleIndex;
10530 var upperIndex;
10531 var i;
10532 var area = 0;
10533 var coordsLength = coords.length;
10534
10535 if (coordsLength > 2) {
10536 for (i = 0; i < coordsLength; i++) {
10537 if (i === coordsLength - 2) { // i = N-2
10538 lowerIndex = coordsLength - 2;
10539 middleIndex = coordsLength - 1;
10540 upperIndex = 0;
10541 } else if (i === coordsLength - 1) { // i = N-1
10542 lowerIndex = coordsLength - 1;
10543 middleIndex = 0;
10544 upperIndex = 1;
10545 } else { // i = 0 to N-3
10546 lowerIndex = i;
10547 middleIndex = i + 1;
10548 upperIndex = i + 2;
10549 }
10550 p1 = coords[lowerIndex];
10551 p2 = coords[middleIndex];
10552 p3 = coords[upperIndex];
10553 area += (rad(p3[0]) - rad(p1[0])) * Math.sin(rad(p2[1]));
10554 }
10555
10556 area = area * RADIUS * RADIUS / 2;
10557 }
10558
10559 return area;
10560}
10561
10562function rad(_) {
10563 return _ * Math.PI / 180;
10564}
10565
10566/**
10567 * Takes a {@link LineString} and returns a {@link Point} at a specified distance along the line.
10568 *
10569 * @name along
10570 * @param {Feature<LineString>} line input line
10571 * @param {number} distance distance along the line
10572 * @param {Object} [options] Optional parameters
10573 * @param {string} [options.units="kilometers"] can be degrees, radians, miles, or kilometers
10574 * @returns {Feature<Point>} Point `distance` `units` along the line
10575 * @example
10576 * var line = turf.lineString([[-83, 30], [-84, 36], [-78, 41]]);
10577 * var options = {units: 'miles'};
10578 *
10579 * var along = turf.along(line, 200, options);
10580 *
10581 * //addToMap
10582 * var addToMap = [along, line]
10583 */
10584function along(line, distance$$1, options) {
10585 // Optional parameters
10586 options = options || {};
10587 if (!isObject(options)) throw new Error('options is invalid');
10588
10589 // Validation
10590 var coords;
10591 if (line.type === 'Feature') coords = line.geometry.coordinates;
10592 else if (line.type === 'LineString') coords = line.coordinates;
10593 else throw new Error('input must be a LineString Feature or Geometry');
10594 if (!isNumber(distance$$1)) throw new Error('distance must be a number');
10595
10596 var travelled = 0;
10597 for (var i = 0; i < coords.length; i++) {
10598 if (distance$$1 >= travelled && i === coords.length - 1) break;
10599 else if (travelled >= distance$$1) {
10600 var overshot = distance$$1 - travelled;
10601 if (!overshot) return point(coords[i]);
10602 else {
10603 var direction = bearing(coords[i], coords[i - 1]) - 180;
10604 var interpolated = destination(coords[i], overshot, direction, options);
10605 return interpolated;
10606 }
10607 } else {
10608 travelled += distance(coords[i], coords[i + 1], options);
10609 }
10610 }
10611 return point(coords[coords.length - 1]);
10612}
10613
10614/**
10615 * Takes a {@link GeoJSON} and measures its length in the specified units, {@link (Multi)Point}'s distance are ignored.
10616 *
10617 * @name length
10618 * @param {GeoJSON} geojson GeoJSON to measure
10619 * @param {Object} [options={}] Optional parameters
10620 * @param {string} [options.units=kilometers] can be degrees, radians, miles, or kilometers
10621 * @returns {number} length of GeoJSON
10622 * @example
10623 * var line = turf.lineString([[115, -32], [131, -22], [143, -25], [150, -34]]);
10624 * var length = turf.length(line, {units: 'miles'});
10625 *
10626 * //addToMap
10627 * var addToMap = [line];
10628 * line.properties.distance = length;
10629 */
10630function length(geojson, options) {
10631 // Optional parameters
10632 options = options || {};
10633 if (!isObject(options)) throw new Error('options is invalid');
10634
10635 // Input Validation
10636 if (!geojson) throw new Error('geojson is required');
10637
10638 // Calculate distance from 2-vertex line segements
10639 return segmentReduce(geojson, function (previousValue, segment) {
10640 var coords = segment.geometry.coordinates;
10641 return previousValue + distance(coords[0], coords[1], options);
10642 }, 0);
10643}
10644
10645/**
10646 * Takes a {@link LineString|line}, a start {@link Point}, and a stop point
10647 * and returns a subsection of the line in-between those points.
10648 * The start & stop points don't need to fall exactly on the line.
10649 *
10650 * This can be useful for extracting only the part of a route between waypoints.
10651 *
10652 * @name lineSlice
10653 * @param {Coord} startPt starting point
10654 * @param {Coord} stopPt stopping point
10655 * @param {Feature<LineString>|LineString} line line to slice
10656 * @returns {Feature<LineString>} sliced line
10657 * @example
10658 * var line = turf.lineString([
10659 * [-77.031669, 38.878605],
10660 * [-77.029609, 38.881946],
10661 * [-77.020339, 38.884084],
10662 * [-77.025661, 38.885821],
10663 * [-77.021884, 38.889563],
10664 * [-77.019824, 38.892368]
10665 * ]);
10666 * var start = turf.point([-77.029609, 38.881946]);
10667 * var stop = turf.point([-77.021884, 38.889563]);
10668 *
10669 * var sliced = turf.lineSlice(start, stop, line);
10670 *
10671 * //addToMap
10672 * var addToMap = [start, stop, line]
10673 */
10674function lineSlice(startPt, stopPt, line) {
10675 // Validation
10676 var coords = getCoords(line);
10677 if (getType(line) !== 'LineString') throw new Error('line must be a LineString');
10678
10679 var startVertex = nearestPointOnLine(line, startPt);
10680 var stopVertex = nearestPointOnLine(line, stopPt);
10681 var ends;
10682 if (startVertex.properties.index <= stopVertex.properties.index) {
10683 ends = [startVertex, stopVertex];
10684 } else {
10685 ends = [stopVertex, startVertex];
10686 }
10687 var clipCoords = [ends[0].geometry.coordinates];
10688 for (var i = ends[0].properties.index + 1; i < ends[1].properties.index + 1; i++) {
10689 clipCoords.push(coords[i]);
10690 }
10691 clipCoords.push(ends[1].geometry.coordinates);
10692 return lineString(clipCoords, line.properties);
10693}
10694
10695/**
10696 * Takes a {@link LineString|line}, a specified distance along the line to a start {@link Point},
10697 * and a specified distance along the line to a stop point
10698 * and returns a subsection of the line in-between those points.
10699 *
10700 * This can be useful for extracting only the part of a route between two distances.
10701 *
10702 * @name lineSliceAlong
10703 * @param {Feature<LineString>|LineString} line input line
10704 * @param {number} startDist distance along the line to starting point
10705 * @param {number} stopDist distance along the line to ending point
10706 * @param {Object} [options={}] Optional parameters
10707 * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers
10708 * @returns {Feature<LineString>} sliced line
10709 * @example
10710 * var line = turf.lineString([[7, 45], [9, 45], [14, 40], [14, 41]]);
10711 * var start = 12.5;
10712 * var stop = 25;
10713 * var sliced = turf.lineSliceAlong(line, start, stop, {units: 'miles'});
10714 *
10715 * //addToMap
10716 * var addToMap = [line, start, stop, sliced]
10717 */
10718function lineSliceAlong(line, startDist, stopDist, options) {
10719 // Optional parameters
10720 options = options || {};
10721 if (!isObject(options)) throw new Error('options is invalid');
10722
10723 var coords;
10724 var slice = [];
10725
10726 // Validation
10727 if (line.type === 'Feature') coords = line.geometry.coordinates;
10728 else if (line.type === 'LineString') coords = line.coordinates;
10729 else throw new Error('input must be a LineString Feature or Geometry');
10730
10731 var travelled = 0;
10732 var overshot, direction, interpolated;
10733 for (var i = 0; i < coords.length; i++) {
10734 if (startDist >= travelled && i === coords.length - 1) break;
10735 else if (travelled > startDist && slice.length === 0) {
10736 overshot = startDist - travelled;
10737 if (!overshot) {
10738 slice.push(coords[i]);
10739 return lineString(slice);
10740 }
10741 direction = bearing(coords[i], coords[i - 1]) - 180;
10742 interpolated = destination(coords[i], overshot, direction, options);
10743 slice.push(interpolated.geometry.coordinates);
10744 }
10745
10746 if (travelled >= stopDist) {
10747 overshot = stopDist - travelled;
10748 if (!overshot) {
10749 slice.push(coords[i]);
10750 return lineString(slice);
10751 }
10752 direction = bearing(coords[i], coords[i - 1]) - 180;
10753 interpolated = destination(coords[i], overshot, direction, options);
10754 slice.push(interpolated.geometry.coordinates);
10755 return lineString(slice);
10756 }
10757
10758 if (travelled >= startDist) {
10759 slice.push(coords[i]);
10760 }
10761
10762 if (i === coords.length - 1) {
10763 return lineString(slice);
10764 }
10765
10766 travelled += distance(coords[i], coords[i + 1], options);
10767 }
10768 return lineString(coords[coords.length - 1]);
10769}
10770
10771/**
10772 * Returns true if a point is on a line. Accepts a optional parameter to ignore the start and end vertices of the linestring.
10773 *
10774 * @name booleanPointOnLine
10775 * @param {Coord} pt GeoJSON Point
10776 * @param {Feature<LineString>} line GeoJSON LineString
10777 * @param {Object} [options={}] Optional parameters
10778 * @param {boolean} [options.ignoreEndVertices=false] whether to ignore the start and end vertices.
10779 * @returns {boolean} true/false
10780 * @example
10781 * var pt = turf.point([0, 0]);
10782 * var line = turf.lineString([[-1, -1],[1, 1],[1.5, 2.2]]);
10783 * var isPointOnLine = turf.booleanPointOnLine(pt, line);
10784 * //=true
10785 */
10786function booleanPointOnLine(pt, line, options) {
10787 // Optional parameters
10788 options = options || {};
10789 var ignoreEndVertices = options.ignoreEndVertices;
10790 if (!isObject(options)) throw new Error('invalid options');
10791
10792 // Validate input
10793 if (!pt) throw new Error('pt is required');
10794 if (!line) throw new Error('line is required');
10795
10796 // Normalize inputs
10797 var ptCoords = getCoord(pt);
10798 var lineCoords = getCoords(line);
10799
10800 // Main
10801 for (var i = 0; i < lineCoords.length - 1; i++) {
10802 var ignoreBoundary = false;
10803 if (ignoreEndVertices) {
10804 if (i === 0) ignoreBoundary = 'start';
10805 if (i === lineCoords.length - 2) ignoreBoundary = 'end';
10806 if (i === 0 && i + 1 === lineCoords.length - 1) ignoreBoundary = 'both';
10807 }
10808 if (isPointOnLineSegment$1(lineCoords[i], lineCoords[i + 1], ptCoords, ignoreBoundary)) return true;
10809 }
10810 return false;
10811}
10812
10813// See http://stackoverflow.com/a/4833823/1979085
10814/**
10815 * @private
10816 * @param {Position} lineSegmentStart coord pair of start of line
10817 * @param {Position} lineSegmentEnd coord pair of end of line
10818 * @param {Position} pt coord pair of point to check
10819 * @param {boolean|string} excludeBoundary whether the point is allowed to fall on the line ends. If true which end to ignore.
10820 * @returns {boolean} true/false
10821 */
10822function isPointOnLineSegment$1(lineSegmentStart, lineSegmentEnd, pt, excludeBoundary) {
10823 var x = pt[0];
10824 var y = pt[1];
10825 var x1 = lineSegmentStart[0];
10826 var y1 = lineSegmentStart[1];
10827 var x2 = lineSegmentEnd[0];
10828 var y2 = lineSegmentEnd[1];
10829 var dxc = pt[0] - x1;
10830 var dyc = pt[1] - y1;
10831 var dxl = x2 - x1;
10832 var dyl = y2 - y1;
10833 var cross = dxc * dyl - dyc * dxl;
10834 if (cross !== 0) {
10835 return false;
10836 }
10837 if (!excludeBoundary) {
10838 if (Math.abs(dxl) >= Math.abs(dyl)) {
10839 return dxl > 0 ? x1 <= x && x <= x2 : x2 <= x && x <= x1;
10840 }
10841 return dyl > 0 ? y1 <= y && y <= y2 : y2 <= y && y <= y1;
10842 } else if (excludeBoundary === 'start') {
10843 if (Math.abs(dxl) >= Math.abs(dyl)) {
10844 return dxl > 0 ? x1 < x && x <= x2 : x2 <= x && x < x1;
10845 }
10846 return dyl > 0 ? y1 < y && y <= y2 : y2 <= y && y < y1;
10847 } else if (excludeBoundary === 'end') {
10848 if (Math.abs(dxl) >= Math.abs(dyl)) {
10849 return dxl > 0 ? x1 <= x && x < x2 : x2 < x && x <= x1;
10850 }
10851 return dyl > 0 ? y1 <= y && y < y2 : y2 < y && y <= y1;
10852 } else if (excludeBoundary === 'both') {
10853 if (Math.abs(dxl) >= Math.abs(dyl)) {
10854 return dxl > 0 ? x1 < x && x < x2 : x2 < x && x < x1;
10855 }
10856 return dyl > 0 ? y1 < y && y < y2 : y2 < y && y < y1;
10857 }
10858}
10859
10860/**
10861 * Boolean-within returns true if the first geometry is completely within the second geometry.
10862 * The interiors of both geometries must intersect and, the interior and boundary of the primary (geometry a)
10863 * must not intersect the exterior of the secondary (geometry b).
10864 * Boolean-within returns the exact opposite result of the `@turf/boolean-contains`.
10865 *
10866 * @name booleanWithin
10867 * @param {Geometry|Feature<any>} feature1 GeoJSON Feature or Geometry
10868 * @param {Geometry|Feature<any>} feature2 GeoJSON Feature or Geometry
10869 * @returns {boolean} true/false
10870 * @example
10871 * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]);
10872 * var point = turf.point([1, 2]);
10873 *
10874 * turf.booleanWithin(point, line);
10875 * //=true
10876 */
10877function booleanWithin(feature1, feature2) {
10878 var type1 = getType(feature1);
10879 var type2 = getType(feature2);
10880 var geom1 = getGeom(feature1);
10881 var geom2 = getGeom(feature2);
10882
10883 switch (type1) {
10884 case 'Point':
10885 switch (type2) {
10886 case 'MultiPoint':
10887 return isPointInMultiPoint(geom1, geom2);
10888 case 'LineString':
10889 return booleanPointOnLine(geom1, geom2, {ignoreEndVertices: true});
10890 case 'Polygon':
10891 return booleanPointInPolygon(geom1, geom2, {ignoreBoundary: true});
10892 default:
10893 throw new Error('feature2 ' + type2 + ' geometry not supported');
10894 }
10895 case 'MultiPoint':
10896 switch (type2) {
10897 case 'MultiPoint':
10898 return isMultiPointInMultiPoint(geom1, geom2);
10899 case 'LineString':
10900 return isMultiPointOnLine(geom1, geom2);
10901 case 'Polygon':
10902 return isMultiPointInPoly(geom1, geom2);
10903 default:
10904 throw new Error('feature2 ' + type2 + ' geometry not supported');
10905 }
10906 case 'LineString':
10907 switch (type2) {
10908 case 'LineString':
10909 return isLineOnLine(geom1, geom2);
10910 case 'Polygon':
10911 return isLineInPoly(geom1, geom2);
10912 default:
10913 throw new Error('feature2 ' + type2 + ' geometry not supported');
10914 }
10915 case 'Polygon':
10916 switch (type2) {
10917 case 'Polygon':
10918 return isPolyInPoly(geom1, geom2);
10919 default:
10920 throw new Error('feature2 ' + type2 + ' geometry not supported');
10921 }
10922 default:
10923 throw new Error('feature1 ' + type1 + ' geometry not supported');
10924 }
10925}
10926
10927function isPointInMultiPoint(point, multiPoint) {
10928 var i;
10929 var output = false;
10930 for (i = 0; i < multiPoint.coordinates.length; i++) {
10931 if (compareCoords(multiPoint.coordinates[i], point.coordinates)) {
10932 output = true;
10933 break;
10934 }
10935 }
10936 return output;
10937}
10938
10939function isMultiPointInMultiPoint(multiPoint1, multiPoint2) {
10940 for (var i = 0; i < multiPoint1.coordinates.length; i++) {
10941 var anyMatch = false;
10942 for (var i2 = 0; i2 < multiPoint2.coordinates.length; i2++) {
10943 if (compareCoords(multiPoint1.coordinates[i], multiPoint2.coordinates[i2])) {
10944 anyMatch = true;
10945 }
10946 }
10947 if (!anyMatch) {
10948 return false;
10949 }
10950 }
10951 return true;
10952}
10953
10954function isMultiPointOnLine(multiPoint, lineString) {
10955 var foundInsidePoint = false;
10956
10957 for (var i = 0; i < multiPoint.coordinates.length; i++) {
10958 if (!booleanPointOnLine(multiPoint.coordinates[i], lineString)) {
10959 return false;
10960 }
10961 if (!foundInsidePoint) {
10962 foundInsidePoint = booleanPointOnLine(multiPoint.coordinates[i], lineString, {ignoreEndVertices: true});
10963 }
10964 }
10965 return foundInsidePoint;
10966}
10967
10968function isMultiPointInPoly(multiPoint, polygon) {
10969 var output = true;
10970 var oneInside = false;
10971 for (var i = 0; i < multiPoint.coordinates.length; i++) {
10972 var isInside = booleanPointInPolygon(multiPoint.coordinates[1], polygon);
10973 if (!isInside) {
10974 output = false;
10975 break;
10976 }
10977 if (!oneInside) {
10978 isInside = booleanPointInPolygon(multiPoint.coordinates[1], polygon, {ignoreBoundary: true});
10979 }
10980 }
10981 return output && isInside;
10982}
10983
10984function isLineOnLine(lineString1, lineString2) {
10985 for (var i = 0; i < lineString1.coordinates.length; i++) {
10986 if (!booleanPointOnLine(lineString1.coordinates[i], lineString2)) {
10987 return false;
10988 }
10989 }
10990 return true;
10991}
10992
10993function isLineInPoly(linestring, polygon) {
10994 var polyBbox = bbox(polygon);
10995 var lineBbox = bbox(linestring);
10996 if (!doBBoxOverlap(polyBbox, lineBbox)) {
10997 return false;
10998 }
10999 var foundInsidePoint = false;
11000
11001 for (var i = 0; i < linestring.coordinates.length - 1; i++) {
11002 if (!booleanPointInPolygon(linestring.coordinates[i], polygon)) {
11003 return false;
11004 }
11005 if (!foundInsidePoint) {
11006 foundInsidePoint = booleanPointInPolygon(linestring.coordinates[i], polygon, {ignoreBoundary: true});
11007 }
11008 if (!foundInsidePoint) {
11009 var midpoint = getMidpoint(linestring.coordinates[i], linestring.coordinates[i + 1]);
11010 foundInsidePoint = booleanPointInPolygon(midpoint, polygon, {ignoreBoundary: true});
11011
11012 }
11013 }
11014 return foundInsidePoint;
11015}
11016
11017/**
11018 * Is Polygon2 in Polygon1
11019 * Only takes into account outer rings
11020 *
11021 * @private
11022 * @param {Geometry|Feature<Polygon>} feature1 Polygon1
11023 * @param {Geometry|Feature<Polygon>} feature2 Polygon2
11024 * @returns {boolean} true/false
11025 */
11026function isPolyInPoly(feature1, feature2) {
11027 var poly1Bbox = bbox(feature1);
11028 var poly2Bbox = bbox(feature2);
11029 if (!doBBoxOverlap(poly2Bbox, poly1Bbox)) {
11030 return false;
11031 }
11032 for (var i = 0; i < feature1.coordinates[0].length; i++) {
11033 if (!booleanPointInPolygon(feature1.coordinates[0][i], feature2)) {
11034 return false;
11035 }
11036 }
11037 return true;
11038}
11039
11040function doBBoxOverlap(bbox1, bbox2) {
11041 if (bbox1[0] > bbox2[0]) return false;
11042 if (bbox1[2] < bbox2[2]) return false;
11043 if (bbox1[1] > bbox2[1]) return false;
11044 if (bbox1[3] < bbox2[3]) return false;
11045 return true;
11046}
11047
11048/**
11049 * compareCoords
11050 *
11051 * @private
11052 * @param {Position} pair1 point [x,y]
11053 * @param {Position} pair2 point [x,y]
11054 * @returns {boolean} true/false if coord pairs match
11055 */
11056function compareCoords(pair1, pair2) {
11057 return pair1[0] === pair2[0] && pair1[1] === pair2[1];
11058}
11059
11060/**
11061 * getMidpoint
11062 *
11063 * @private
11064 * @param {Position} pair1 point [x,y]
11065 * @param {Position} pair2 point [x,y]
11066 * @returns {Position} midpoint of pair1 and pair2
11067 */
11068function getMidpoint(pair1, pair2) {
11069 return [(pair1[0] + pair2[0]) / 2, (pair1[1] + pair2[1]) / 2];
11070}
11071
11072/**
11073 * Creates a {@link Point} grid from a bounding box, {@link FeatureCollection} or {@link Feature}.
11074 *
11075 * @name pointGrid
11076 * @param {Array<number>} bbox extent in [minX, minY, maxX, maxY] order
11077 * @param {number} cellSide the distance between points, in units
11078 * @param {Object} [options={}] Optional parameters
11079 * @param {string} [options.units='kilometers'] used in calculating cellSide, can be degrees, radians, miles, or kilometers
11080 * @param {Feature<Polygon|MultiPolygon>} [options.mask] if passed a Polygon or MultiPolygon, the grid Points will be created only inside it
11081 * @param {Object} [options.properties={}] passed to each point of the grid
11082 * @returns {FeatureCollection<Point>} grid of points
11083 * @example
11084 * var extent = [-70.823364, -33.553984, -70.473175, -33.302986];
11085 * var cellSide = 3;
11086 * var options = {units: 'miles'};
11087 *
11088 * var grid = turf.pointGrid(extent, cellSide, options);
11089 *
11090 * //addToMap
11091 * var addToMap = [grid];
11092 */
11093function pointGrid(bbox, cellSide, options) {
11094 // Optional parameters
11095 options = options || {};
11096 if (!isObject(options)) throw new Error('options is invalid');
11097 // var units = options.units;
11098 var mask = options.mask;
11099 var properties = options.properties;
11100
11101 // Containers
11102 var results = [];
11103
11104 // Input Validation
11105 if (cellSide === null || cellSide === undefined) throw new Error('cellSide is required');
11106 if (!isNumber(cellSide)) throw new Error('cellSide is invalid');
11107 if (!bbox) throw new Error('bbox is required');
11108 if (!Array.isArray(bbox)) throw new Error('bbox must be array');
11109 if (bbox.length !== 4) throw new Error('bbox must contain 4 numbers');
11110 if (mask && ['Polygon', 'MultiPolygon'].indexOf(getType(mask)) === -1) throw new Error('options.mask must be a (Multi)Polygon');
11111
11112 var west = bbox[0];
11113 var south = bbox[1];
11114 var east = bbox[2];
11115 var north = bbox[3];
11116
11117 var xFraction = cellSide / (distance([west, south], [east, south], options));
11118 var cellWidth = xFraction * (east - west);
11119 var yFraction = cellSide / (distance([west, south], [west, north], options));
11120 var cellHeight = yFraction * (north - south);
11121
11122 var bboxWidth = (east - west);
11123 var bboxHeight = (north - south);
11124 var columns = Math.floor(bboxWidth / cellWidth);
11125 var rows = Math.floor(bboxHeight / cellHeight);
11126 // adjust origin of the grid
11127 var deltaX = (bboxWidth - columns * cellWidth) / 2;
11128 var deltaY = (bboxHeight - rows * cellHeight) / 2;
11129
11130 var currentX = west + deltaX;
11131 while (currentX <= east) {
11132 var currentY = south + deltaY;
11133 while (currentY <= north) {
11134 var cellPt = point([currentX, currentY], properties);
11135 if (mask) {
11136 if (booleanWithin(cellPt, mask)) results.push(cellPt);
11137 } else {
11138 results.push(cellPt);
11139 }
11140 currentY += cellHeight;
11141 }
11142 currentX += cellWidth;
11143 }
11144
11145 return featureCollection(results);
11146}
11147
11148/**
11149 * Takes a GeoJSON Feature or FeatureCollection and truncates the precision of the geometry.
11150 *
11151 * @name truncate
11152 * @param {GeoJSON} geojson any GeoJSON Feature, FeatureCollection, Geometry or GeometryCollection.
11153 * @param {Object} [options={}] Optional parameters
11154 * @param {number} [options.precision=6] coordinate decimal precision
11155 * @param {number} [options.coordinates=3] maximum number of coordinates (primarly used to remove z coordinates)
11156 * @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated (significant performance increase if true)
11157 * @returns {GeoJSON} layer with truncated geometry
11158 * @example
11159 * var point = turf.point([
11160 * 70.46923055566859,
11161 * 58.11088890802906,
11162 * 1508
11163 * ]);
11164 * var options = {precision: 3, coordinates: 2};
11165 * var truncated = turf.truncate(point, options);
11166 * //=truncated.geometry.coordinates => [70.469, 58.111]
11167 *
11168 * //addToMap
11169 * var addToMap = [truncated];
11170 */
11171function truncate(geojson, options) {
11172 // Optional parameters
11173 options = options || {};
11174 if (!isObject(options)) throw new Error('options is invalid');
11175 var precision = options.precision;
11176 var coordinates = options.coordinates;
11177 var mutate = options.mutate;
11178
11179 // default params
11180 precision = (precision === undefined || precision === null || isNaN(precision)) ? 6 : precision;
11181 coordinates = (coordinates === undefined || coordinates === null || isNaN(coordinates)) ? 3 : coordinates;
11182
11183 // validation
11184 if (!geojson) throw new Error('<geojson> is required');
11185 if (typeof precision !== 'number') throw new Error('<precision> must be a number');
11186 if (typeof coordinates !== 'number') throw new Error('<coordinates> must be a number');
11187
11188 // prevent input mutation
11189 if (mutate === false || mutate === undefined) geojson = JSON.parse(JSON.stringify(geojson));
11190
11191 var factor = Math.pow(10, precision);
11192
11193 // Truncate Coordinates
11194 coordEach(geojson, function (coords) {
11195 truncateCoords(coords, factor, coordinates);
11196 });
11197 return geojson;
11198}
11199
11200/**
11201 * Truncate Coordinates - Mutates coordinates in place
11202 *
11203 * @private
11204 * @param {Array<any>} coords Geometry Coordinates
11205 * @param {number} factor rounding factor for coordinate decimal precision
11206 * @param {number} coordinates maximum number of coordinates (primarly used to remove z coordinates)
11207 * @returns {Array<any>} mutated coordinates
11208 */
11209function truncateCoords(coords, factor, coordinates) {
11210 // Remove extra coordinates (usually elevation coordinates and more)
11211 if (coords.length > coordinates) coords.splice(coordinates, coords.length);
11212
11213 // Truncate coordinate decimals
11214 for (var i = 0; i < coords.length; i++) {
11215 coords[i] = Math.round(coords[i] * factor) / factor;
11216 }
11217 return coords;
11218}
11219
11220/**
11221 * Flattens any {@link GeoJSON} to a {@link FeatureCollection} inspired by [geojson-flatten](https://github.com/tmcw/geojson-flatten).
11222 *
11223 * @name flatten
11224 * @param {GeoJSON} geojson any valid GeoJSON Object
11225 * @returns {FeatureCollection<any>} all Multi-Geometries are flattened into single Features
11226 * @example
11227 * var multiGeometry = turf.multiPolygon([
11228 * [[[102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0]]],
11229 * [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]],
11230 * [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]]]
11231 * ]);
11232 *
11233 * var flatten = turf.flatten(multiGeometry);
11234 *
11235 * //addToMap
11236 * var addToMap = [flatten]
11237 */
11238function flatten(geojson) {
11239 if (!geojson) throw new Error('geojson is required');
11240
11241 var results = [];
11242 flattenEach(geojson, function (feature$$1) {
11243 results.push(feature$$1);
11244 });
11245 return featureCollection(results);
11246}
11247
11248/**
11249 * Divides a {@link LineString} into chunks of a specified length.
11250 * If the line is shorter than the segment length then the original line is returned.
11251 *
11252 * @name lineChunk
11253 * @param {FeatureCollection|Geometry|Feature<LineString|MultiLineString>} geojson the lines to split
11254 * @param {number} segmentLength how long to make each segment
11255 * @param {Object} [options={}] Optional parameters
11256 * @param {string} [options.units='kilometers'] units can be degrees, radians, miles, or kilometers
11257 * @param {boolean} [options.reverse=false] reverses coordinates to start the first chunked segment at the end
11258 * @returns {FeatureCollection<LineString>} collection of line segments
11259 * @example
11260 * var line = turf.lineString([[-95, 40], [-93, 45], [-85, 50]]);
11261 *
11262 * var chunk = turf.lineChunk(line, 15, {units: 'miles'});
11263 *
11264 * //addToMap
11265 * var addToMap = [chunk];
11266 */
11267function lineChunk(geojson, segmentLength, options) {
11268 // Optional parameters
11269 options = options || {};
11270 if (!isObject(options)) throw new Error('options is invalid');
11271 var units = options.units;
11272 var reverse = options.reverse;
11273
11274 // Validation
11275 if (!geojson) throw new Error('geojson is required');
11276 if (segmentLength <= 0) throw new Error('segmentLength must be greater than 0');
11277
11278 // Container
11279 var results = [];
11280
11281 // Flatten each feature to simple LineString
11282 flattenEach(geojson, function (feature$$1) {
11283 // reverses coordinates to start the first chunked segment at the end
11284 if (reverse) feature$$1.geometry.coordinates = feature$$1.geometry.coordinates.reverse();
11285
11286 sliceLineSegments(feature$$1, segmentLength, units, function (segment) {
11287 results.push(segment);
11288 });
11289 });
11290 return featureCollection(results);
11291}
11292
11293/**
11294 * Slice Line Segments
11295 *
11296 * @private
11297 * @param {Feature<LineString>} line GeoJSON LineString
11298 * @param {number} segmentLength how long to make each segment
11299 * @param {string}[units='kilometers'] units can be degrees, radians, miles, or kilometers
11300 * @param {Function} callback iterate over sliced line segments
11301 * @returns {void}
11302 */
11303function sliceLineSegments(line, segmentLength, units, callback) {
11304 var lineLength = length(line, {units: units});
11305
11306 // If the line is shorter than the segment length then the orginal line is returned.
11307 if (lineLength <= segmentLength) return callback(line);
11308
11309 var numberOfSegments = lineLength / segmentLength;
11310
11311 // If numberOfSegments is integer, no need to plus 1
11312 if (!Number.isInteger(numberOfSegments)) {
11313 numberOfSegments = Math.floor(numberOfSegments) + 1;
11314 }
11315
11316 for (var i = 0; i < numberOfSegments; i++) {
11317 var outline = lineSliceAlong(line, segmentLength * i, segmentLength * (i + 1), {units: units});
11318 callback(outline, i);
11319 }
11320}
11321
11322// Find self-intersections in geojson polygon (possibly with interior rings)
11323var isects = function (feature$$1, filterFn, useSpatialIndex) {
11324 if (feature$$1.geometry.type !== 'Polygon') throw new Error('The input feature must be a Polygon');
11325 if (useSpatialIndex === undefined) useSpatialIndex = 1;
11326
11327 var coord = feature$$1.geometry.coordinates;
11328
11329 var output = [];
11330 var seen = {};
11331
11332 if (useSpatialIndex) {
11333 var allEdgesAsRbushTreeItems = [];
11334 for (var ring0 = 0; ring0 < coord.length; ring0++) {
11335 for (var edge0 = 0; edge0 < coord[ring0].length - 1; edge0++) {
11336 allEdgesAsRbushTreeItems.push(rbushTreeItem(ring0, edge0));
11337 }
11338 }
11339 var tree = rbush_1();
11340 tree.load(allEdgesAsRbushTreeItems);
11341 }
11342
11343 for (var ringA = 0; ringA < coord.length; ringA++) {
11344 for (var edgeA = 0; edgeA < coord[ringA].length - 1; edgeA++) {
11345 if (useSpatialIndex) {
11346 var bboxOverlaps = tree.search(rbushTreeItem(ringA, edgeA));
11347 bboxOverlaps.forEach(function (bboxIsect) {
11348 var ring1 = bboxIsect.ring;
11349 var edge1 = bboxIsect.edge;
11350 ifIsectAddToOutput(ringA, edgeA, ring1, edge1);
11351 });
11352 } else {
11353 for (var ring1 = 0; ring1 < coord.length; ring1++) {
11354 for (var edge1 = 0; edge1 < coord[ring1].length - 1; edge1++) {
11355 // TODO: speedup possible if only interested in unique: start last two loops at ringA and edgeA+1
11356 ifIsectAddToOutput(ringA, edgeA, ring1, edge1);
11357 }
11358 }
11359 }
11360 }
11361 }
11362
11363 if (!filterFn) output = {type: 'Feature', geometry: {type: 'MultiPoint', coordinates: output}};
11364 return output;
11365
11366 // Function to check if two edges intersect and add the intersection to the output
11367 function ifIsectAddToOutput(ring0, edge0, ring1, edge1) {
11368 var start0 = coord[ring0][edge0];
11369 var end0 = coord[ring0][edge0 + 1];
11370 var start1 = coord[ring1][edge1];
11371 var end1 = coord[ring1][edge1 + 1];
11372
11373 var isect = intersect(start0, end0, start1, end1);
11374
11375 if (isect === null) return; // discard parallels and coincidence
11376 var frac0;
11377 var frac1;
11378 if (end0[0] !== start0[0]) {
11379 frac0 = (isect[0] - start0[0]) / (end0[0] - start0[0]);
11380 } else {
11381 frac0 = (isect[1] - start0[1]) / (end0[1] - start0[1]);
11382 }
11383 if (end1[0] !== start1[0]) {
11384 frac1 = (isect[0] - start1[0]) / (end1[0] - start1[0]);
11385 } else {
11386 frac1 = (isect[1] - start1[1]) / (end1[1] - start1[1]);
11387 }
11388 if (frac0 >= 1 || frac0 <= 0 || frac1 >= 1 || frac1 <= 0) return; // require segment intersection
11389
11390 var key = isect;
11391 var unique = !seen[key];
11392 if (unique) {
11393 seen[key] = true;
11394 }
11395
11396 if (filterFn) {
11397 output.push(filterFn(isect, ring0, edge0, start0, end0, frac0, ring1, edge1, start1, end1, frac1, unique));
11398 } else {
11399 output.push(isect);
11400 }
11401 }
11402
11403 // Function to return a rbush tree item given an ring and edge number
11404 function rbushTreeItem(ring, edge) {
11405
11406 var start = coord[ring][edge];
11407 var end = coord[ring][edge + 1];
11408 var minX;
11409 var maxX;
11410 var minY;
11411 var maxY;
11412 if (start[0] < end[0]) {
11413 minX = start[0];
11414 maxX = end[0];
11415 } else {
11416 minX = end[0];
11417 maxX = start[0];
11418 }
11419 if (start[1] < end[1]) {
11420 minY = start[1];
11421 maxY = end[1];
11422 } else {
11423 minY = end[1];
11424 maxY = start[1];
11425 }
11426 return {minX: minX, minY: minY, maxX: maxX, maxY: maxY, ring: ring, edge: edge};
11427 }
11428};
11429
11430// Function to compute where two lines (not segments) intersect. From https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
11431function intersect(start0, end0, start1, end1) {
11432 if (equalArrays$1(start0, start1) || equalArrays$1(start0, end1) || equalArrays$1(end0, start1) || equalArrays$1(end1, start1)) return null;
11433 var x0 = start0[0],
11434 y0 = start0[1],
11435 x1 = end0[0],
11436 y1 = end0[1],
11437 x2 = start1[0],
11438 y2 = start1[1],
11439 x3 = end1[0],
11440 y3 = end1[1];
11441 var denom = (x0 - x1) * (y2 - y3) - (y0 - y1) * (x2 - x3);
11442 if (denom === 0) return null;
11443 var x4 = ((x0 * y1 - y0 * x1) * (x2 - x3) - (x0 - x1) * (x2 * y3 - y2 * x3)) / denom;
11444 var y4 = ((x0 * y1 - y0 * x1) * (y2 - y3) - (y0 - y1) * (x2 * y3 - y2 * x3)) / denom;
11445 return [x4, y4];
11446}
11447
11448// Function to compare Arrays of numbers. From http://stackoverflow.com/questions/7837456/how-to-compare-arrays-in-javascript
11449function equalArrays$1(array1, array2) {
11450 // if the other array is a falsy value, return
11451 if (!array1 || !array2)
11452 return false;
11453
11454 // compare lengths - can save a lot of time
11455 if (array1.length !== array2.length)
11456 return false;
11457
11458 for (var i = 0, l = array1.length; i < l; i++) {
11459 // Check if we have nested arrays
11460 if (array1[i] instanceof Array && array2[i] instanceof Array) {
11461 // recurse into the nested arrays
11462 if (!equalArrays$1(array1[i], array2[i]))
11463 return false;
11464 } else if (array1[i] !== array2[i]) {
11465 // Warning - two different object instances will never be equal: {x:20} !== {x:20}
11466 return false;
11467 }
11468 }
11469 return true;
11470}
11471
11472/**
11473 * Takes a complex (i.e. self-intersecting) geojson polygon, and breaks it down into its composite simple, non-self-intersecting one-ring polygons.
11474 *
11475 * @module simplepolygon
11476 * @param {Feature} feature Input polygon. This polygon may be unconform the {@link https://en.wikipedia.org/wiki/Simple_Features|Simple Features standard} in the sense that it's inner and outer rings may cross-intersect or self-intersect, that the outer ring must not contain the optional inner rings and that the winding number must not be positive for the outer and negative for the inner rings.
11477 * @return {FeatureCollection} Feature collection containing the simple, non-self-intersecting one-ring polygon features that the complex polygon is composed of. These simple polygons have properties such as their parent polygon, winding number and net winding number.
11478 *
11479 * @example
11480 * var poly = {
11481 * "type": "Feature",
11482 * "geometry": {
11483 * "type": "Polygon",
11484 * "coordinates": [[[0,0],[2,0],[0,2],[2,2],[0,0]]]
11485 * }
11486 * };
11487 *
11488 * var result = simplepolygon(poly);
11489 *
11490 * // =result
11491 * // which will be a featureCollection of two polygons, one with coordinates [[[0,0],[2,0],[1,1],[0,0]]], parent -1, winding 1 and net winding 1, and one with coordinates [[[1,1],[0,2],[2,2],[1,1]]], parent -1, winding -1 and net winding -1
11492 */
11493var simplepolygon = function (feature$$1) {
11494 // Check input
11495 if (feature$$1.type != 'Feature') throw new Error('The input must a geojson object of type Feature');
11496 if ((feature$$1.geometry === undefined) || (feature$$1.geometry == null)) throw new Error('The input must a geojson object with a non-empty geometry');
11497 if (feature$$1.geometry.type != 'Polygon') throw new Error('The input must be a geojson Polygon');
11498
11499 // Process input
11500 var numRings = feature$$1.geometry.coordinates.length;
11501 var vertices = [];
11502 for (var i = 0; i < numRings; i++) {
11503 var ring = feature$$1.geometry.coordinates[i];
11504 if (!equalArrays(ring[0], ring[ring.length - 1])) {
11505 ring.push(ring[0]); // Close input ring if it is not
11506 }
11507 vertices.push.apply(vertices, ring.slice(0, ring.length - 1));
11508 }
11509 if (!isUnique(vertices)) throw new Error('The input polygon may not have duplicate vertices (except for the first and last vertex of each ring)');
11510 var numvertices = vertices.length; // number of input ring vertices, with the last closing vertices not counted
11511
11512 // Compute self-intersections
11513 var selfIsectsData = isects(feature$$1, function filterFn(isect, ring0, edge0, start0, end0, frac0, ring1, edge1, start1, end1, frac1, unique) {
11514 return [isect, ring0, edge0, start0, end0, frac0, ring1, edge1, start1, end1, frac1, unique];
11515 });
11516 var numSelfIsect = selfIsectsData.length;
11517
11518 // If no self-intersections are found, the input rings are the output rings. Hence, we must only compute their winding numbers, net winding numbers and (since ohers rings could lie outside the first ring) parents.
11519 if (numSelfIsect == 0) {
11520 var outputFeatureArray = [];
11521 for (var i = 0; i < numRings; i++) {
11522 outputFeatureArray.push(polygon([feature$$1.geometry.coordinates[i]], {parent: -1, winding: windingOfRing(feature$$1.geometry.coordinates[i])}));
11523 }
11524 var output = featureCollection(outputFeatureArray);
11525 determineParents();
11526 setNetWinding();
11527
11528 return output;
11529 }
11530
11531 // If self-intersections are found, we will compute the output rings with the help of two intermediate variables
11532 // First, we build the pseudo vertex list and intersection list
11533 // The Pseudo vertex list is an array with for each ring an array with for each edge an array containing the pseudo-vertices (as made by their constructor) that have this ring and edge as ringAndEdgeIn, sorted for each edge by their fractional distance on this edge. It's length hence equals numRings.
11534 var pseudoVtxListByRingAndEdge = [];
11535 // The intersection list is an array containing intersections (as made by their constructor). First all numvertices ring-vertex-intersections, then all self-intersections (intra- and inter-ring). The order of the latter is not important but is permanent once given.
11536 var isectList = [];
11537 // Adding ring-pseudo-vertices to pseudoVtxListByRingAndEdge and ring-vertex-intersections to isectList
11538 for (var i = 0; i < numRings; i++) {
11539 pseudoVtxListByRingAndEdge.push([]);
11540 for (var j = 0; j < feature$$1.geometry.coordinates[i].length - 1; j++) {
11541 // Each edge will feature one ring-pseudo-vertex in its array, on the last position. i.e. edge j features the ring-pseudo-vertex of the ring vertex j+1, which has ringAndEdgeIn = [i,j], on the last position.
11542 pseudoVtxListByRingAndEdge[i].push([new PseudoVtx(feature$$1.geometry.coordinates[i][(j + 1).modulo(feature$$1.geometry.coordinates[i].length - 1)], 1, [i, j], [i, (j + 1).modulo(feature$$1.geometry.coordinates[i].length - 1)], undefined)]);
11543 // The first numvertices elements in isectList correspond to the ring-vertex-intersections
11544 isectList.push(new Isect(feature$$1.geometry.coordinates[i][j], [i, (j - 1).modulo(feature$$1.geometry.coordinates[i].length - 1)], [i, j], undefined, undefined, false, true));
11545 }
11546 }
11547 // Adding intersection-pseudo-vertices to pseudoVtxListByRingAndEdge and self-intersections to isectList
11548 for (var i = 0; i < numSelfIsect; i++) {
11549 // Adding intersection-pseudo-vertices made using selfIsectsData to pseudoVtxListByRingAndEdge's array corresponding to the incomming ring and edge
11550 pseudoVtxListByRingAndEdge[selfIsectsData[i][1]][selfIsectsData[i][2]].push(new PseudoVtx(selfIsectsData[i][0], selfIsectsData[i][5], [selfIsectsData[i][1], selfIsectsData[i][2]], [selfIsectsData[i][6], selfIsectsData[i][7]], undefined));
11551 // selfIsectsData contains double mentions of each intersection, but we only want to add them once to isectList
11552 if (selfIsectsData[i][11]) isectList.push(new Isect(selfIsectsData[i][0], [selfIsectsData[i][1], selfIsectsData[i][2]], [selfIsectsData[i][6], selfIsectsData[i][7]], undefined, undefined, true, true));
11553 }
11554 var numIsect = isectList.length;
11555 // Sort edge arrays of pseudoVtxListByRingAndEdge by the fractional distance 'param'
11556 for (var i = 0; i < pseudoVtxListByRingAndEdge.length; i++) {
11557 for (var j = 0; j < pseudoVtxListByRingAndEdge[i].length; j++) {
11558 pseudoVtxListByRingAndEdge[i][j].sort(function (a, b) { return (a.param < b.param) ? -1 : 1; });
11559 }
11560 }
11561
11562 // Make a spatial index of intersections, in preperation for the following two steps
11563 var allIsectsAsIsectRbushTreeItem = [];
11564 for (var i = 0; i < numIsect; i++) {
11565 allIsectsAsIsectRbushTreeItem.push({minX: isectList[i].coord[0], minY: isectList[i].coord[1], maxX: isectList[i].coord[0], maxY: isectList[i].coord[1], index: i}); // could pass isect: isectList[i], but not necessary
11566 }
11567 var isectRbushTree = rbush_1();
11568 isectRbushTree.load(allIsectsAsIsectRbushTreeItem);
11569
11570 // Now we will teach each intersection in isectList which is the next intersection along both it's [ring, edge]'s, in two steps.
11571 // First, we find the next intersection for each pseudo-vertex in pseudoVtxListByRingAndEdge:
11572 // For each pseudovertex in pseudoVtxListByRingAndEdge (3 loops) look at the next pseudovertex on that edge and find the corresponding intersection by comparing coordinates
11573 for (var i = 0; i < pseudoVtxListByRingAndEdge.length; i++) {
11574 for (var j = 0; j < pseudoVtxListByRingAndEdge[i].length; j++) {
11575 for (var k = 0; k < pseudoVtxListByRingAndEdge[i][j].length; k++) {
11576 var coordToFind;
11577 if (k == pseudoVtxListByRingAndEdge[i][j].length - 1) { // If it's the last pseudoVertex on that edge, then the next pseudoVertex is the first one on the next edge of that ring.
11578 coordToFind = pseudoVtxListByRingAndEdge[i][(j + 1).modulo(feature$$1.geometry.coordinates[i].length - 1)][0].coord;
11579 } else {
11580 coordToFind = pseudoVtxListByRingAndEdge[i][j][k + 1].coord;
11581 }
11582 var IsectRbushTreeItemFound = isectRbushTree.search({minX: coordToFind[0], minY: coordToFind[1], maxX: coordToFind[0], maxY: coordToFind[1]})[0]; // We can take [0] of the result, because there is only one isect correponding to a pseudo-vertex
11583 pseudoVtxListByRingAndEdge[i][j][k].nxtIsectAlongEdgeIn = IsectRbushTreeItemFound.index;
11584 }
11585 }
11586 }
11587
11588 // Second, we port this knowledge of the next intersection over to the intersections in isectList, by finding the intersection corresponding to each pseudo-vertex and copying the pseudo-vertex' knownledge of the next-intersection over to the intersection
11589 for (var i = 0; i < pseudoVtxListByRingAndEdge.length; i++) {
11590 for (var j = 0; j < pseudoVtxListByRingAndEdge[i].length; j++) {
11591 for (var k = 0; k < pseudoVtxListByRingAndEdge[i][j].length; k++) {
11592 var coordToFind = pseudoVtxListByRingAndEdge[i][j][k].coord;
11593 var IsectRbushTreeItemFound = isectRbushTree.search({minX: coordToFind[0], minY: coordToFind[1], maxX: coordToFind[0], maxY: coordToFind[1]})[0]; // We can take [0] of the result, because there is only one isect correponding to a pseudo-vertex
11594 var l = IsectRbushTreeItemFound.index;
11595 if (l < numvertices) { // Special treatment at ring-vertices: we correct the misnaming that happened in the previous block, since ringAndEdgeOut = ringAndEdge2 for ring vertices.
11596 isectList[l].nxtIsectAlongRingAndEdge2 = pseudoVtxListByRingAndEdge[i][j][k].nxtIsectAlongEdgeIn;
11597 } else { // Port the knowledge of the next intersection from the pseudo-vertices to the intersections, depending on how the edges are labeled in the pseudo-vertex and intersection.
11598 if (equalArrays(isectList[l].ringAndEdge1, pseudoVtxListByRingAndEdge[i][j][k].ringAndEdgeIn)) {
11599 isectList[l].nxtIsectAlongRingAndEdge1 = pseudoVtxListByRingAndEdge[i][j][k].nxtIsectAlongEdgeIn;
11600 } else {
11601 isectList[l].nxtIsectAlongRingAndEdge2 = pseudoVtxListByRingAndEdge[i][j][k].nxtIsectAlongEdgeIn;
11602 }
11603 }
11604 }
11605 }
11606 }
11607 // This explains why, eventhough when we will walk away from an intersection, we will walk way from the corresponding pseudo-vertex along edgeOut, pseudo-vertices have the property 'nxtIsectAlongEdgeIn' in stead of some propery 'nxtPseudoVtxAlongEdgeOut'. This is because this property (which is easy to find out) is used in the above for nxtIsectAlongRingAndEdge1 and nxtIsectAlongRingAndEdge2!
11608
11609 // Before we start walking over the intersections to build the output rings, we prepare a queue that stores information on intersections we still have to deal with, and put at least one intersection in it.
11610 // This queue will contain information on intersections where we can start walking from once the current walk is finished, and its parent output ring (the smallest output ring it lies within, -1 if no parent or parent unknown yet) and its winding number (which we can already determine).
11611 var queue = [];
11612 // For each output ring, add the ring-vertex-intersection with the smalles x-value (i.e. the left-most) as a start intersection. By choosing such an extremal intersections, we are sure to start at an intersection that is a convex vertex of its output ring. By adding them all to the queue, we are sure that no rings will be forgotten. If due to ring-intersections such an intersection will be encountered while walking, it will be removed from the queue.
11613 var i = 0;
11614 for (var j = 0; j < numRings; j++) {
11615 var leftIsect = i;
11616 for (var k = 0; k < feature$$1.geometry.coordinates[j].length - 1; k++) {
11617 if (isectList[i].coord[0] < isectList[leftIsect].coord[0]) {
11618 leftIsect = i;
11619 }
11620 i++;
11621 }
11622 // Compute winding at this left-most ring-vertex-intersection. We thus this by using our knowledge that this extremal vertex must be a convex vertex.
11623 // We first find the intersection before and after it, and then use them to determine the winding number of the corresponding output ring, since we know that an extremal vertex of a simple, non-self-intersecting ring is always convex, so the only reason it would not be is because the winding number we use to compute it is wrong
11624 var isectAfterLeftIsect = isectList[leftIsect].nxtIsectAlongRingAndEdge2;
11625 for (var k = 0; k < isectList.length; k++) {
11626 if ((isectList[k].nxtIsectAlongRingAndEdge1 == leftIsect) || (isectList[k].nxtIsectAlongRingAndEdge2 == leftIsect)) {
11627 var isectBeforeLeftIsect = k;
11628 break;
11629 }
11630 }
11631 var windingAtIsect = isConvex([isectList[isectBeforeLeftIsect].coord, isectList[leftIsect].coord, isectList[isectAfterLeftIsect].coord], true) ? 1 : -1;
11632
11633 queue.push({isect: leftIsect, parent: -1, winding: windingAtIsect});
11634 }
11635 // Sort the queue by the same criterion used to find the leftIsect: the left-most leftIsect must be last in the queue, such that it will be popped first, such that we will work from out to in regarding input rings. This assumtion is used when predicting the winding number and parent of a new queue member.
11636 queue.sort(function (a, b) { return (isectList[a.isect].coord > isectList[b.isect].coord) ? -1 : 1; });
11637
11638 // Initialise output
11639 var outputFeatureArray = [];
11640
11641 // While the queue is not empty, take the last object (i.e. its intersection) out and start making an output ring by walking in the direction that has not been walked away over yet.
11642 while (queue.length > 0) {
11643 // Get the last object out of the queue
11644 var popped = queue.pop();
11645 var startIsect = popped.isect;
11646 var currentOutputRingParent = popped.parent;
11647 var currentOutputRingWinding = popped.winding;
11648 // Make new output ring and add vertex from starting intersection
11649 var currentOutputRing = outputFeatureArray.length;
11650 var currentOutputRingCoords = [isectList[startIsect].coord];
11651 // Set up the variables used while walking over intersections: 'currentIsect', 'nxtIsect' and 'walkingRingAndEdge'
11652 var currentIsect = startIsect;
11653 if (isectList[startIsect].ringAndEdge1Walkable) {
11654 var walkingRingAndEdge = isectList[startIsect].ringAndEdge1;
11655 var nxtIsect = isectList[startIsect].nxtIsectAlongRingAndEdge1;
11656 } else {
11657 var walkingRingAndEdge = isectList[startIsect].ringAndEdge2;
11658 var nxtIsect = isectList[startIsect].nxtIsectAlongRingAndEdge2;
11659 }
11660 // While we have not arrived back at the same intersection, keep walking
11661 while (!equalArrays(isectList[startIsect].coord, isectList[nxtIsect].coord)) {
11662 currentOutputRingCoords.push(isectList[nxtIsect].coord);
11663 // If the next intersection is queued, we can remove it, because we will go there now.
11664 var nxtIsectInQueue = undefined;
11665 for (var i = 0; i < queue.length; i++) { if (queue[i].isect == nxtIsect) { nxtIsectInQueue = i; break; } }
11666 if (nxtIsectInQueue != undefined) {
11667 queue.splice(nxtIsectInQueue, 1);
11668 }
11669 // Arriving at this new intersection, we know which will be our next walking ring and edge (if we came from 1 we will walk away from 2 and vice versa),
11670 // So we can set it as our new walking ring and intersection and remember that we (will) have walked over it
11671 // If we have never walked away from this new intersection along the other ring and edge then we will soon do, add the intersection (and the parent wand winding number) to the queue
11672 // (We can predict the winding number and parent as follows: if the edge is convex, the other output ring started from there will have the alternate winding and lie outside of the current one, and thus have the same parent ring as the current ring. Otherwise, it will have the same winding number and lie inside of the current ring. We are, however, only sure of this of an output ring started from there does not enclose the current ring. This is why the initial queue's intersections must be sorted such that outer ones come out first.)
11673 // We then update the other two walking variables.
11674 if (equalArrays(walkingRingAndEdge, isectList[nxtIsect].ringAndEdge1)) {
11675 walkingRingAndEdge = isectList[nxtIsect].ringAndEdge2;
11676 isectList[nxtIsect].ringAndEdge2Walkable = false;
11677 if (isectList[nxtIsect].ringAndEdge1Walkable) {
11678 var pushing = {isect: nxtIsect};
11679 if (isConvex([isectList[currentIsect].coord, isectList[nxtIsect].coord, isectList[isectList[nxtIsect].nxtIsectAlongRingAndEdge2].coord], currentOutputRingWinding == 1)) {
11680 pushing.parent = currentOutputRingParent;
11681 pushing.winding = -currentOutputRingWinding;
11682 } else {
11683 pushing.parent = currentOutputRing;
11684 pushing.winding = currentOutputRingWinding;
11685 }
11686 queue.push(pushing);
11687 }
11688 currentIsect = nxtIsect;
11689 nxtIsect = isectList[nxtIsect].nxtIsectAlongRingAndEdge2;
11690 } else {
11691 walkingRingAndEdge = isectList[nxtIsect].ringAndEdge1;
11692 isectList[nxtIsect].ringAndEdge1Walkable = false;
11693 if (isectList[nxtIsect].ringAndEdge2Walkable) {
11694 var pushing = {isect: nxtIsect};
11695 if (isConvex([isectList[currentIsect].coord, isectList[nxtIsect].coord, isectList[isectList[nxtIsect].nxtIsectAlongRingAndEdge1].coord], currentOutputRingWinding == 1)) {
11696 pushing.parent = currentOutputRingParent;
11697 pushing.winding = -currentOutputRingWinding;
11698 } else {
11699 pushing.parent = currentOutputRing;
11700 pushing.winding = currentOutputRingWinding;
11701 }
11702 queue.push(pushing);
11703 }
11704 currentIsect = nxtIsect;
11705 nxtIsect = isectList[nxtIsect].nxtIsectAlongRingAndEdge1;
11706 }
11707 }
11708 // Close output ring
11709 currentOutputRingCoords.push(isectList[nxtIsect].coord);
11710 // Push output ring to output
11711 outputFeatureArray.push(polygon([currentOutputRingCoords], {index: currentOutputRing, parent: currentOutputRingParent, winding: currentOutputRingWinding, netWinding: undefined}));
11712 }
11713
11714 var output = featureCollection(outputFeatureArray);
11715
11716 determineParents();
11717
11718 setNetWinding();
11719
11720 // These functions are also used if no intersections are found
11721 function determineParents() {
11722 var featuresWithoutParent = [];
11723 for (var i = 0; i < output.features.length; i++) {
11724 if (output.features[i].properties.parent == -1) featuresWithoutParent.push(i);
11725 }
11726 if (featuresWithoutParent.length > 1) {
11727 for (var i = 0; i < featuresWithoutParent.length; i++) {
11728 var parent = -1;
11729 var parentArea = Infinity;
11730 for (var j = 0; j < output.features.length; j++) {
11731 if (featuresWithoutParent[i] == j) continue;
11732 if (booleanPointInPolygon(output.features[featuresWithoutParent[i]].geometry.coordinates[0][0], output.features[j], {ignoreBoundary: true})) {
11733 if (area$1(output.features[j]) < parentArea) {
11734 parent = j;
11735 }
11736 }
11737 }
11738 output.features[featuresWithoutParent[i]].properties.parent = parent;
11739 }
11740 }
11741 }
11742
11743 function setNetWinding() {
11744 for (var i = 0; i < output.features.length; i++) {
11745 if (output.features[i].properties.parent == -1) {
11746 var netWinding = output.features[i].properties.winding;
11747 output.features[i].properties.netWinding = netWinding;
11748 setNetWindingOfChildren(i, netWinding);
11749 }
11750 }
11751 }
11752
11753 function setNetWindingOfChildren(parent, ParentNetWinding) {
11754 for (var i = 0; i < output.features.length; i++) {
11755 if (output.features[i].properties.parent == parent) {
11756 var netWinding = ParentNetWinding + output.features[i].properties.winding;
11757 output.features[i].properties.netWinding = netWinding;
11758 setNetWindingOfChildren(i, netWinding);
11759 }
11760 }
11761 }
11762
11763
11764 return output;
11765};
11766
11767
11768
11769// Constructor for (ring- or intersection-) pseudo-vertices.
11770var PseudoVtx = function (coord, param, ringAndEdgeIn, ringAndEdgeOut, nxtIsectAlongEdgeIn) {
11771 this.coord = coord; // [x,y] of this pseudo-vertex
11772 this.param = param; // fractional distance of this intersection on incomming edge
11773 this.ringAndEdgeIn = ringAndEdgeIn; // [ring index, edge index] of incomming edge
11774 this.ringAndEdgeOut = ringAndEdgeOut; // [ring index, edge index] of outgoing edge
11775 this.nxtIsectAlongEdgeIn = nxtIsectAlongEdgeIn; // The next intersection when following the incomming edge (so not when following ringAndEdgeOut!)
11776};
11777
11778// Constructor for an intersection. There are two intersection-pseudo-vertices per self-intersection and one ring-pseudo-vertex per ring-vertex-intersection. Their labels 1 and 2 are not assigned a particular meaning but are permanent once given.
11779var Isect = function (coord, ringAndEdge1, ringAndEdge2, nxtIsectAlongRingAndEdge1, nxtIsectAlongRingAndEdge2, ringAndEdge1Walkable, ringAndEdge2Walkable) {
11780 this.coord = coord; // [x,y] of this intersection
11781 this.ringAndEdge1 = ringAndEdge1; // first edge of this intersection
11782 this.ringAndEdge2 = ringAndEdge2; // second edge of this intersection
11783 this.nxtIsectAlongRingAndEdge1 = nxtIsectAlongRingAndEdge1; // the next intersection when following ringAndEdge1
11784 this.nxtIsectAlongRingAndEdge2 = nxtIsectAlongRingAndEdge2; // the next intersection when following ringAndEdge2
11785 this.ringAndEdge1Walkable = ringAndEdge1Walkable; // May we (still) walk away from this intersection over ringAndEdge1?
11786 this.ringAndEdge2Walkable = ringAndEdge2Walkable; // May we (still) walk away from this intersection over ringAndEdge2?
11787};
11788
11789// Function to determine if three consecutive points of a simple, non-self-intersecting ring make up a convex vertex, assuming the ring is right- or lefthanded
11790function isConvex(pts, righthanded) {
11791 // 'pts' is an [x,y] pair
11792 // 'righthanded' is a boolean
11793 if (typeof (righthanded) === 'undefined') righthanded = true;
11794 if (pts.length != 3) throw new Error('This function requires an array of three points [x,y]');
11795 var d = (pts[1][0] - pts[0][0]) * (pts[2][1] - pts[0][1]) - (pts[1][1] - pts[0][1]) * (pts[2][0] - pts[0][0]);
11796 return (d >= 0) == righthanded;
11797}
11798
11799// Function to compute winding of simple, non-self-intersecting ring
11800function windingOfRing(ring) {
11801 // 'ring' is an array of [x,y] pairs with the last equal to the first
11802 // Compute the winding number based on the vertex with the smallest x-value, it precessor and successor. An extremal vertex of a simple, non-self-intersecting ring is always convex, so the only reason it is not is because the winding number we use to compute it is wrong
11803 var leftVtx = 0;
11804 for (var i = 0; i < ring.length - 1; i++) { if (ring[i][0] < ring[leftVtx][0]) leftVtx = i; }
11805 if (isConvex([ring[(leftVtx - 1).modulo(ring.length - 1)], ring[leftVtx], ring[(leftVtx + 1).modulo(ring.length - 1)]], true)) {
11806 var winding = 1;
11807 } else {
11808 var winding = -1;
11809 }
11810 return winding;
11811}
11812
11813// Function to compare Arrays of numbers. From http://stackoverflow.com/questions/7837456/how-to-compare-arrays-in-javascript
11814function equalArrays(array1, array2) {
11815 // if the other array is a falsy value, return
11816 if (!array1 || !array2)
11817 return false;
11818
11819 // compare lengths - can save a lot of time
11820 if (array1.length != array2.length)
11821 return false;
11822
11823 for (var i = 0, l = array1.length; i < l; i++) {
11824 // Check if we have nested arrays
11825 if (array1[i] instanceof Array && array2[i] instanceof Array) {
11826 // recurse into the nested arrays
11827 if (!equalArrays(array1[i], array2[i]))
11828 return false;
11829 } else if (array1[i] != array2[i]) {
11830 // Warning - two different object instances will never be equal: {x:20} != {x:20}
11831 return false;
11832 }
11833 }
11834 return true;
11835}
11836
11837// Fix Javascript modulo for negative number. From http://stackoverflow.com/questions/4467539/javascript-modulo-not-behaving
11838Number.prototype.modulo = function (n) {
11839 return ((this % n) + n) % n;
11840};
11841
11842// Function to check if array is unique (i.e. all unique elements, i.e. no duplicate elements)
11843function isUnique(array) {
11844 var u = {};
11845 var isUnique = 1;
11846 for (var i = 0, l = array.length; i < l; ++i) {
11847 if (u.hasOwnProperty(array[i])) {
11848 isUnique = 0;
11849 break;
11850 }
11851 u[array[i]] = 1;
11852 }
11853 return isUnique;
11854}
11855
11856/**
11857 * Takes a kinked polygon and returns a feature collection of polygons that have no kinks.
11858 * Uses [simplepolygon](https://github.com/mclaeysb/simplepolygon) internally.
11859 *
11860 * @name unkinkPolygon
11861 * @param {FeatureCollection|Feature<Polygon|MultiPolygon>} geojson GeoJSON Polygon or MultiPolygon
11862 * @returns {FeatureCollection<Polygon>} Unkinked polygons
11863 * @example
11864 * var poly = turf.polygon([[[0, 0], [2, 0], [0, 2], [2, 2], [0, 0]]]);
11865 *
11866 * var result = turf.unkinkPolygon(poly);
11867 *
11868 * //addToMap
11869 * var addToMap = [poly, result]
11870 */
11871function unkinkPolygon(geojson) {
11872 var features = [];
11873 flattenEach(geojson, function (feature$$1) {
11874 if (feature$$1.geometry.type !== 'Polygon') return;
11875 featureEach(simplepolygon(feature$$1), function (poly) {
11876 features.push(polygon(poly.geometry.coordinates, feature$$1.properties));
11877 });
11878 });
11879 return featureCollection(features);
11880}
11881
11882var D2R = Math.PI / 180;
11883var R2D = 180 / Math.PI;
11884
11885var Coord = function (lon, lat) {
11886 this.lon = lon;
11887 this.lat = lat;
11888 this.x = D2R * lon;
11889 this.y = D2R * lat;
11890};
11891
11892Coord.prototype.view = function () {
11893 return String(this.lon).slice(0, 4) + ',' + String(this.lat).slice(0, 4);
11894};
11895
11896Coord.prototype.antipode = function () {
11897 var anti_lat = -1 * this.lat;
11898 var anti_lon = (this.lon < 0) ? 180 + this.lon : (180 - this.lon) * -1;
11899 return new Coord(anti_lon, anti_lat);
11900};
11901
11902var LineString = function () {
11903 this.coords = [];
11904 this.length = 0;
11905};
11906
11907LineString.prototype.move_to = function (coord) {
11908 this.length++;
11909 this.coords.push(coord);
11910};
11911
11912var Arc = function (properties) {
11913 this.properties = properties || {};
11914 this.geometries = [];
11915};
11916
11917Arc.prototype.json = function () {
11918 if (this.geometries.length <= 0) {
11919 return {'geometry': { 'type': 'LineString', 'coordinates': null },
11920 'type': 'Feature', 'properties': this.properties
11921 };
11922 } else if (this.geometries.length === 1) {
11923 return {'geometry': { 'type': 'LineString', 'coordinates': this.geometries[0].coords },
11924 'type': 'Feature', 'properties': this.properties
11925 };
11926 } else {
11927 var multiline = [];
11928 for (var i = 0; i < this.geometries.length; i++) {
11929 multiline.push(this.geometries[i].coords);
11930 }
11931 return {'geometry': { 'type': 'MultiLineString', 'coordinates': multiline },
11932 'type': 'Feature', 'properties': this.properties
11933 };
11934 }
11935};
11936
11937// TODO - output proper multilinestring
11938Arc.prototype.wkt = function () {
11939 var wkt_string = '';
11940 var wkt = 'LINESTRING(';
11941 var collect = function (c) { wkt += c[0] + ' ' + c[1] + ','; };
11942 for (var i = 0; i < this.geometries.length; i++) {
11943 if (this.geometries[i].coords.length === 0) {
11944 return 'LINESTRING(empty)';
11945 } else {
11946 var coords = this.geometries[i].coords;
11947 coords.forEach(collect);
11948 wkt_string += wkt.substring(0, wkt.length - 1) + ')';
11949 }
11950 }
11951 return wkt_string;
11952};
11953
11954/*
11955 * http://en.wikipedia.org/wiki/Great-circle_distance
11956 *
11957 */
11958var GreatCircle = function (start, end, properties) {
11959 if (!start || start.x === undefined || start.y === undefined) {
11960 throw new Error('GreatCircle constructor expects two args: start and end objects with x and y properties');
11961 }
11962 if (!end || end.x === undefined || end.y === undefined) {
11963 throw new Error('GreatCircle constructor expects two args: start and end objects with x and y properties');
11964 }
11965 this.start = new Coord(start.x, start.y);
11966 this.end = new Coord(end.x, end.y);
11967 this.properties = properties || {};
11968
11969 var w = this.start.x - this.end.x;
11970 var h = this.start.y - this.end.y;
11971 var z = Math.pow(Math.sin(h / 2.0), 2) +
11972 Math.cos(this.start.y) *
11973 Math.cos(this.end.y) *
11974 Math.pow(Math.sin(w / 2.0), 2);
11975 this.g = 2.0 * Math.asin(Math.sqrt(z));
11976
11977 if (this.g === Math.PI) {
11978 throw new Error('it appears ' + start.view() + ' and ' + end.view() + ' are \'antipodal\', e.g diametrically opposite, thus there is no single route but rather infinite');
11979 } else if (isNaN(this.g)) {
11980 throw new Error('could not calculate great circle between ' + start + ' and ' + end);
11981 }
11982};
11983
11984/*
11985 * http://williams.best.vwh.net/avform.htm#Intermediate
11986 */
11987GreatCircle.prototype.interpolate = function (f) {
11988 var A = Math.sin((1 - f) * this.g) / Math.sin(this.g);
11989 var B = Math.sin(f * this.g) / Math.sin(this.g);
11990 var x = A * Math.cos(this.start.y) * Math.cos(this.start.x) + B * Math.cos(this.end.y) * Math.cos(this.end.x);
11991 var y = A * Math.cos(this.start.y) * Math.sin(this.start.x) + B * Math.cos(this.end.y) * Math.sin(this.end.x);
11992 var z = A * Math.sin(this.start.y) + B * Math.sin(this.end.y);
11993 var lat = R2D * Math.atan2(z, Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)));
11994 var lon = R2D * Math.atan2(y, x);
11995 return [lon, lat];
11996};
11997
11998
11999
12000/*
12001 * Generate points along the great circle
12002 */
12003GreatCircle.prototype.Arc = function (npoints, options) {
12004 var first_pass = [];
12005 if (!npoints || npoints <= 2) {
12006 first_pass.push([this.start.lon, this.start.lat]);
12007 first_pass.push([this.end.lon, this.end.lat]);
12008 } else {
12009 var delta = 1.0 / (npoints - 1);
12010 for (var i = 0; i < npoints; ++i) {
12011 var step = delta * i;
12012 var pair = this.interpolate(step);
12013 first_pass.push(pair);
12014 }
12015 }
12016 /* partial port of dateline handling from:
12017 gdal/ogr/ogrgeometryfactory.cpp
12018
12019 TODO - does not handle all wrapping scenarios yet
12020 */
12021 var bHasBigDiff = false;
12022 var dfMaxSmallDiffLong = 0;
12023 // from http://www.gdal.org/ogr2ogr.html
12024 // -datelineoffset:
12025 // (starting with GDAL 1.10) offset from dateline in degrees (default long. = +/- 10deg, geometries within 170deg to -170deg will be splited)
12026 var dfDateLineOffset = options && options.offset ? options.offset : 10;
12027 var dfLeftBorderX = 180 - dfDateLineOffset;
12028 var dfRightBorderX = -180 + dfDateLineOffset;
12029 var dfDiffSpace = 360 - dfDateLineOffset;
12030
12031 // https://github.com/OSGeo/gdal/blob/7bfb9c452a59aac958bff0c8386b891edf8154ca/gdal/ogr/ogrgeometryfactory.cpp#L2342
12032 for (var j = 1; j < first_pass.length; ++j) {
12033 var dfPrevX = first_pass[j - 1][0];
12034 var dfX = first_pass[j][0];
12035 var dfDiffLong = Math.abs(dfX - dfPrevX);
12036 if (dfDiffLong > dfDiffSpace &&
12037 ((dfX > dfLeftBorderX && dfPrevX < dfRightBorderX) || (dfPrevX > dfLeftBorderX && dfX < dfRightBorderX))) {
12038 bHasBigDiff = true;
12039 } else if (dfDiffLong > dfMaxSmallDiffLong) {
12040 dfMaxSmallDiffLong = dfDiffLong;
12041 }
12042 }
12043
12044 var poMulti = [];
12045 if (bHasBigDiff && dfMaxSmallDiffLong < dfDateLineOffset) {
12046 var poNewLS = [];
12047 poMulti.push(poNewLS);
12048 for (var k = 0; k < first_pass.length; ++k) {
12049 var dfX0 = parseFloat(first_pass[k][0]);
12050 if (k > 0 && Math.abs(dfX0 - first_pass[k - 1][0]) > dfDiffSpace) {
12051 var dfX1 = parseFloat(first_pass[k - 1][0]);
12052 var dfY1 = parseFloat(first_pass[k - 1][1]);
12053 var dfX2 = parseFloat(first_pass[k][0]);
12054 var dfY2 = parseFloat(first_pass[k][1]);
12055 if (dfX1 > -180 && dfX1 < dfRightBorderX && dfX2 === 180 &&
12056 k + 1 < first_pass.length &&
12057 first_pass[k - 1][0] > -180 && first_pass[k - 1][0] < dfRightBorderX) {
12058 poNewLS.push([-180, first_pass[k][1]]);
12059 k++;
12060 poNewLS.push([first_pass[k][0], first_pass[k][1]]);
12061 continue;
12062 } else if (dfX1 > dfLeftBorderX && dfX1 < 180 && dfX2 === -180 &&
12063 k + 1 < first_pass.length &&
12064 first_pass[k - 1][0] > dfLeftBorderX && first_pass[k - 1][0] < 180) {
12065 poNewLS.push([180, first_pass[k][1]]);
12066 k++;
12067 poNewLS.push([first_pass[k][0], first_pass[k][1]]);
12068 continue;
12069 }
12070
12071 if (dfX1 < dfRightBorderX && dfX2 > dfLeftBorderX) {
12072 // swap dfX1, dfX2
12073 var tmpX = dfX1;
12074 dfX1 = dfX2;
12075 dfX2 = tmpX;
12076 // swap dfY1, dfY2
12077 var tmpY = dfY1;
12078 dfY1 = dfY2;
12079 dfY2 = tmpY;
12080 }
12081 if (dfX1 > dfLeftBorderX && dfX2 < dfRightBorderX) {
12082 dfX2 += 360;
12083 }
12084
12085 if (dfX1 <= 180 && dfX2 >= 180 && dfX1 < dfX2) {
12086 var dfRatio = (180 - dfX1) / (dfX2 - dfX1);
12087 var dfY = dfRatio * dfY2 + (1 - dfRatio) * dfY1;
12088 poNewLS.push([first_pass[k - 1][0] > dfLeftBorderX ? 180 : -180, dfY]);
12089 poNewLS = [];
12090 poNewLS.push([first_pass[k - 1][0] > dfLeftBorderX ? -180 : 180, dfY]);
12091 poMulti.push(poNewLS);
12092 } else {
12093 poNewLS = [];
12094 poMulti.push(poNewLS);
12095 }
12096 poNewLS.push([dfX0, first_pass[k][1]]);
12097 } else {
12098 poNewLS.push([first_pass[k][0], first_pass[k][1]]);
12099 }
12100 }
12101 } else {
12102 // add normally
12103 var poNewLS0 = [];
12104 poMulti.push(poNewLS0);
12105 for (var l = 0; l < first_pass.length; ++l) {
12106 poNewLS0.push([first_pass[l][0], first_pass[l][1]]);
12107 }
12108 }
12109
12110 var arc = new Arc(this.properties);
12111 for (var m = 0; m < poMulti.length; ++m) {
12112 var line = new LineString();
12113 arc.geometries.push(line);
12114 var points = poMulti[m];
12115 for (var j0 = 0; j0 < points.length; ++j0) {
12116 line.move_to(points[j0]);
12117 }
12118 }
12119 return arc;
12120};
12121
12122/**
12123 * Calculate great circles routes as {@link LineString}
12124 *
12125 * @name greatCircle
12126 * @param {Coord} start source point feature
12127 * @param {Coord} end destination point feature
12128 * @param {Object} [options={}] Optional parameters
12129 * @param {Object} [options.properties={}] line feature properties
12130 * @param {number} [options.npoints=100] number of points
12131 * @param {number} [options.offset=10] offset controls the likelyhood that lines will
12132 * be split which cross the dateline. The higher the number the more likely.
12133 * @returns {Feature<LineString>} great circle line feature
12134 * @example
12135 * var start = turf.point([-122, 48]);
12136 * var end = turf.point([-77, 39]);
12137 *
12138 * var greatCircle = turf.greatCircle(start, end, {'name': 'Seattle to DC'});
12139 *
12140 * //addToMap
12141 * var addToMap = [start, end, greatCircle]
12142 */
12143function greatCircle(start, end, options) {
12144 // Optional parameters
12145 options = options || {};
12146 if (typeof options !== 'object') throw new Error('options is invalid');
12147 var properties = options.properties;
12148 var npoints = options.npoints;
12149 var offset = options.offset;
12150
12151 start = getCoord(start);
12152 end = getCoord(end);
12153 properties = properties || {};
12154 npoints = npoints || 100;
12155 offset = offset || 10;
12156
12157 var generator = new GreatCircle({x: start[0], y: start[1]}, {x: end[0], y: end[1]}, properties);
12158
12159 /* eslint-disable */
12160 var line = generator.Arc(npoints, {offset: offset});
12161 /* eslint-enable */
12162
12163 return line.json();
12164}
12165
12166/**
12167 * Split a LineString by another GeoJSON Feature.
12168 *
12169 * @name lineSplit
12170 * @param {Feature<LineString>} line LineString Feature to split
12171 * @param {Feature<any>} splitter Feature used to split line
12172 * @returns {FeatureCollection<LineString>} Split LineStrings
12173 * @example
12174 * var line = turf.lineString([[120, -25], [145, -25]]);
12175 * var splitter = turf.lineString([[130, -15], [130, -35]]);
12176 *
12177 * var split = turf.lineSplit(line, splitter);
12178 *
12179 * //addToMap
12180 * var addToMap = [line, splitter]
12181 */
12182function lineSplit(line, splitter) {
12183 if (!line) throw new Error('line is required');
12184 if (!splitter) throw new Error('splitter is required');
12185
12186 var lineType = getType(line);
12187 var splitterType = getType(splitter);
12188
12189 if (lineType !== 'LineString') throw new Error('line must be LineString');
12190 if (splitterType === 'FeatureCollection') throw new Error('splitter cannot be a FeatureCollection');
12191 if (splitterType === 'GeometryCollection') throw new Error('splitter cannot be a GeometryCollection');
12192
12193 // remove excessive decimals from splitter
12194 // to avoid possible approximation issues in rbush
12195 var truncatedSplitter = truncate(splitter, {precision: 7});
12196
12197 switch (splitterType) {
12198 case 'Point':
12199 return splitLineWithPoint(line, truncatedSplitter);
12200 case 'MultiPoint':
12201 return splitLineWithPoints(line, truncatedSplitter);
12202 case 'LineString':
12203 case 'MultiLineString':
12204 case 'Polygon':
12205 case 'MultiPolygon':
12206 return splitLineWithPoints(line, lineIntersect(line, truncatedSplitter));
12207 }
12208}
12209
12210/**
12211 * Split LineString with MultiPoint
12212 *
12213 * @private
12214 * @param {Feature<LineString>} line LineString
12215 * @param {FeatureCollection<Point>} splitter Point
12216 * @returns {FeatureCollection<LineString>} split LineStrings
12217 */
12218function splitLineWithPoints(line, splitter) {
12219 var results = [];
12220 var tree = geojsonRbush();
12221
12222 flattenEach(splitter, function (point$$1) {
12223 // Add index/id to features (needed for filter)
12224 results.forEach(function (feature$$1, index) {
12225 feature$$1.id = index;
12226 });
12227 // First Point - doesn't need to handle any previous line results
12228 if (!results.length) {
12229 results = splitLineWithPoint(line, point$$1).features;
12230
12231 // Add Square BBox to each feature for GeoJSON-RBush
12232 results.forEach(function (feature$$1) {
12233 if (!feature$$1.bbox) feature$$1.bbox = square(bbox(feature$$1));
12234 });
12235 tree.load(featureCollection(results));
12236 // Split with remaining points - lines might needed to be split multiple times
12237 } else {
12238 // Find all lines that are within the splitter's bbox
12239 var search = tree.search(point$$1);
12240
12241 if (search.features.length) {
12242 // RBush might return multiple lines - only process the closest line to splitter
12243 var closestLine = findClosestFeature(point$$1, search);
12244
12245 // Remove closest line from results since this will be split into two lines
12246 // This removes any duplicates inside the results & index
12247 results = results.filter(function (feature$$1) { return feature$$1.id !== closestLine.id; });
12248 tree.remove(closestLine);
12249
12250 // Append the two newly split lines into the results
12251 featureEach(splitLineWithPoint(closestLine, point$$1), function (line) {
12252 results.push(line);
12253 tree.insert(line);
12254 });
12255 }
12256 }
12257 });
12258 return featureCollection(results);
12259}
12260
12261/**
12262 * Split LineString with Point
12263 *
12264 * @private
12265 * @param {Feature<LineString>} line LineString
12266 * @param {Feature<Point>} splitter Point
12267 * @returns {FeatureCollection<LineString>} split LineStrings
12268 */
12269function splitLineWithPoint(line, splitter) {
12270 var results = [];
12271
12272 // handle endpoints
12273 var startPoint = getCoords(line)[0];
12274 var endPoint = getCoords(line)[line.geometry.coordinates.length - 1];
12275 if (pointsEquals(startPoint, getCoord(splitter)) ||
12276 pointsEquals(endPoint, getCoord(splitter))) return featureCollection([line]);
12277
12278 // Create spatial index
12279 var tree = geojsonRbush();
12280 var segments = lineSegment(line);
12281 tree.load(segments);
12282
12283 // Find all segments that are within bbox of splitter
12284 var search = tree.search(splitter);
12285
12286 // Return itself if point is not within spatial index
12287 if (!search.features.length) return featureCollection([line]);
12288
12289 // RBush might return multiple lines - only process the closest line to splitter
12290 var closestSegment = findClosestFeature(splitter, search);
12291
12292 // Initial value is the first point of the first segments (beginning of line)
12293 var initialValue = [startPoint];
12294 var lastCoords = featureReduce(segments, function (previous, current, index) {
12295 var currentCoords = getCoords(current)[1];
12296 var splitterCoords = getCoord(splitter);
12297
12298 // Location where segment intersects with line
12299 if (index === closestSegment.id) {
12300 previous.push(splitterCoords);
12301 results.push(lineString(previous));
12302 // Don't duplicate splitter coordinate (Issue #688)
12303 if (pointsEquals(splitterCoords, currentCoords)) return [splitterCoords];
12304 return [splitterCoords, currentCoords];
12305
12306 // Keep iterating over coords until finished or intersection is found
12307 } else {
12308 previous.push(currentCoords);
12309 return previous;
12310 }
12311 }, initialValue);
12312 // Append last line to final split results
12313 if (lastCoords.length > 1) {
12314 results.push(lineString(lastCoords));
12315 }
12316 return featureCollection(results);
12317}
12318
12319
12320/**
12321 * Find Closest Feature
12322 *
12323 * @private
12324 * @param {Feature<Point>} point Feature must be closest to this point
12325 * @param {FeatureCollection<LineString>} lines Collection of Features
12326 * @returns {Feature<LineString>} closest LineString
12327 */
12328function findClosestFeature(point$$1, lines) {
12329 if (!lines.features.length) throw new Error('lines must contain features');
12330 // Filter to one segment that is the closest to the line
12331 if (lines.features.length === 1) return lines.features[0];
12332
12333 var closestFeature;
12334 var closestDistance = Infinity;
12335 featureEach(lines, function (segment) {
12336 var pt = nearestPointOnLine(segment, point$$1);
12337 var dist = pt.properties.dist;
12338 if (dist < closestDistance) {
12339 closestFeature = segment;
12340 closestDistance = dist;
12341 }
12342 });
12343 return closestFeature;
12344}
12345
12346/**
12347 * Compares two points and returns if they are equals
12348 *
12349 * @private
12350 * @param {Array<number>} pt1 point
12351 * @param {Array<number>} pt2 point
12352 * @returns {boolean} true if they are equals
12353 */
12354function pointsEquals(pt1, pt2) {
12355 return pt1[0] === pt2[0] && pt1[1] === pt2[1];
12356}
12357
12358/**
12359 * Creates a circular arc, of a circle of the given radius and center point, between bearing1 and bearing2;
12360 * 0 bearing is North of center point, positive clockwise.
12361 *
12362 * @name lineArc
12363 * @param {Coord} center center point
12364 * @param {number} radius radius of the circle
12365 * @param {number} bearing1 angle, in decimal degrees, of the first radius of the arc
12366 * @param {number} bearing2 angle, in decimal degrees, of the second radius of the arc
12367 * @param {Object} [options={}] Optional parameters
12368 * @param {number} [options.steps=64] number of steps
12369 * @param {string} [options.units='kilometers'] miles, kilometers, degrees, or radians
12370 * @returns {Feature<LineString>} line arc
12371 * @example
12372 * var center = turf.point([-75, 40]);
12373 * var radius = 5;
12374 * var bearing1 = 25;
12375 * var bearing2 = 47;
12376 *
12377 * var arc = turf.lineArc(center, radius, bearing1, bearing2);
12378 *
12379 * //addToMap
12380 * var addToMap = [center, arc]
12381 */
12382function lineArc(center, radius, bearing1, bearing2, options) {
12383 // Optional parameters
12384 options = options || {};
12385 if (!isObject(options)) throw new Error('options is invalid');
12386 var steps = options.steps;
12387 var units = options.units;
12388
12389 // validation
12390 if (!center) throw new Error('center is required');
12391 if (!radius) throw new Error('radius is required');
12392 if (bearing1 === undefined || bearing1 === null) throw new Error('bearing1 is required');
12393 if (bearing2 === undefined || bearing2 === null) throw new Error('bearing2 is required');
12394 if (typeof options !== 'object') throw new Error('options must be an object');
12395
12396 // default params
12397 steps = steps || 64;
12398
12399 var angle1 = convertAngleTo360(bearing1);
12400 var angle2 = convertAngleTo360(bearing2);
12401 var properties = center.properties;
12402
12403 // handle angle parameters
12404 if (angle1 === angle2) {
12405 return lineString(circle(center, radius, options).geometry.coordinates[0], properties);
12406 }
12407 var arcStartDegree = angle1;
12408 var arcEndDegree = (angle1 < angle2) ? angle2 : angle2 + 360;
12409
12410 var alfa = arcStartDegree;
12411 var coordinates = [];
12412 var i = 0;
12413
12414 while (alfa < arcEndDegree) {
12415 coordinates.push(destination(center, radius, alfa, units).geometry.coordinates);
12416 i++;
12417 alfa = arcStartDegree + i * 360 / steps;
12418 }
12419 if (alfa > arcEndDegree) {
12420 coordinates.push(destination(center, radius, arcEndDegree, units).geometry.coordinates);
12421 }
12422 return lineString(coordinates, properties);
12423}
12424
12425
12426/**
12427 * Takes any angle in degrees
12428 * and returns a valid angle between 0-360 degrees
12429 *
12430 * @private
12431 * @param {number} alfa angle between -180-180 degrees
12432 * @returns {number} angle between 0-360 degrees
12433 */
12434function convertAngleTo360(alfa) {
12435 var beta = alfa % 360;
12436 if (beta < 0) {
12437 beta += 360;
12438 }
12439 return beta;
12440}
12441
12442/**
12443 * Converts a {@link Polygon} to {@link LineString|(Multi)LineString} or {@link MultiPolygon} to a {@link FeatureCollection} of {@link LineString|(Multi)LineString}.
12444 *
12445 * @name polygonToLine
12446 * @param {Feature<Polygon|MultiPolygon>} polygon Feature to convert
12447 * @param {Object} [options={}] Optional parameters
12448 * @param {Object} [options.properties={}] translates GeoJSON properties to Feature
12449 * @returns {FeatureCollection|Feature<LineString|MultiLinestring>} converted (Multi)Polygon to (Multi)LineString
12450 * @example
12451 * var poly = turf.polygon([[[125, -30], [145, -30], [145, -20], [125, -20], [125, -30]]]);
12452 *
12453 * var line = turf.polygonToLine(poly);
12454 *
12455 * //addToMap
12456 * var addToMap = [line];
12457 */
12458function polygonToLine(polygon$$1, options) {
12459 // Optional parameters
12460 options = options || {};
12461 if (!isObject(options)) throw new Error('options is invalid');
12462 var properties = options.properties;
12463
12464 // Variables
12465 var geom = getType(polygon$$1);
12466 var coords = getCoords(polygon$$1);
12467 properties = properties || polygon$$1.properties || {};
12468
12469 if (!coords.length) throw new Error('polygon must contain coordinates');
12470
12471 switch (geom) {
12472 case 'Polygon':
12473 return coordsToLine(coords, properties);
12474 case 'MultiPolygon':
12475 var lines = [];
12476 coords.forEach(function (coord) {
12477 lines.push(coordsToLine(coord, properties));
12478 });
12479 return featureCollection(lines);
12480 default:
12481 throw new Error('geom ' + geom + ' not supported');
12482 }
12483}
12484
12485function coordsToLine(coords, properties) {
12486 if (coords.length > 1) return multiLineString(coords, properties);
12487 return lineString(coords[0], properties);
12488}
12489
12490/**
12491 * Converts (Multi)LineString(s) to Polygon(s).
12492 *
12493 * @name lineToPolygon
12494 * @param {FeatureCollection|Feature<LineString|MultiLineString>} lines Features to convert
12495 * @param {Object} [options={}] Optional parameters
12496 * @param {Object} [options.properties={}] translates GeoJSON properties to Feature
12497 * @param {boolean} [options.autoComplete=true] auto complete linestrings (matches first & last coordinates)
12498 * @param {boolean} [options.orderCoords=true] sorts linestrings to place outer ring at the first position of the coordinates
12499 * @returns {Feature<Polygon|MultiPolygon>} converted to Polygons
12500 * @example
12501 * var line = turf.lineString([[125, -30], [145, -30], [145, -20], [125, -20], [125, -30]]);
12502 *
12503 * var polygon = turf.lineToPolygon(line);
12504 *
12505 * //addToMap
12506 * var addToMap = [polygon];
12507 */
12508function lineToPolygon(lines, options) {
12509 // Optional parameters
12510 options = options || {};
12511 if (!isObject(options)) throw new Error('options is invalid');
12512 var properties = options.properties;
12513 var autoComplete = options.autoComplete;
12514 var orderCoords = options.orderCoords;
12515
12516 // validation
12517 if (!lines) throw new Error('lines is required');
12518
12519 // default params
12520 autoComplete = (autoComplete !== undefined) ? autoComplete : true;
12521 orderCoords = (orderCoords !== undefined) ? orderCoords : true;
12522 var type = getType(lines);
12523
12524 switch (type) {
12525 case 'FeatureCollection':
12526 case 'GeometryCollection':
12527 var coords = [];
12528 var features = (lines.features) ? lines.features : lines.geometries;
12529 features.forEach(function (line) {
12530 coords.push(getCoords(lineStringToPolygon(line, {}, autoComplete, orderCoords)));
12531 });
12532 return multiPolygon(coords, properties);
12533 }
12534 return lineStringToPolygon(lines, properties, autoComplete, orderCoords);
12535}
12536
12537/**
12538 * LineString to Polygon
12539 *
12540 * @private
12541 * @param {Feature<LineString|MultiLineString>} line line
12542 * @param {Object} [properties] translates GeoJSON properties to Feature
12543 * @param {boolean} [autoComplete=true] auto complete linestrings
12544 * @param {boolean} [orderCoords=true] sorts linestrings to place outer ring at the first position of the coordinates
12545 * @returns {Feature<Polygon>} line converted to Polygon
12546 */
12547function lineStringToPolygon(line, properties, autoComplete, orderCoords) {
12548 properties = properties || line.properties || {};
12549 var coords = getCoords(line);
12550 var type = getType(line);
12551
12552 if (!coords.length) throw new Error('line must contain coordinates');
12553
12554 switch (type) {
12555 case 'LineString':
12556 if (autoComplete) coords = autoCompleteCoords(coords);
12557 return polygon([coords], properties);
12558 case 'MultiLineString':
12559 var multiCoords = [];
12560 var largestArea = 0;
12561
12562 coords.forEach(function (coord) {
12563 if (autoComplete) coord = autoCompleteCoords(coord);
12564
12565 // Largest LineString to be placed in the first position of the coordinates array
12566 if (orderCoords) {
12567 var area = calculateArea$1(bbox(lineString(coord)));
12568 if (area > largestArea) {
12569 multiCoords.unshift(coord);
12570 largestArea = area;
12571 } else multiCoords.push(coord);
12572 } else {
12573 multiCoords.push(coord);
12574 }
12575 });
12576 return polygon(multiCoords, properties);
12577 default:
12578 throw new Error('geometry type ' + type + ' is not supported');
12579 }
12580}
12581
12582/**
12583 * Auto Complete Coords - matches first & last coordinates
12584 *
12585 * @private
12586 * @param {Array<Array<number>>} coords Coordinates
12587 * @returns {Array<Array<number>>} auto completed coordinates
12588 */
12589function autoCompleteCoords(coords) {
12590 var first = coords[0];
12591 var x1 = first[0];
12592 var y1 = first[1];
12593 var last = coords[coords.length - 1];
12594 var x2 = last[0];
12595 var y2 = last[1];
12596 if (x1 !== x2 || y1 !== y2) {
12597 coords.push(first);
12598 }
12599 return coords;
12600}
12601
12602/**
12603 * area - quick approximate area calculation (used to sort)
12604 *
12605 * @private
12606 * @param {Array<number>} bbox BBox [west, south, east, north]
12607 * @returns {number} very quick area calculation
12608 */
12609function calculateArea$1(bbox$$1) {
12610 var west = bbox$$1[0];
12611 var south = bbox$$1[1];
12612 var east = bbox$$1[2];
12613 var north = bbox$$1[3];
12614 return Math.abs(west - east) * Math.abs(south - north);
12615}
12616
12617var lineclip_1 = lineclip;
12618
12619lineclip.polyline = lineclip;
12620lineclip.polygon = polygonclip;
12621
12622
12623// Cohen-Sutherland line clippign algorithm, adapted to efficiently
12624// handle polylines rather than just segments
12625
12626function lineclip(points, bbox, result) {
12627
12628 var len = points.length,
12629 codeA = bitCode(points[0], bbox),
12630 part = [],
12631 i, a, b, codeB, lastCode;
12632
12633 if (!result) result = [];
12634
12635 for (i = 1; i < len; i++) {
12636 a = points[i - 1];
12637 b = points[i];
12638 codeB = lastCode = bitCode(b, bbox);
12639
12640 while (true) {
12641
12642 if (!(codeA | codeB)) { // accept
12643 part.push(a);
12644
12645 if (codeB !== lastCode) { // segment went outside
12646 part.push(b);
12647
12648 if (i < len - 1) { // start a new line
12649 result.push(part);
12650 part = [];
12651 }
12652 } else if (i === len - 1) {
12653 part.push(b);
12654 }
12655 break;
12656
12657 } else if (codeA & codeB) { // trivial reject
12658 break;
12659
12660 } else if (codeA) { // a outside, intersect with clip edge
12661 a = intersect$1(a, b, codeA, bbox);
12662 codeA = bitCode(a, bbox);
12663
12664 } else { // b outside
12665 b = intersect$1(a, b, codeB, bbox);
12666 codeB = bitCode(b, bbox);
12667 }
12668 }
12669
12670 codeA = lastCode;
12671 }
12672
12673 if (part.length) result.push(part);
12674
12675 return result;
12676}
12677
12678// Sutherland-Hodgeman polygon clipping algorithm
12679
12680function polygonclip(points, bbox) {
12681
12682 var result, edge, prev, prevInside, i, p, inside;
12683
12684 // clip against each side of the clip rectangle
12685 for (edge = 1; edge <= 8; edge *= 2) {
12686 result = [];
12687 prev = points[points.length - 1];
12688 prevInside = !(bitCode(prev, bbox) & edge);
12689
12690 for (i = 0; i < points.length; i++) {
12691 p = points[i];
12692 inside = !(bitCode(p, bbox) & edge);
12693
12694 // if segment goes through the clip window, add an intersection
12695 if (inside !== prevInside) result.push(intersect$1(prev, p, edge, bbox));
12696
12697 if (inside) result.push(p); // add a point if it's inside
12698
12699 prev = p;
12700 prevInside = inside;
12701 }
12702
12703 points = result;
12704
12705 if (!points.length) break;
12706 }
12707
12708 return result;
12709}
12710
12711// intersect a segment against one of the 4 lines that make up the bbox
12712
12713function intersect$1(a, b, edge, bbox) {
12714 return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox[3] - a[1]) / (b[1] - a[1]), bbox[3]] : // top
12715 edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox[1] - a[1]) / (b[1] - a[1]), bbox[1]] : // bottom
12716 edge & 2 ? [bbox[2], a[1] + (b[1] - a[1]) * (bbox[2] - a[0]) / (b[0] - a[0])] : // right
12717 edge & 1 ? [bbox[0], a[1] + (b[1] - a[1]) * (bbox[0] - a[0]) / (b[0] - a[0])] : // left
12718 null;
12719}
12720
12721// bit code reflects the point position relative to the bbox:
12722
12723// left mid right
12724// top 1001 1000 1010
12725// mid 0001 0000 0010
12726// bottom 0101 0100 0110
12727
12728function bitCode(p, bbox) {
12729 var code = 0;
12730
12731 if (p[0] < bbox[0]) code |= 1; // left
12732 else if (p[0] > bbox[2]) code |= 2; // right
12733
12734 if (p[1] < bbox[1]) code |= 4; // bottom
12735 else if (p[1] > bbox[3]) code |= 8; // top
12736
12737 return code;
12738}
12739
12740/**
12741 * Takes a {@link Feature} and a bbox and clips the feature to the bbox using [lineclip](https://github.com/mapbox/lineclip).
12742 * May result in degenerate edges when clipping Polygons.
12743 *
12744 * @name bboxClip
12745 * @param {Feature<LineString|MultiLineString|Polygon|MultiPolygon>} feature feature to clip to the bbox
12746 * @param {BBox} bbox extent in [minX, minY, maxX, maxY] order
12747 * @returns {Feature<LineString|MultiLineString|Polygon|MultiPolygon>} clipped Feature
12748 * @example
12749 * var bbox = [0, 0, 10, 10];
12750 * var poly = turf.polygon([[[2, 2], [8, 4], [12, 8], [3, 7], [2, 2]]]);
12751 *
12752 * var clipped = turf.bboxClip(poly, bbox);
12753 *
12754 * //addToMap
12755 * var addToMap = [bbox, poly, clipped]
12756 */
12757function bboxClip(feature$$1, bbox) {
12758 var geom = getGeom$1(feature$$1);
12759 var coords = getCoords(feature$$1);
12760 var properties = feature$$1.properties;
12761
12762 switch (geom) {
12763 case 'LineString':
12764 case 'MultiLineString':
12765 var lines = [];
12766 if (geom === 'LineString') coords = [coords];
12767 coords.forEach(function (line) {
12768 lineclip_1(line, bbox, lines);
12769 });
12770 if (lines.length === 1) return lineString(lines[0], properties);
12771 return multiLineString(lines, properties);
12772 case 'Polygon':
12773 return polygon(clipPolygon(coords, bbox), properties);
12774 case 'MultiPolygon':
12775 return multiPolygon(coords.map(function (polygon$$1) {
12776 return clipPolygon(polygon$$1, bbox);
12777 }), properties);
12778 default:
12779 throw new Error('geometry ' + geom + ' not supported');
12780 }
12781}
12782
12783function clipPolygon(rings, bbox) {
12784 var outRings = [];
12785 for (var i = 0; i < rings.length; i++) {
12786 var clipped = lineclip_1.polygon(rings[i], bbox);
12787 if (clipped.length > 0) {
12788 if (clipped[0][0] !== clipped[clipped.length - 1][0] || clipped[0][1] !== clipped[clipped.length - 1][1]) {
12789 clipped.push(clipped[0]);
12790 }
12791 if (clipped.length >= 4) {
12792 outRings.push(clipped);
12793 }
12794 }
12795 }
12796 return outRings;
12797}
12798
12799function getGeom$1(feature$$1) {
12800 return (feature$$1.geometry) ? feature$$1.geometry.type : feature$$1.type;
12801}
12802
12803var pSlice = Array.prototype.slice;
12804
12805function isArguments(object) {
12806 return Object.prototype.toString.call(object) === '[object Arguments]';
12807}
12808
12809function deepEqual(actual, expected, opts) {
12810 if (!opts) opts = {};
12811 // 7.1. All identical values are equivalent, as determined by ===.
12812 if (actual === expected) {
12813 return true;
12814
12815 } else if (actual instanceof Date && expected instanceof Date) {
12816 return actual.getTime() === expected.getTime();
12817
12818 // 7.3. Other pairs that do not both pass typeof value == 'object',
12819 // equivalence is determined by ==.
12820 } else if (!actual || !expected || typeof actual != 'object' && typeof expected != 'object') {
12821 return opts.strict ? actual === expected : actual === expected;
12822
12823 // 7.4. For all other Object pairs, including Array objects, equivalence is
12824 // determined by having the same number of owned properties (as verified
12825 // with Object.prototype.hasOwnProperty.call), the same set of keys
12826 // (although not necessarily the same order), equivalent values for every
12827 // corresponding key, and an identical 'prototype' property. Note: this
12828 // accounts for both named and indexed properties on Arrays.
12829 } else {
12830 return objEquiv(actual, expected, opts);
12831 }
12832}
12833
12834function isUndefinedOrNull(value) {
12835 return value === null || value === undefined;
12836}
12837
12838function isBuffer(x) {
12839 if (!x || typeof x !== 'object' || typeof x.length !== 'number') return false;
12840 if (typeof x.copy !== 'function' || typeof x.slice !== 'function') {
12841 return false;
12842 }
12843 if (x.length > 0 && typeof x[0] !== 'number') return false;
12844 return true;
12845}
12846
12847function objEquiv(a, b, opts) {
12848 var i, key;
12849 if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
12850 return false;
12851 // an identical 'prototype' property.
12852 if (a.prototype !== b.prototype) return false;
12853 //~~~I've managed to break Object.keys through screwy arguments passing.
12854 // Converting to array solves the problem.
12855 if (isArguments(a)) {
12856 if (!isArguments(b)) {
12857 return false;
12858 }
12859 a = pSlice.call(a);
12860 b = pSlice.call(b);
12861 return deepEqual(a, b, opts);
12862 }
12863 if (isBuffer(a)) {
12864 if (!isBuffer(b)) {
12865 return false;
12866 }
12867 if (a.length !== b.length) return false;
12868 for (i = 0; i < a.length; i++) {
12869 if (a[i] !== b[i]) return false;
12870 }
12871 return true;
12872 }
12873 try {
12874 var ka = Object.keys(a),
12875 kb = Object.keys(b);
12876 } catch (e) { //happens when one is a string literal and the other isn't
12877 return false;
12878 }
12879 // having the same number of owned properties (keys incorporates
12880 // hasOwnProperty)
12881 if (ka.length !== kb.length)
12882 return false;
12883 //the same set of keys (although not necessarily the same order),
12884 ka.sort();
12885 kb.sort();
12886 //~~~cheap key test
12887 for (i = ka.length - 1; i >= 0; i--) {
12888 if (ka[i] !== kb[i])
12889 return false;
12890 }
12891 //equivalent values for every corresponding key, and
12892 //~~~possibly expensive deep test
12893 for (i = ka.length - 1; i >= 0; i--) {
12894 key = ka[i];
12895 if (!deepEqual(a[key], b[key], opts)) return false;
12896 }
12897 return typeof a === typeof b;
12898}
12899
12900/**
12901 * Takes any LineString or Polygon and returns the overlapping lines between both features.
12902 *
12903 * @name lineOverlap
12904 * @param {Geometry|Feature<LineString|MultiLineString|Polygon|MultiPolygon>} line1 any LineString or Polygon
12905 * @param {Geometry|Feature<LineString|MultiLineString|Polygon|MultiPolygon>} line2 any LineString or Polygon
12906 * @param {Object} [options={}] Optional parameters
12907 * @param {number} [options.tolerance=0] Tolerance distance to match overlapping line segments (in kilometers)
12908 * @returns {FeatureCollection<LineString>} lines(s) that are overlapping between both features
12909 * @example
12910 * var line1 = turf.lineString([[115, -35], [125, -30], [135, -30], [145, -35]]);
12911 * var line2 = turf.lineString([[115, -25], [125, -30], [135, -30], [145, -25]]);
12912 *
12913 * var overlapping = turf.lineOverlap(line1, line2);
12914 *
12915 * //addToMap
12916 * var addToMap = [line1, line2, overlapping]
12917 */
12918function lineOverlap(line1, line2, options) {
12919 // Optional parameters
12920 options = options || {};
12921 if (!isObject(options)) throw new Error('options is invalid');
12922 var tolerance = options.tolerance || 0;
12923
12924 // Containers
12925 var features = [];
12926
12927 // Create Spatial Index
12928 var tree = geojsonRbush();
12929 tree.load(lineSegment(line1));
12930 var overlapSegment;
12931
12932 // Line Intersection
12933
12934 // Iterate over line segments
12935 segmentEach(line2, function (segment) {
12936 var doesOverlaps = false;
12937
12938 // Iterate over each segments which falls within the same bounds
12939 featureEach(tree.search(segment), function (match) {
12940 if (doesOverlaps === false) {
12941 var coordsSegment = getCoords(segment).sort();
12942 var coordsMatch = getCoords(match).sort();
12943
12944 // Segment overlaps feature
12945 if (deepEqual(coordsSegment, coordsMatch)) {
12946 doesOverlaps = true;
12947 // Overlaps already exists - only append last coordinate of segment
12948 if (overlapSegment) overlapSegment = concatSegment(overlapSegment, segment);
12949 else overlapSegment = segment;
12950 // Match segments which don't share nodes (Issue #901)
12951 } else if (
12952 (tolerance === 0) ?
12953 booleanPointOnLine(coordsSegment[0], match) && booleanPointOnLine(coordsSegment[1], match) :
12954 nearestPointOnLine(match, coordsSegment[0]).properties.dist <= tolerance &&
12955 nearestPointOnLine(match, coordsSegment[1]).properties.dist <= tolerance) {
12956 doesOverlaps = true;
12957 if (overlapSegment) overlapSegment = concatSegment(overlapSegment, segment);
12958 else overlapSegment = segment;
12959 } else if (
12960 (tolerance === 0) ?
12961 booleanPointOnLine(coordsMatch[0], segment) && booleanPointOnLine(coordsMatch[1], segment) :
12962 nearestPointOnLine(segment, coordsMatch[0]).properties.dist <= tolerance &&
12963 nearestPointOnLine(segment, coordsMatch[1]).properties.dist <= tolerance) {
12964 // Do not define (doesOverlap = true) since more matches can occur within the same segment
12965 // doesOverlaps = true;
12966 if (overlapSegment) overlapSegment = concatSegment(overlapSegment, match);
12967 else overlapSegment = match;
12968 }
12969 }
12970 });
12971
12972 // Segment doesn't overlap - add overlaps to results & reset
12973 if (doesOverlaps === false && overlapSegment) {
12974 features.push(overlapSegment);
12975 overlapSegment = undefined;
12976 }
12977 });
12978 // Add last segment if exists
12979 if (overlapSegment) features.push(overlapSegment);
12980
12981 return featureCollection(features);
12982}
12983
12984
12985/**
12986 * Concat Segment
12987 *
12988 * @private
12989 * @param {Feature<LineString>} line LineString
12990 * @param {Feature<LineString>} segment 2-vertex LineString
12991 * @returns {Feature<LineString>} concat linestring
12992 */
12993function concatSegment(line, segment) {
12994 var coords = getCoords(segment);
12995 var lineCoords = getCoords(line);
12996 var start = lineCoords[0];
12997 var end = lineCoords[lineCoords.length - 1];
12998 var geom = line.geometry.coordinates;
12999
13000 if (deepEqual(coords[0], start)) geom.unshift(coords[1]);
13001 else if (deepEqual(coords[0], end)) geom.push(coords[1]);
13002 else if (deepEqual(coords[1], start)) geom.unshift(coords[0]);
13003 else if (deepEqual(coords[1], end)) geom.push(coords[0]);
13004 return line;
13005}
13006
13007/**
13008 * Creates a circular sector of a circle of given radius and center {@link Point},
13009 * between (clockwise) bearing1 and bearing2; 0 bearing is North of center point, positive clockwise.
13010 *
13011 * @name sector
13012 * @param {Coord} center center point
13013 * @param {number} radius radius of the circle
13014 * @param {number} bearing1 angle, in decimal degrees, of the first radius of the sector
13015 * @param {number} bearing2 angle, in decimal degrees, of the second radius of the sector
13016 * @param {Object} [options={}] Optional parameters
13017 * @param {string} [options.units='kilometers'] miles, kilometers, degrees, or radians
13018 * @param {number} [options.steps=64] number of steps
13019 * @returns {Feature<Polygon>} sector polygon
13020 * @example
13021 * var center = turf.point([-75, 40]);
13022 * var radius = 5;
13023 * var bearing1 = 25;
13024 * var bearing2 = 45;
13025 *
13026 * var sector = turf.sector(center, radius, bearing1, bearing2);
13027 *
13028 * //addToMap
13029 * var addToMap = [center, sector];
13030 */
13031function sector(center, radius, bearing1, bearing2, options) {
13032 // Optional parameters
13033 options = options || {};
13034 if (!isObject(options)) throw new Error('options is invalid');
13035
13036 // validation
13037 if (!center) throw new Error('center is required');
13038 if (bearing1 === undefined || bearing1 === null) throw new Error('bearing1 is required');
13039 if (bearing2 === undefined || bearing2 === null) throw new Error('bearing2 is required');
13040 if (!radius) throw new Error('radius is required');
13041 if (typeof options !== 'object') throw new Error('options must be an object');
13042
13043 if (convertAngleTo360$1(bearing1) === convertAngleTo360$1(bearing2)) {
13044 return circle(center, radius, options);
13045 }
13046 var coords = getCoords(center);
13047 var arc = lineArc(center, radius, bearing1, bearing2, options);
13048 var sliceCoords = [[coords]];
13049 coordEach(arc, function (currentCoords) {
13050 sliceCoords[0].push(currentCoords);
13051 });
13052 sliceCoords[0].push(coords);
13053
13054 return polygon(sliceCoords);
13055}
13056
13057/**
13058 * Takes any angle in degrees
13059 * and returns a valid angle between 0-360 degrees
13060 *
13061 * @private
13062 * @param {number} alfa angle between -180-180 degrees
13063 * @returns {number} angle between 0-360 degrees
13064 */
13065function convertAngleTo360$1(alfa) {
13066 var beta = alfa % 360;
13067 if (beta < 0) beta += 360;
13068 return beta;
13069}
13070
13071// https://en.wikipedia.org/wiki/Rhumb_line
13072/**
13073 * Returns the destination {@link Point} having travelled the given distance along a Rhumb line from the
13074 * origin Point with the (varant) given bearing.
13075 *
13076 * @name rhumbDestination
13077 * @param {Coord} origin starting point
13078 * @param {number} distance distance from the starting point
13079 * @param {number} bearing varant bearing angle ranging from -180 to 180 degrees from north
13080 * @param {Object} [options={}] Optional parameters
13081 * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers
13082 * @param {Object} [options.properties={}] translate properties to destination point
13083 * @returns {Feature<Point>} Destination point.
13084 * @example
13085 * var pt = turf.point([-75.343, 39.984], {"marker-color": "F00"});
13086 * var distance = 50;
13087 * var bearing = 90;
13088 * var options = {units: 'miles'};
13089 *
13090 * var destination = turf.rhumbDestination(pt, distance, bearing, options);
13091 *
13092 * //addToMap
13093 * var addToMap = [pt, destination]
13094 * destination.properties['marker-color'] = '#00F';
13095 */
13096function rhumbDestination(origin, distance, bearing, options) {
13097 // Optional parameters
13098 options = options || {};
13099 if (!isObject(options)) throw new Error('options is invalid');
13100 var units = options.units;
13101 var properties = options.properties;
13102
13103 // validation
13104 if (!origin) throw new Error('origin is required');
13105 if (distance === undefined || distance === null) throw new Error('distance is required');
13106 if (bearing === undefined || bearing === null) throw new Error('bearing is required');
13107 if (!(distance >= 0)) throw new Error('distance must be greater than 0');
13108
13109 var distanceInMeters = convertLength(distance, units, 'meters');
13110 var coords = getCoord(origin);
13111 var destination = calculateRhumbDestination(coords, distanceInMeters, bearing);
13112
13113 // compensate the crossing of the 180th meridian (https://macwright.org/2016/09/26/the-180th-meridian.html)
13114 // solution from https://github.com/mapbox/mapbox-gl-js/issues/3250#issuecomment-294887678
13115 destination[0] += (destination[0] - coords[0] > 180) ? -360 : (coords[0] - destination[0] > 180) ? 360 : 0;
13116 return point(destination, properties);
13117}
13118
13119/**
13120 * Returns the destination point having travelled along a rhumb line from origin point the given
13121 * distance on the given bearing.
13122 * Adapted from Geodesy: http://www.movable-type.co.uk/scripts/latlong.html#rhumblines
13123 *
13124 * @private
13125 * @param {Array<number>} origin - point
13126 * @param {number} distance - Distance travelled, in same units as earth radius (default: metres).
13127 * @param {number} bearing - Bearing in degrees from north.
13128 * @param {number} [radius=6371e3] - (Mean) radius of earth (defaults to radius in metres).
13129 * @returns {Array<number>} Destination point.
13130 */
13131function calculateRhumbDestination(origin, distance, bearing, radius) {
13132 // φ => phi
13133 // λ => lambda
13134 // ψ => psi
13135 // Δ => Delta
13136 // δ => delta
13137 // θ => theta
13138
13139 radius = (radius === undefined) ? earthRadius : Number(radius);
13140
13141 var delta = distance / radius; // angular distance in radians
13142 var lambda1 = origin[0] * Math.PI / 180; // to radians, but without normalize to 𝜋
13143 var phi1 = degreesToRadians(origin[1]);
13144 var theta = degreesToRadians(bearing);
13145
13146 var DeltaPhi = delta * Math.cos(theta);
13147 var phi2 = phi1 + DeltaPhi;
13148
13149 // check for some daft bugger going past the pole, normalise latitude if so
13150 if (Math.abs(phi2) > Math.PI / 2) phi2 = phi2 > 0 ? Math.PI - phi2 : -Math.PI - phi2;
13151
13152 var DeltaPsi = Math.log(Math.tan(phi2 / 2 + Math.PI / 4) / Math.tan(phi1 / 2 + Math.PI / 4));
13153 var q = Math.abs(DeltaPsi) > 10e-12 ? DeltaPhi / DeltaPsi : Math.cos(phi1); // E-W course becomes ill-conditioned with 0/0
13154
13155 var DeltaLambda = delta * Math.sin(theta) / q;
13156 var lambda2 = lambda1 + DeltaLambda;
13157
13158 return [((lambda2 * 180 / Math.PI) + 540) % 360 - 180, phi2 * 180 / Math.PI]; // normalise to −180..+180°
13159}
13160
13161/**
13162 * Finds the tangents of a {@link Polygon|(Multi)Polygon} from a {@link Point}.
13163 *
13164 * @name polygonTangents
13165 * @param {Coord} pt to calculate the tangent points from
13166 * @param {Feature<Polygon|MultiPolygon>} polygon to get tangents from
13167 * @returns {FeatureCollection<Point>} Feature Collection containing the two tangent points
13168 * @example
13169 * var polygon = turf.polygon([[[11, 0], [22, 4], [31, 0], [31, 11], [21, 15], [11, 11], [11, 0]]]);
13170 * var point = turf.point([61, 5]);
13171 *
13172 * var tangents = turf.polygonTangents(point, polygon)
13173 *
13174 * //addToMap
13175 * var addToMap = [tangents, point, polygon];
13176 */
13177function polygonTangents(pt, polygon$$1) {
13178 var pointCoords = getCoords(pt);
13179 var polyCoords = getCoords(polygon$$1);
13180
13181 var rtan;
13182 var ltan;
13183 var enext;
13184 var eprev;
13185
13186 var type = getType(polygon$$1);
13187 switch (type) {
13188 case 'Polygon':
13189 rtan = polyCoords[0][0];
13190 ltan = polyCoords[0][0];
13191 eprev = isLeft(polyCoords[0][0], polyCoords[0][polyCoords[0].length - 1], pointCoords);
13192 var out = processPolygon$1(polyCoords[0], pointCoords, eprev, enext, rtan, ltan);
13193 rtan = out[0];
13194 ltan = out[1];
13195 break;
13196 case 'MultiPolygon':
13197 rtan = polyCoords[0][0][0];
13198 ltan = polyCoords[0][0][0];
13199 eprev = isLeft(polyCoords[0][0][0], polyCoords[0][0][polyCoords[0][0].length - 1], pointCoords);
13200 polyCoords.forEach(function (ring) {
13201 var out = processPolygon$1(ring[0], pointCoords, eprev, enext, rtan, ltan);
13202 rtan = out[0];
13203 ltan = out[1];
13204 });
13205 break;
13206 }
13207 return featureCollection([point(rtan), point(ltan)]);
13208}
13209
13210function processPolygon$1(polygonCoords, ptCoords, eprev, enext, rtan, ltan) {
13211 for (var i = 0; i < polygonCoords.length; i++) {
13212 var currentCoords = polygonCoords[i];
13213 var nextCoordPair = polygonCoords[i + 1];
13214 if (i === polygonCoords.length - 1) {
13215 nextCoordPair = polygonCoords[0];
13216 }
13217 enext = isLeft(currentCoords, nextCoordPair, ptCoords);
13218 if (eprev <= 0 && enext > 0) {
13219 if (!isBelow(ptCoords, currentCoords, rtan)) {
13220 rtan = currentCoords;
13221 }
13222 } else if (eprev > 0 && enext <= 0) {
13223 if (!isAbove(ptCoords, currentCoords, ltan)) {
13224 ltan = currentCoords;
13225 }
13226 }
13227 eprev = enext;
13228 }
13229 return [rtan, ltan];
13230}
13231
13232function isAbove(point1, point2, point3) {
13233 return isLeft(point1, point2, point3) > 0;
13234}
13235
13236function isBelow(point1, point2, point3) {
13237 return isLeft(point1, point2, point3) < 0;
13238}
13239
13240function isLeft(point1, point2, point3) {
13241 return (point2[0] - point1[0]) * (point3[1] - point1[1]) - (point3[0] - point1[0]) * (point2[1] - point1[1]);
13242}
13243
13244/**
13245 * Takes a ring and return true or false whether or not the ring is clockwise or counter-clockwise.
13246 *
13247 * @name booleanClockwise
13248 * @param {Feature<LineString>} line to be evaluated
13249 * @returns {boolean} true/false
13250 * @example
13251 * var clockwiseRing = turf.lineString([[0,0],[1,1],[1,0],[0,0]]);
13252 * var counterClockwiseRing = turf.lineString([[0,0],[1,0],[1,1],[0,0]]);
13253 *
13254 * turf.booleanClockwise(clockwiseRing)
13255 * //=true
13256 * turf.booleanClockwise(counterClockwiseRing)
13257 * //=false
13258 */
13259function booleanClockwise(line) {
13260 // validation
13261 if (!line) throw new Error('line is required');
13262 var type = (line.geometry) ? line.geometry.type : line.type;
13263 if (!Array.isArray(line) && type !== 'LineString') throw new Error('geometry must be a LineString');
13264
13265 var ring = getCoords(line);
13266 var sum = 0;
13267 var i = 1;
13268 var prev, cur;
13269 while (i < ring.length) {
13270 prev = cur || ring[0];
13271 cur = ring[i];
13272 sum += ((cur[0] - prev[0]) * (cur[1] + prev[1]));
13273 i++;
13274 }
13275 return sum > 0;
13276}
13277
13278/**
13279 * Rewind {@link LineString|(Multi)LineString} or {@link Polygon|(Multi)Polygon} outer ring counterclockwise and inner rings clockwise (Uses {@link http://en.wikipedia.org/wiki/Shoelace_formula|Shoelace Formula}).
13280 *
13281 * @name rewind
13282 * @param {GeoJSON} geojson input GeoJSON Polygon
13283 * @param {Object} [options={}] Optional parameters
13284 * @param {boolean} [options.reverse=false] enable reverse winding
13285 * @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated (significant performance increase if true)
13286 * @returns {GeoJSON} rewind Polygon
13287 * @example
13288 * var polygon = turf.polygon([[[121, -29], [138, -29], [138, -18], [121, -18], [121, -29]]]);
13289 *
13290 * var rewind = turf.rewind(polygon);
13291 *
13292 * //addToMap
13293 * var addToMap = [rewind];
13294 */
13295function rewind(geojson, options) {
13296 // Optional parameters
13297 options = options || {};
13298 if (!isObject(options)) throw new Error('options is invalid');
13299 var reverse = options.reverse || false;
13300 var mutate = options.mutate || false;
13301
13302 // validation
13303 if (!geojson) throw new Error('<geojson> is required');
13304 if (typeof reverse !== 'boolean') throw new Error('<reverse> must be a boolean');
13305 if (typeof mutate !== 'boolean') throw new Error('<mutate> must be a boolean');
13306
13307 // prevent input mutation
13308 if (mutate === false) geojson = clone(geojson);
13309
13310 // Support Feature Collection or Geometry Collection
13311 var results = [];
13312 switch (geojson.type) {
13313 case 'GeometryCollection':
13314 geomEach(geojson, function (geometry$$1) {
13315 rewindFeature(geometry$$1, reverse);
13316 });
13317 return geojson;
13318 case 'FeatureCollection':
13319 featureEach(geojson, function (feature$$1) {
13320 featureEach(rewindFeature(feature$$1, reverse), function (result) {
13321 results.push(result);
13322 });
13323 });
13324 return featureCollection(results);
13325 }
13326 // Support Feature or Geometry Objects
13327 return rewindFeature(geojson, reverse);
13328}
13329
13330/**
13331 * Rewind
13332 *
13333 * @private
13334 * @param {Geometry|Feature<any>} geojson Geometry or Feature
13335 * @param {Boolean} [reverse=false] enable reverse winding
13336 * @returns {Geometry|Feature<any>} rewind Geometry or Feature
13337 */
13338function rewindFeature(geojson, reverse) {
13339 var type = (geojson.type === 'Feature') ? geojson.geometry.type : geojson.type;
13340
13341 // Support all GeoJSON Geometry Objects
13342 switch (type) {
13343 case 'GeometryCollection':
13344 geomEach(geojson, function (geometry$$1) {
13345 rewindFeature(geometry$$1, reverse);
13346 });
13347 return geojson;
13348 case 'LineString':
13349 rewindLineString(getCoords(geojson), reverse);
13350 return geojson;
13351 case 'Polygon':
13352 rewindPolygon(getCoords(geojson), reverse);
13353 return geojson;
13354 case 'MultiLineString':
13355 getCoords(geojson).forEach(function (lineCoords) {
13356 rewindLineString(lineCoords, reverse);
13357 });
13358 return geojson;
13359 case 'MultiPolygon':
13360 getCoords(geojson).forEach(function (lineCoords) {
13361 rewindPolygon(lineCoords, reverse);
13362 });
13363 return geojson;
13364 case 'Point':
13365 case 'MultiPoint':
13366 return geojson;
13367 }
13368}
13369
13370/**
13371 * Rewind LineString - outer ring clockwise
13372 *
13373 * @private
13374 * @param {Array<Array<number>>} coords GeoJSON LineString geometry coordinates
13375 * @param {Boolean} [reverse=false] enable reverse winding
13376 * @returns {void} mutates coordinates
13377 */
13378function rewindLineString(coords, reverse) {
13379 if (booleanClockwise(coords) === reverse) coords.reverse();
13380}
13381
13382/**
13383 * Rewind Polygon - outer ring counterclockwise and inner rings clockwise.
13384 *
13385 * @private
13386 * @param {Array<Array<Array<number>>>} coords GeoJSON Polygon geometry coordinates
13387 * @param {Boolean} [reverse=false] enable reverse winding
13388 * @returns {void} mutates coordinates
13389 */
13390function rewindPolygon(coords, reverse) {
13391 // outer ring
13392 if (booleanClockwise(coords[0]) !== reverse) {
13393 coords[0].reverse();
13394 }
13395 // inner rings
13396 for (var i = 1; i < coords.length; i++) {
13397 if (booleanClockwise(coords[i]) === reverse) {
13398 coords[i].reverse();
13399 }
13400 }
13401}
13402
13403/**
13404 * Takes a {@link Point} grid and returns a correspondent matrix {Array<Array<number>>}
13405 * of the 'property' values
13406 *
13407 * @name gridToMatrix
13408 * @param {FeatureCollection<Point>} grid of points
13409 * @param {Object} [options={}] Optional parameters
13410 * @param {string} [options.zProperty='elevation'] the property name in `points` from which z-values will be pulled
13411 * @param {boolean} [options.flip=false] returns the matrix upside-down
13412 * @param {boolean} [options.flags=false] flags, adding a `matrixPosition` array field ([row, column]) to its properties,
13413 * the grid points with coordinates on the matrix
13414 * @returns {Array<Array<number>>} matrix of property values
13415 * @example
13416 * var extent = [-70.823364, -33.553984, -70.473175, -33.302986];
13417 * var cellSize = 3;
13418 * var grid = turf.pointGrid(extent, cellSize);
13419 * // add a random property to each point between 0 and 60
13420 * for (var i = 0; i < grid.features.length; i++) {
13421 * grid.features[i].properties.elevation = (Math.random() * 60);
13422 * }
13423 * gridToMatrix(grid);
13424 * //= [
13425 * [ 1, 13, 10, 9, 10, 13, 18],
13426 * [34, 8, 5, 4, 5, 8, 13],
13427 * [10, 5, 2, 1, 2, 5, 4],
13428 * [ 0, 4, 56, 19, 1, 4, 9],
13429 * [10, 5, 2, 1, 2, 5, 10],
13430 * [57, 8, 5, 4, 5, 0, 57],
13431 * [ 3, 13, 10, 9, 5, 13, 18],
13432 * [18, 13, 10, 9, 78, 13, 18]
13433 * ]
13434 */
13435function gridToMatrix$1(grid, options) {
13436 // Optional parameters
13437 options = options || {};
13438 if (!isObject(options)) throw new Error('options is invalid');
13439 var zProperty = options.zProperty || 'elevation';
13440 var flip = options.flip;
13441 var flags = options.flags;
13442
13443 // validation
13444 collectionOf(grid, 'Point', 'input must contain Points');
13445
13446 var pointsMatrix = sortPointsByLatLng$1(grid, flip);
13447
13448 var matrix = [];
13449 // create property matrix from sorted points
13450 // looping order matters here
13451 for (var r = 0; r < pointsMatrix.length; r++) {
13452 var pointRow = pointsMatrix[r];
13453 var row = [];
13454 for (var c = 0; c < pointRow.length; c++) {
13455 var point$$1 = pointRow[c];
13456 // Check if zProperty exist
13457 if (point$$1.properties[zProperty]) row.push(point$$1.properties[zProperty]);
13458 else row.push(0);
13459 // add flags
13460 if (flags === true) point$$1.properties.matrixPosition = [r, c];
13461 }
13462 matrix.push(row);
13463 }
13464
13465 return matrix;
13466}
13467
13468/**
13469 * Sorts points by latitude and longitude, creating a 2-dimensional array of points
13470 *
13471 * @private
13472 * @param {FeatureCollection<Point>} points GeoJSON Point features
13473 * @param {boolean} [flip=false] returns the matrix upside-down
13474 * @returns {Array<Array<Point>>} points ordered by latitude and longitude
13475 */
13476function sortPointsByLatLng$1(points$$1, flip) {
13477 var pointsByLatitude = {};
13478
13479 // divide points by rows with the same latitude
13480 featureEach(points$$1, function (point$$1) {
13481 var lat = getCoords(point$$1)[1];
13482 if (!pointsByLatitude[lat]) pointsByLatitude[lat] = [];
13483 pointsByLatitude[lat].push(point$$1);
13484 });
13485
13486 // sort points (with the same latitude) by longitude
13487 var orderedRowsByLatitude = Object.keys(pointsByLatitude).map(function (lat) {
13488 var row = pointsByLatitude[lat];
13489 var rowOrderedByLongitude = row.sort(function (a, b) {
13490 return getCoords(a)[0] - getCoords(b)[0];
13491 });
13492 return rowOrderedByLongitude;
13493 });
13494
13495 // sort rows (of points with the same latitude) by latitude
13496 var pointMatrix = orderedRowsByLatitude.sort(function (a, b) {
13497 if (flip) return getCoords(a[0])[1] - getCoords(b[0])[1];
13498 else return getCoords(b[0])[1] - getCoords(a[0])[1];
13499 });
13500
13501 return pointMatrix;
13502}
13503
13504/*!
13505* @license GNU Affero General Public License.
13506* Copyright (c) 2015, 2015 Ronny Lorenz <ronny@tbi.univie.ac.at>
13507* v. 1.2.0
13508* https://github.com/RaumZeit/MarchingSquares.js
13509*/
13510
13511var defaultSettings$1 = {
13512 successCallback: null,
13513 verbose: false,
13514 polygons: false
13515};
13516
13517var settings$1 = {};
13518
13519/*
13520 Compute isobands(s) of a scalar 2D field given a certain
13521 threshold and a bandwidth by applying the Marching Squares
13522 Algorithm. The function returns a list of path coordinates
13523 either for individual polygons within each grid cell, or the
13524 outline of connected polygons.
13525*/
13526function isoBands(data, minV, bandwidth, options) {
13527 /* process options */
13528 options = options ? options : {};
13529
13530 var optionKeys = Object.keys(defaultSettings$1);
13531
13532 for (var i = 0; i < optionKeys.length; i++) {
13533 var key = optionKeys[i];
13534 var val = options[key];
13535 val = ((typeof val !== 'undefined') && (val !== null)) ? val : defaultSettings$1[key];
13536
13537 settings$1[key] = val;
13538 }
13539
13540 if (settings$1.verbose)
13541 console.log('MarchingSquaresJS-isoBands: computing isobands for [' + minV + ':' + (minV + bandwidth) + ']');
13542
13543 var grid = computeBandGrid(data, minV, bandwidth);
13544
13545 var ret;
13546 if (settings$1.polygons) {
13547 if (settings$1.verbose)
13548 console.log('MarchingSquaresJS-isoBands: returning single polygons for each grid cell');
13549 ret = BandGrid2Areas(grid);
13550 } else {
13551 if (settings$1.verbose)
13552 console.log('MarchingSquaresJS-isoBands: returning polygon paths for entire data grid');
13553 ret = BandGrid2AreaPaths(grid);
13554 }
13555
13556 if (typeof settings$1.successCallback === 'function')
13557 settings$1.successCallback(ret);
13558
13559 return ret;
13560}
13561
13562/*
13563 Thats all for the public interface, below follows the actual
13564 implementation
13565*/
13566
13567/* Some private variables */
13568var Node0 = 64;
13569var Node1 = 16;
13570var Node2 = 4;
13571var Node3 = 1;
13572
13573/*
13574 The look-up tables for tracing back the contour path
13575 of isoBands
13576*/
13577
13578var isoBandNextXTL = [];
13579var isoBandNextYTL = [];
13580var isoBandNextOTL = [];
13581
13582var isoBandNextXTR = [];
13583var isoBandNextYTR = [];
13584var isoBandNextOTR = [];
13585
13586var isoBandNextXRT = [];
13587var isoBandNextYRT = [];
13588var isoBandNextORT = [];
13589
13590var isoBandNextXRB = [];
13591var isoBandNextYRB = [];
13592var isoBandNextORB = [];
13593
13594var isoBandNextXBL = [];
13595var isoBandNextYBL = [];
13596var isoBandNextOBL = [];
13597
13598var isoBandNextXBR = [];
13599var isoBandNextYBR = [];
13600var isoBandNextOBR = [];
13601
13602var isoBandNextXLT = [];
13603var isoBandNextYLT = [];
13604var isoBandNextOLT = [];
13605
13606var isoBandNextXLB = [];
13607var isoBandNextYLB = [];
13608var isoBandNextOLB = [];
13609
13610isoBandNextXRT[85] = isoBandNextXRB[85] = -1;
13611isoBandNextYRT[85] = isoBandNextYRB[85] = 0;
13612isoBandNextORT[85] = isoBandNextORB[85] = 1;
13613isoBandNextXLT[85] = isoBandNextXLB[85] = 1;
13614isoBandNextYLT[85] = isoBandNextYLB[85] = 0;
13615isoBandNextOLT[85] = isoBandNextOLB[85] = 1;
13616
13617isoBandNextXTL[85] = isoBandNextXTR[85] = 0;
13618isoBandNextYTL[85] = isoBandNextYTR[85] = -1;
13619isoBandNextOTL[85] = isoBandNextOBL[85] = 0;
13620isoBandNextXBR[85] = isoBandNextXBL[85] = 0;
13621isoBandNextYBR[85] = isoBandNextYBL[85] = 1;
13622isoBandNextOTR[85] = isoBandNextOBR[85] = 1;
13623
13624
13625/* triangle cases */
13626isoBandNextXLB[1] = isoBandNextXLB[169] = 0;
13627isoBandNextYLB[1] = isoBandNextYLB[169] = -1;
13628isoBandNextOLB[1] = isoBandNextOLB[169] = 0;
13629isoBandNextXBL[1] = isoBandNextXBL[169] = -1;
13630isoBandNextYBL[1] = isoBandNextYBL[169] = 0;
13631isoBandNextOBL[1] = isoBandNextOBL[169] = 0;
13632
13633isoBandNextXRB[4] = isoBandNextXRB[166] = 0;
13634isoBandNextYRB[4] = isoBandNextYRB[166] = -1;
13635isoBandNextORB[4] = isoBandNextORB[166] = 1;
13636isoBandNextXBR[4] = isoBandNextXBR[166] = 1;
13637isoBandNextYBR[4] = isoBandNextYBR[166] = 0;
13638isoBandNextOBR[4] = isoBandNextOBR[166] = 0;
13639
13640isoBandNextXRT[16] = isoBandNextXRT[154] = 0;
13641isoBandNextYRT[16] = isoBandNextYRT[154] = 1;
13642isoBandNextORT[16] = isoBandNextORT[154] = 1;
13643isoBandNextXTR[16] = isoBandNextXTR[154] = 1;
13644isoBandNextYTR[16] = isoBandNextYTR[154] = 0;
13645isoBandNextOTR[16] = isoBandNextOTR[154] = 1;
13646
13647isoBandNextXLT[64] = isoBandNextXLT[106] = 0;
13648isoBandNextYLT[64] = isoBandNextYLT[106] = 1;
13649isoBandNextOLT[64] = isoBandNextOLT[106] = 0;
13650isoBandNextXTL[64] = isoBandNextXTL[106] = -1;
13651isoBandNextYTL[64] = isoBandNextYTL[106] = 0;
13652isoBandNextOTL[64] = isoBandNextOTL[106] = 1;
13653
13654/* single trapezoid cases */
13655isoBandNextXLT[2] = isoBandNextXLT[168] = 0;
13656isoBandNextYLT[2] = isoBandNextYLT[168] = -1;
13657isoBandNextOLT[2] = isoBandNextOLT[168] = 1;
13658isoBandNextXLB[2] = isoBandNextXLB[168] = 0;
13659isoBandNextYLB[2] = isoBandNextYLB[168] = -1;
13660isoBandNextOLB[2] = isoBandNextOLB[168] = 0;
13661isoBandNextXBL[2] = isoBandNextXBL[168] = -1;
13662isoBandNextYBL[2] = isoBandNextYBL[168] = 0;
13663isoBandNextOBL[2] = isoBandNextOBL[168] = 0;
13664isoBandNextXBR[2] = isoBandNextXBR[168] = -1;
13665isoBandNextYBR[2] = isoBandNextYBR[168] = 0;
13666isoBandNextOBR[2] = isoBandNextOBR[168] = 1;
13667
13668isoBandNextXRT[8] = isoBandNextXRT[162] = 0;
13669isoBandNextYRT[8] = isoBandNextYRT[162] = -1;
13670isoBandNextORT[8] = isoBandNextORT[162] = 0;
13671isoBandNextXRB[8] = isoBandNextXRB[162] = 0;
13672isoBandNextYRB[8] = isoBandNextYRB[162] = -1;
13673isoBandNextORB[8] = isoBandNextORB[162] = 1;
13674isoBandNextXBL[8] = isoBandNextXBL[162] = 1;
13675isoBandNextYBL[8] = isoBandNextYBL[162] = 0;
13676isoBandNextOBL[8] = isoBandNextOBL[162] = 1;
13677isoBandNextXBR[8] = isoBandNextXBR[162] = 1;
13678isoBandNextYBR[8] = isoBandNextYBR[162] = 0;
13679isoBandNextOBR[8] = isoBandNextOBR[162] = 0;
13680
13681isoBandNextXRT[32] = isoBandNextXRT[138] = 0;
13682isoBandNextYRT[32] = isoBandNextYRT[138] = 1;
13683isoBandNextORT[32] = isoBandNextORT[138] = 1;
13684isoBandNextXRB[32] = isoBandNextXRB[138] = 0;
13685isoBandNextYRB[32] = isoBandNextYRB[138] = 1;
13686isoBandNextORB[32] = isoBandNextORB[138] = 0;
13687isoBandNextXTL[32] = isoBandNextXTL[138] = 1;
13688isoBandNextYTL[32] = isoBandNextYTL[138] = 0;
13689isoBandNextOTL[32] = isoBandNextOTL[138] = 0;
13690isoBandNextXTR[32] = isoBandNextXTR[138] = 1;
13691isoBandNextYTR[32] = isoBandNextYTR[138] = 0;
13692isoBandNextOTR[32] = isoBandNextOTR[138] = 1;
13693
13694isoBandNextXLB[128] = isoBandNextXLB[42] = 0;
13695isoBandNextYLB[128] = isoBandNextYLB[42] = 1;
13696isoBandNextOLB[128] = isoBandNextOLB[42] = 1;
13697isoBandNextXLT[128] = isoBandNextXLT[42] = 0;
13698isoBandNextYLT[128] = isoBandNextYLT[42] = 1;
13699isoBandNextOLT[128] = isoBandNextOLT[42] = 0;
13700isoBandNextXTL[128] = isoBandNextXTL[42] = -1;
13701isoBandNextYTL[128] = isoBandNextYTL[42] = 0;
13702isoBandNextOTL[128] = isoBandNextOTL[42] = 1;
13703isoBandNextXTR[128] = isoBandNextXTR[42] = -1;
13704isoBandNextYTR[128] = isoBandNextYTR[42] = 0;
13705isoBandNextOTR[128] = isoBandNextOTR[42] = 0;
13706
13707/* single rectangle cases */
13708isoBandNextXRB[5] = isoBandNextXRB[165] = -1;
13709isoBandNextYRB[5] = isoBandNextYRB[165] = 0;
13710isoBandNextORB[5] = isoBandNextORB[165] = 0;
13711isoBandNextXLB[5] = isoBandNextXLB[165] = 1;
13712isoBandNextYLB[5] = isoBandNextYLB[165] = 0;
13713isoBandNextOLB[5] = isoBandNextOLB[165] = 0;
13714
13715isoBandNextXBR[20] = isoBandNextXBR[150] = 0;
13716isoBandNextYBR[20] = isoBandNextYBR[150] = 1;
13717isoBandNextOBR[20] = isoBandNextOBR[150] = 1;
13718isoBandNextXTR[20] = isoBandNextXTR[150] = 0;
13719isoBandNextYTR[20] = isoBandNextYTR[150] = -1;
13720isoBandNextOTR[20] = isoBandNextOTR[150] = 1;
13721
13722isoBandNextXRT[80] = isoBandNextXRT[90] = -1;
13723isoBandNextYRT[80] = isoBandNextYRT[90] = 0;
13724isoBandNextORT[80] = isoBandNextORT[90] = 1;
13725isoBandNextXLT[80] = isoBandNextXLT[90] = 1;
13726isoBandNextYLT[80] = isoBandNextYLT[90] = 0;
13727isoBandNextOLT[80] = isoBandNextOLT[90] = 1;
13728
13729isoBandNextXBL[65] = isoBandNextXBL[105] = 0;
13730isoBandNextYBL[65] = isoBandNextYBL[105] = 1;
13731isoBandNextOBL[65] = isoBandNextOBL[105] = 0;
13732isoBandNextXTL[65] = isoBandNextXTL[105] = 0;
13733isoBandNextYTL[65] = isoBandNextYTL[105] = -1;
13734isoBandNextOTL[65] = isoBandNextOTL[105] = 0;
13735
13736isoBandNextXRT[160] = isoBandNextXRT[10] = -1;
13737isoBandNextYRT[160] = isoBandNextYRT[10] = 0;
13738isoBandNextORT[160] = isoBandNextORT[10] = 1;
13739isoBandNextXRB[160] = isoBandNextXRB[10] = -1;
13740isoBandNextYRB[160] = isoBandNextYRB[10] = 0;
13741isoBandNextORB[160] = isoBandNextORB[10] = 0;
13742isoBandNextXLB[160] = isoBandNextXLB[10] = 1;
13743isoBandNextYLB[160] = isoBandNextYLB[10] = 0;
13744isoBandNextOLB[160] = isoBandNextOLB[10] = 0;
13745isoBandNextXLT[160] = isoBandNextXLT[10] = 1;
13746isoBandNextYLT[160] = isoBandNextYLT[10] = 0;
13747isoBandNextOLT[160] = isoBandNextOLT[10] = 1;
13748
13749isoBandNextXBR[130] = isoBandNextXBR[40] = 0;
13750isoBandNextYBR[130] = isoBandNextYBR[40] = 1;
13751isoBandNextOBR[130] = isoBandNextOBR[40] = 1;
13752isoBandNextXBL[130] = isoBandNextXBL[40] = 0;
13753isoBandNextYBL[130] = isoBandNextYBL[40] = 1;
13754isoBandNextOBL[130] = isoBandNextOBL[40] = 0;
13755isoBandNextXTL[130] = isoBandNextXTL[40] = 0;
13756isoBandNextYTL[130] = isoBandNextYTL[40] = -1;
13757isoBandNextOTL[130] = isoBandNextOTL[40] = 0;
13758isoBandNextXTR[130] = isoBandNextXTR[40] = 0;
13759isoBandNextYTR[130] = isoBandNextYTR[40] = -1;
13760isoBandNextOTR[130] = isoBandNextOTR[40] = 1;
13761
13762/* single hexagon cases */
13763isoBandNextXRB[37] = isoBandNextXRB[133] = 0;
13764isoBandNextYRB[37] = isoBandNextYRB[133] = 1;
13765isoBandNextORB[37] = isoBandNextORB[133] = 1;
13766isoBandNextXLB[37] = isoBandNextXLB[133] = 0;
13767isoBandNextYLB[37] = isoBandNextYLB[133] = 1;
13768isoBandNextOLB[37] = isoBandNextOLB[133] = 0;
13769isoBandNextXTL[37] = isoBandNextXTL[133] = -1;
13770isoBandNextYTL[37] = isoBandNextYTL[133] = 0;
13771isoBandNextOTL[37] = isoBandNextOTL[133] = 0;
13772isoBandNextXTR[37] = isoBandNextXTR[133] = 1;
13773isoBandNextYTR[37] = isoBandNextYTR[133] = 0;
13774isoBandNextOTR[37] = isoBandNextOTR[133] = 0;
13775
13776isoBandNextXBR[148] = isoBandNextXBR[22] = -1;
13777isoBandNextYBR[148] = isoBandNextYBR[22] = 0;
13778isoBandNextOBR[148] = isoBandNextOBR[22] = 0;
13779isoBandNextXLB[148] = isoBandNextXLB[22] = 0;
13780isoBandNextYLB[148] = isoBandNextYLB[22] = -1;
13781isoBandNextOLB[148] = isoBandNextOLB[22] = 1;
13782isoBandNextXLT[148] = isoBandNextXLT[22] = 0;
13783isoBandNextYLT[148] = isoBandNextYLT[22] = 1;
13784isoBandNextOLT[148] = isoBandNextOLT[22] = 1;
13785isoBandNextXTR[148] = isoBandNextXTR[22] = -1;
13786isoBandNextYTR[148] = isoBandNextYTR[22] = 0;
13787isoBandNextOTR[148] = isoBandNextOTR[22] = 1;
13788
13789isoBandNextXRT[82] = isoBandNextXRT[88] = 0;
13790isoBandNextYRT[82] = isoBandNextYRT[88] = -1;
13791isoBandNextORT[82] = isoBandNextORT[88] = 1;
13792isoBandNextXBR[82] = isoBandNextXBR[88] = 1;
13793isoBandNextYBR[82] = isoBandNextYBR[88] = 0;
13794isoBandNextOBR[82] = isoBandNextOBR[88] = 1;
13795isoBandNextXBL[82] = isoBandNextXBL[88] = -1;
13796isoBandNextYBL[82] = isoBandNextYBL[88] = 0;
13797isoBandNextOBL[82] = isoBandNextOBL[88] = 1;
13798isoBandNextXLT[82] = isoBandNextXLT[88] = 0;
13799isoBandNextYLT[82] = isoBandNextYLT[88] = -1;
13800isoBandNextOLT[82] = isoBandNextOLT[88] = 0;
13801
13802isoBandNextXRT[73] = isoBandNextXRT[97] = 0;
13803isoBandNextYRT[73] = isoBandNextYRT[97] = 1;
13804isoBandNextORT[73] = isoBandNextORT[97] = 0;
13805isoBandNextXRB[73] = isoBandNextXRB[97] = 0;
13806isoBandNextYRB[73] = isoBandNextYRB[97] = -1;
13807isoBandNextORB[73] = isoBandNextORB[97] = 0;
13808isoBandNextXBL[73] = isoBandNextXBL[97] = 1;
13809isoBandNextYBL[73] = isoBandNextYBL[97] = 0;
13810isoBandNextOBL[73] = isoBandNextOBL[97] = 0;
13811isoBandNextXTL[73] = isoBandNextXTL[97] = 1;
13812isoBandNextYTL[73] = isoBandNextYTL[97] = 0;
13813isoBandNextOTL[73] = isoBandNextOTL[97] = 1;
13814
13815isoBandNextXRT[145] = isoBandNextXRT[25] = 0;
13816isoBandNextYRT[145] = isoBandNextYRT[25] = -1;
13817isoBandNextORT[145] = isoBandNextORT[25] = 0;
13818isoBandNextXBL[145] = isoBandNextXBL[25] = 1;
13819isoBandNextYBL[145] = isoBandNextYBL[25] = 0;
13820isoBandNextOBL[145] = isoBandNextOBL[25] = 1;
13821isoBandNextXLB[145] = isoBandNextXLB[25] = 0;
13822isoBandNextYLB[145] = isoBandNextYLB[25] = 1;
13823isoBandNextOLB[145] = isoBandNextOLB[25] = 1;
13824isoBandNextXTR[145] = isoBandNextXTR[25] = -1;
13825isoBandNextYTR[145] = isoBandNextYTR[25] = 0;
13826isoBandNextOTR[145] = isoBandNextOTR[25] = 0;
13827
13828isoBandNextXRB[70] = isoBandNextXRB[100] = 0;
13829isoBandNextYRB[70] = isoBandNextYRB[100] = 1;
13830isoBandNextORB[70] = isoBandNextORB[100] = 0;
13831isoBandNextXBR[70] = isoBandNextXBR[100] = -1;
13832isoBandNextYBR[70] = isoBandNextYBR[100] = 0;
13833isoBandNextOBR[70] = isoBandNextOBR[100] = 1;
13834isoBandNextXLT[70] = isoBandNextXLT[100] = 0;
13835isoBandNextYLT[70] = isoBandNextYLT[100] = -1;
13836isoBandNextOLT[70] = isoBandNextOLT[100] = 1;
13837isoBandNextXTL[70] = isoBandNextXTL[100] = 1;
13838isoBandNextYTL[70] = isoBandNextYTL[100] = 0;
13839isoBandNextOTL[70] = isoBandNextOTL[100] = 0;
13840
13841/* single pentagon cases */
13842isoBandNextXRB[101] = isoBandNextXRB[69] = 0;
13843isoBandNextYRB[101] = isoBandNextYRB[69] = 1;
13844isoBandNextORB[101] = isoBandNextORB[69] = 0;
13845isoBandNextXTL[101] = isoBandNextXTL[69] = 1;
13846isoBandNextYTL[101] = isoBandNextYTL[69] = 0;
13847isoBandNextOTL[101] = isoBandNextOTL[69] = 0;
13848
13849isoBandNextXLB[149] = isoBandNextXLB[21] = 0;
13850isoBandNextYLB[149] = isoBandNextYLB[21] = 1;
13851isoBandNextOLB[149] = isoBandNextOLB[21] = 1;
13852isoBandNextXTR[149] = isoBandNextXTR[21] = -1;
13853isoBandNextYTR[149] = isoBandNextYTR[21] = 0;
13854isoBandNextOTR[149] = isoBandNextOTR[21] = 0;
13855
13856isoBandNextXBR[86] = isoBandNextXBR[84] = -1;
13857isoBandNextYBR[86] = isoBandNextYBR[84] = 0;
13858isoBandNextOBR[86] = isoBandNextOBR[84] = 1;
13859isoBandNextXLT[86] = isoBandNextXLT[84] = 0;
13860isoBandNextYLT[86] = isoBandNextYLT[84] = -1;
13861isoBandNextOLT[86] = isoBandNextOLT[84] = 1;
13862
13863isoBandNextXRT[89] = isoBandNextXRT[81] = 0;
13864isoBandNextYRT[89] = isoBandNextYRT[81] = -1;
13865isoBandNextORT[89] = isoBandNextORT[81] = 0;
13866isoBandNextXBL[89] = isoBandNextXBL[81] = 1;
13867isoBandNextYBL[89] = isoBandNextYBL[81] = 0;
13868isoBandNextOBL[89] = isoBandNextOBL[81] = 1;
13869
13870isoBandNextXRT[96] = isoBandNextXRT[74] = 0;
13871isoBandNextYRT[96] = isoBandNextYRT[74] = 1;
13872isoBandNextORT[96] = isoBandNextORT[74] = 0;
13873isoBandNextXRB[96] = isoBandNextXRB[74] = -1;
13874isoBandNextYRB[96] = isoBandNextYRB[74] = 0;
13875isoBandNextORB[96] = isoBandNextORB[74] = 1;
13876isoBandNextXLT[96] = isoBandNextXLT[74] = 1;
13877isoBandNextYLT[96] = isoBandNextYLT[74] = 0;
13878isoBandNextOLT[96] = isoBandNextOLT[74] = 0;
13879isoBandNextXTL[96] = isoBandNextXTL[74] = 1;
13880isoBandNextYTL[96] = isoBandNextYTL[74] = 0;
13881isoBandNextOTL[96] = isoBandNextOTL[74] = 1;
13882
13883isoBandNextXRT[24] = isoBandNextXRT[146] = 0;
13884isoBandNextYRT[24] = isoBandNextYRT[146] = -1;
13885isoBandNextORT[24] = isoBandNextORT[146] = 1;
13886isoBandNextXBR[24] = isoBandNextXBR[146] = 1;
13887isoBandNextYBR[24] = isoBandNextYBR[146] = 0;
13888isoBandNextOBR[24] = isoBandNextOBR[146] = 1;
13889isoBandNextXBL[24] = isoBandNextXBL[146] = 0;
13890isoBandNextYBL[24] = isoBandNextYBL[146] = 1;
13891isoBandNextOBL[24] = isoBandNextOBL[146] = 1;
13892isoBandNextXTR[24] = isoBandNextXTR[146] = 0;
13893isoBandNextYTR[24] = isoBandNextYTR[146] = -1;
13894isoBandNextOTR[24] = isoBandNextOTR[146] = 0;
13895
13896isoBandNextXRB[6] = isoBandNextXRB[164] = -1;
13897isoBandNextYRB[6] = isoBandNextYRB[164] = 0;
13898isoBandNextORB[6] = isoBandNextORB[164] = 1;
13899isoBandNextXBR[6] = isoBandNextXBR[164] = -1;
13900isoBandNextYBR[6] = isoBandNextYBR[164] = 0;
13901isoBandNextOBR[6] = isoBandNextOBR[164] = 0;
13902isoBandNextXLB[6] = isoBandNextXLB[164] = 0;
13903isoBandNextYLB[6] = isoBandNextYLB[164] = -1;
13904isoBandNextOLB[6] = isoBandNextOLB[164] = 1;
13905isoBandNextXLT[6] = isoBandNextXLT[164] = 1;
13906isoBandNextYLT[6] = isoBandNextYLT[164] = 0;
13907isoBandNextOLT[6] = isoBandNextOLT[164] = 0;
13908
13909isoBandNextXBL[129] = isoBandNextXBL[41] = 0;
13910isoBandNextYBL[129] = isoBandNextYBL[41] = 1;
13911isoBandNextOBL[129] = isoBandNextOBL[41] = 1;
13912isoBandNextXLB[129] = isoBandNextXLB[41] = 0;
13913isoBandNextYLB[129] = isoBandNextYLB[41] = 1;
13914isoBandNextOLB[129] = isoBandNextOLB[41] = 0;
13915isoBandNextXTL[129] = isoBandNextXTL[41] = -1;
13916isoBandNextYTL[129] = isoBandNextYTL[41] = 0;
13917isoBandNextOTL[129] = isoBandNextOTL[41] = 0;
13918isoBandNextXTR[129] = isoBandNextXTR[41] = 0;
13919isoBandNextYTR[129] = isoBandNextYTR[41] = -1;
13920isoBandNextOTR[129] = isoBandNextOTR[41] = 0;
13921
13922isoBandNextXBR[66] = isoBandNextXBR[104] = 0;
13923isoBandNextYBR[66] = isoBandNextYBR[104] = 1;
13924isoBandNextOBR[66] = isoBandNextOBR[104] = 0;
13925isoBandNextXBL[66] = isoBandNextXBL[104] = -1;
13926isoBandNextYBL[66] = isoBandNextYBL[104] = 0;
13927isoBandNextOBL[66] = isoBandNextOBL[104] = 1;
13928isoBandNextXLT[66] = isoBandNextXLT[104] = 0;
13929isoBandNextYLT[66] = isoBandNextYLT[104] = -1;
13930isoBandNextOLT[66] = isoBandNextOLT[104] = 0;
13931isoBandNextXTL[66] = isoBandNextXTL[104] = 0;
13932isoBandNextYTL[66] = isoBandNextYTL[104] = -1;
13933isoBandNextOTL[66] = isoBandNextOTL[104] = 1;
13934
13935isoBandNextXRT[144] = isoBandNextXRT[26] = -1;
13936isoBandNextYRT[144] = isoBandNextYRT[26] = 0;
13937isoBandNextORT[144] = isoBandNextORT[26] = 0;
13938isoBandNextXLB[144] = isoBandNextXLB[26] = 1;
13939isoBandNextYLB[144] = isoBandNextYLB[26] = 0;
13940isoBandNextOLB[144] = isoBandNextOLB[26] = 1;
13941isoBandNextXLT[144] = isoBandNextXLT[26] = 0;
13942isoBandNextYLT[144] = isoBandNextYLT[26] = 1;
13943isoBandNextOLT[144] = isoBandNextOLT[26] = 1;
13944isoBandNextXTR[144] = isoBandNextXTR[26] = -1;
13945isoBandNextYTR[144] = isoBandNextYTR[26] = 0;
13946isoBandNextOTR[144] = isoBandNextOTR[26] = 1;
13947
13948isoBandNextXRB[36] = isoBandNextXRB[134] = 0;
13949isoBandNextYRB[36] = isoBandNextYRB[134] = 1;
13950isoBandNextORB[36] = isoBandNextORB[134] = 1;
13951isoBandNextXBR[36] = isoBandNextXBR[134] = 0;
13952isoBandNextYBR[36] = isoBandNextYBR[134] = 1;
13953isoBandNextOBR[36] = isoBandNextOBR[134] = 0;
13954isoBandNextXTL[36] = isoBandNextXTL[134] = 0;
13955isoBandNextYTL[36] = isoBandNextYTL[134] = -1;
13956isoBandNextOTL[36] = isoBandNextOTL[134] = 1;
13957isoBandNextXTR[36] = isoBandNextXTR[134] = 1;
13958isoBandNextYTR[36] = isoBandNextYTR[134] = 0;
13959isoBandNextOTR[36] = isoBandNextOTR[134] = 0;
13960
13961isoBandNextXRT[9] = isoBandNextXRT[161] = -1;
13962isoBandNextYRT[9] = isoBandNextYRT[161] = 0;
13963isoBandNextORT[9] = isoBandNextORT[161] = 0;
13964isoBandNextXRB[9] = isoBandNextXRB[161] = 0;
13965isoBandNextYRB[9] = isoBandNextYRB[161] = -1;
13966isoBandNextORB[9] = isoBandNextORB[161] = 0;
13967isoBandNextXBL[9] = isoBandNextXBL[161] = 1;
13968isoBandNextYBL[9] = isoBandNextYBL[161] = 0;
13969isoBandNextOBL[9] = isoBandNextOBL[161] = 0;
13970isoBandNextXLB[9] = isoBandNextXLB[161] = 1;
13971isoBandNextYLB[9] = isoBandNextYLB[161] = 0;
13972isoBandNextOLB[9] = isoBandNextOLB[161] = 1;
13973
13974/* 8-sided cases */
13975isoBandNextXRT[136] = 0;
13976isoBandNextYRT[136] = 1;
13977isoBandNextORT[136] = 1;
13978isoBandNextXRB[136] = 0;
13979isoBandNextYRB[136] = 1;
13980isoBandNextORB[136] = 0;
13981isoBandNextXBR[136] = -1;
13982isoBandNextYBR[136] = 0;
13983isoBandNextOBR[136] = 1;
13984isoBandNextXBL[136] = -1;
13985isoBandNextYBL[136] = 0;
13986isoBandNextOBL[136] = 0;
13987isoBandNextXLB[136] = 0;
13988isoBandNextYLB[136] = -1;
13989isoBandNextOLB[136] = 0;
13990isoBandNextXLT[136] = 0;
13991isoBandNextYLT[136] = -1;
13992isoBandNextOLT[136] = 1;
13993isoBandNextXTL[136] = 1;
13994isoBandNextYTL[136] = 0;
13995isoBandNextOTL[136] = 0;
13996isoBandNextXTR[136] = 1;
13997isoBandNextYTR[136] = 0;
13998isoBandNextOTR[136] = 1;
13999
14000isoBandNextXRT[34] = 0;
14001isoBandNextYRT[34] = -1;
14002isoBandNextORT[34] = 0;
14003isoBandNextXRB[34] = 0;
14004isoBandNextYRB[34] = -1;
14005isoBandNextORB[34] = 1;
14006isoBandNextXBR[34] = 1;
14007isoBandNextYBR[34] = 0;
14008isoBandNextOBR[34] = 0;
14009isoBandNextXBL[34] = 1;
14010isoBandNextYBL[34] = 0;
14011isoBandNextOBL[34] = 1;
14012isoBandNextXLB[34] = 0;
14013isoBandNextYLB[34] = 1;
14014isoBandNextOLB[34] = 1;
14015isoBandNextXLT[34] = 0;
14016isoBandNextYLT[34] = 1;
14017isoBandNextOLT[34] = 0;
14018isoBandNextXTL[34] = -1;
14019isoBandNextYTL[34] = 0;
14020isoBandNextOTL[34] = 1;
14021isoBandNextXTR[34] = -1;
14022isoBandNextYTR[34] = 0;
14023isoBandNextOTR[34] = 0;
14024
14025isoBandNextXRT[35] = 0;
14026isoBandNextYRT[35] = 1;
14027isoBandNextORT[35] = 1;
14028isoBandNextXRB[35] = 0;
14029isoBandNextYRB[35] = -1;
14030isoBandNextORB[35] = 1;
14031isoBandNextXBR[35] = 1;
14032isoBandNextYBR[35] = 0;
14033isoBandNextOBR[35] = 0;
14034isoBandNextXBL[35] = -1;
14035isoBandNextYBL[35] = 0;
14036isoBandNextOBL[35] = 0;
14037isoBandNextXLB[35] = 0;
14038isoBandNextYLB[35] = -1;
14039isoBandNextOLB[35] = 0;
14040isoBandNextXLT[35] = 0;
14041isoBandNextYLT[35] = 1;
14042isoBandNextOLT[35] = 0;
14043isoBandNextXTL[35] = -1;
14044isoBandNextYTL[35] = 0;
14045isoBandNextOTL[35] = 1;
14046isoBandNextXTR[35] = 1;
14047isoBandNextYTR[35] = 0;
14048isoBandNextOTR[35] = 1;
14049
14050/* 6-sided cases */
14051isoBandNextXRT[153] = 0;
14052isoBandNextYRT[153] = 1;
14053isoBandNextORT[153] = 1;
14054isoBandNextXBL[153] = -1;
14055isoBandNextYBL[153] = 0;
14056isoBandNextOBL[153] = 0;
14057isoBandNextXLB[153] = 0;
14058isoBandNextYLB[153] = -1;
14059isoBandNextOLB[153] = 0;
14060isoBandNextXTR[153] = 1;
14061isoBandNextYTR[153] = 0;
14062isoBandNextOTR[153] = 1;
14063
14064isoBandNextXRB[102] = 0;
14065isoBandNextYRB[102] = -1;
14066isoBandNextORB[102] = 1;
14067isoBandNextXBR[102] = 1;
14068isoBandNextYBR[102] = 0;
14069isoBandNextOBR[102] = 0;
14070isoBandNextXLT[102] = 0;
14071isoBandNextYLT[102] = 1;
14072isoBandNextOLT[102] = 0;
14073isoBandNextXTL[102] = -1;
14074isoBandNextYTL[102] = 0;
14075isoBandNextOTL[102] = 1;
14076
14077isoBandNextXRT[155] = 0;
14078isoBandNextYRT[155] = -1;
14079isoBandNextORT[155] = 0;
14080isoBandNextXBL[155] = 1;
14081isoBandNextYBL[155] = 0;
14082isoBandNextOBL[155] = 1;
14083isoBandNextXLB[155] = 0;
14084isoBandNextYLB[155] = 1;
14085isoBandNextOLB[155] = 1;
14086isoBandNextXTR[155] = -1;
14087isoBandNextYTR[155] = 0;
14088isoBandNextOTR[155] = 0;
14089
14090isoBandNextXRB[103] = 0;
14091isoBandNextYRB[103] = 1;
14092isoBandNextORB[103] = 0;
14093isoBandNextXBR[103] = -1;
14094isoBandNextYBR[103] = 0;
14095isoBandNextOBR[103] = 1;
14096isoBandNextXLT[103] = 0;
14097isoBandNextYLT[103] = -1;
14098isoBandNextOLT[103] = 1;
14099isoBandNextXTL[103] = 1;
14100isoBandNextYTL[103] = 0;
14101isoBandNextOTL[103] = 0;
14102
14103/* 7-sided cases */
14104isoBandNextXRT[152] = 0;
14105isoBandNextYRT[152] = 1;
14106isoBandNextORT[152] = 1;
14107isoBandNextXBR[152] = -1;
14108isoBandNextYBR[152] = 0;
14109isoBandNextOBR[152] = 1;
14110isoBandNextXBL[152] = -1;
14111isoBandNextYBL[152] = 0;
14112isoBandNextOBL[152] = 0;
14113isoBandNextXLB[152] = 0;
14114isoBandNextYLB[152] = -1;
14115isoBandNextOLB[152] = 0;
14116isoBandNextXLT[152] = 0;
14117isoBandNextYLT[152] = -1;
14118isoBandNextOLT[152] = 1;
14119isoBandNextXTR[152] = 1;
14120isoBandNextYTR[152] = 0;
14121isoBandNextOTR[152] = 1;
14122
14123isoBandNextXRT[156] = 0;
14124isoBandNextYRT[156] = -1;
14125isoBandNextORT[156] = 1;
14126isoBandNextXBR[156] = 1;
14127isoBandNextYBR[156] = 0;
14128isoBandNextOBR[156] = 1;
14129isoBandNextXBL[156] = -1;
14130isoBandNextYBL[156] = 0;
14131isoBandNextOBL[156] = 0;
14132isoBandNextXLB[156] = 0;
14133isoBandNextYLB[156] = -1;
14134isoBandNextOLB[156] = 0;
14135isoBandNextXLT[156] = 0;
14136isoBandNextYLT[156] = 1;
14137isoBandNextOLT[156] = 1;
14138isoBandNextXTR[156] = -1;
14139isoBandNextYTR[156] = 0;
14140isoBandNextOTR[156] = 1;
14141
14142isoBandNextXRT[137] = 0;
14143isoBandNextYRT[137] = 1;
14144isoBandNextORT[137] = 1;
14145isoBandNextXRB[137] = 0;
14146isoBandNextYRB[137] = 1;
14147isoBandNextORB[137] = 0;
14148isoBandNextXBL[137] = -1;
14149isoBandNextYBL[137] = 0;
14150isoBandNextOBL[137] = 0;
14151isoBandNextXLB[137] = 0;
14152isoBandNextYLB[137] = -1;
14153isoBandNextOLB[137] = 0;
14154isoBandNextXTL[137] = 1;
14155isoBandNextYTL[137] = 0;
14156isoBandNextOTL[137] = 0;
14157isoBandNextXTR[137] = 1;
14158isoBandNextYTR[137] = 0;
14159isoBandNextOTR[137] = 1;
14160
14161isoBandNextXRT[139] = 0;
14162isoBandNextYRT[139] = 1;
14163isoBandNextORT[139] = 1;
14164isoBandNextXRB[139] = 0;
14165isoBandNextYRB[139] = -1;
14166isoBandNextORB[139] = 0;
14167isoBandNextXBL[139] = 1;
14168isoBandNextYBL[139] = 0;
14169isoBandNextOBL[139] = 0;
14170isoBandNextXLB[139] = 0;
14171isoBandNextYLB[139] = 1;
14172isoBandNextOLB[139] = 0;
14173isoBandNextXTL[139] = -1;
14174isoBandNextYTL[139] = 0;
14175isoBandNextOTL[139] = 0;
14176isoBandNextXTR[139] = 1;
14177isoBandNextYTR[139] = 0;
14178isoBandNextOTR[139] = 1;
14179
14180isoBandNextXRT[98] = 0;
14181isoBandNextYRT[98] = -1;
14182isoBandNextORT[98] = 0;
14183isoBandNextXRB[98] = 0;
14184isoBandNextYRB[98] = -1;
14185isoBandNextORB[98] = 1;
14186isoBandNextXBR[98] = 1;
14187isoBandNextYBR[98] = 0;
14188isoBandNextOBR[98] = 0;
14189isoBandNextXBL[98] = 1;
14190isoBandNextYBL[98] = 0;
14191isoBandNextOBL[98] = 1;
14192isoBandNextXLT[98] = 0;
14193isoBandNextYLT[98] = 1;
14194isoBandNextOLT[98] = 0;
14195isoBandNextXTL[98] = -1;
14196isoBandNextYTL[98] = 0;
14197isoBandNextOTL[98] = 1;
14198
14199isoBandNextXRT[99] = 0;
14200isoBandNextYRT[99] = 1;
14201isoBandNextORT[99] = 0;
14202isoBandNextXRB[99] = 0;
14203isoBandNextYRB[99] = -1;
14204isoBandNextORB[99] = 1;
14205isoBandNextXBR[99] = 1;
14206isoBandNextYBR[99] = 0;
14207isoBandNextOBR[99] = 0;
14208isoBandNextXBL[99] = -1;
14209isoBandNextYBL[99] = 0;
14210isoBandNextOBL[99] = 1;
14211isoBandNextXLT[99] = 0;
14212isoBandNextYLT[99] = -1;
14213isoBandNextOLT[99] = 0;
14214isoBandNextXTL[99] = 1;
14215isoBandNextYTL[99] = 0;
14216isoBandNextOTL[99] = 1;
14217
14218isoBandNextXRB[38] = 0;
14219isoBandNextYRB[38] = -1;
14220isoBandNextORB[38] = 1;
14221isoBandNextXBR[38] = 1;
14222isoBandNextYBR[38] = 0;
14223isoBandNextOBR[38] = 0;
14224isoBandNextXLB[38] = 0;
14225isoBandNextYLB[38] = 1;
14226isoBandNextOLB[38] = 1;
14227isoBandNextXLT[38] = 0;
14228isoBandNextYLT[38] = 1;
14229isoBandNextOLT[38] = 0;
14230isoBandNextXTL[38] = -1;
14231isoBandNextYTL[38] = 0;
14232isoBandNextOTL[38] = 1;
14233isoBandNextXTR[38] = -1;
14234isoBandNextYTR[38] = 0;
14235isoBandNextOTR[38] = 0;
14236
14237isoBandNextXRB[39] = 0;
14238isoBandNextYRB[39] = 1;
14239isoBandNextORB[39] = 1;
14240isoBandNextXBR[39] = -1;
14241isoBandNextYBR[39] = 0;
14242isoBandNextOBR[39] = 0;
14243isoBandNextXLB[39] = 0;
14244isoBandNextYLB[39] = -1;
14245isoBandNextOLB[39] = 1;
14246isoBandNextXLT[39] = 0;
14247isoBandNextYLT[39] = 1;
14248isoBandNextOLT[39] = 0;
14249isoBandNextXTL[39] = -1;
14250isoBandNextYTL[39] = 0;
14251isoBandNextOTL[39] = 1;
14252isoBandNextXTR[39] = 1;
14253isoBandNextYTR[39] = 0;
14254isoBandNextOTR[39] = 0;
14255
14256
14257/*
14258 Define helper functions for the polygon_table
14259 */
14260
14261/* triangle cases */
14262var p00 = function (cell) {
14263 return [[cell.bottomleft, 0], [0, 0], [0, cell.leftbottom]];
14264};
14265var p01 = function (cell) {
14266 return [[1, cell.rightbottom], [1, 0], [cell.bottomright, 0]];
14267};
14268var p02 = function (cell) {
14269 return [[cell.topright, 1], [1, 1], [1, cell.righttop]];
14270};
14271var p03 = function (cell) {
14272 return [[0, cell.lefttop], [0, 1], [cell.topleft, 1]];
14273};
14274/* trapezoid cases */
14275var p04 = function (cell) {
14276 return [[cell.bottomright, 0], [cell.bottomleft, 0], [0, cell.leftbottom], [0, cell.lefttop]];
14277};
14278var p05 = function (cell) {
14279 return [[cell.bottomright, 0], [cell.bottomleft, 0], [1, cell.righttop], [1, cell.rightbottom]];
14280};
14281var p06 = function (cell) {
14282 return [[1, cell.righttop], [1, cell.rightbottom], [cell.topleft, 1], [cell.topright, 1]];
14283};
14284var p07 = function (cell) {
14285 return [[0, cell.leftbottom], [0, cell.lefttop], [cell.topleft, 1], [cell.topright, 1]];
14286};
14287/* rectangle cases */
14288var p08 = function (cell) {
14289 return [[0, 0], [0, cell.leftbottom], [1, cell.rightbottom], [1, 0]];
14290};
14291var p09 = function (cell) {
14292 return [[1, 0], [cell.bottomright, 0], [cell.topright, 1], [1, 1]];
14293};
14294var p10 = function (cell) {
14295 return [[1, 1], [1, cell.righttop], [0, cell.lefttop], [0, 1]];
14296};
14297var p11 = function (cell) {
14298 return [[cell.bottomleft, 0], [0, 0], [0, 1], [cell.topleft, 1]];
14299};
14300var p12 = function (cell) {
14301 return [[1, cell.righttop], [1, cell.rightbottom], [0, cell.leftbottom], [0, cell.lefttop]];
14302};
14303var p13 = function (cell) {
14304 return [[cell.topleft, 1], [cell.topright, 1], [cell.bottomright, 0], [cell.bottomleft, 0]];
14305};
14306/* square case */
14307var p14 = function () {
14308 return [[0, 0], [0, 1], [1, 1], [1, 0]];
14309};
14310/* pentagon cases */
14311var p15 = function (cell) {
14312 return [[1, cell.rightbottom], [1, 0], [0, 0], [0, 1], [cell.topleft, 1]];
14313};
14314/* 1211 || 1011 */
14315var p16 = function (cell) {
14316 return [[cell.topright, 1], [1, 1], [1, 0], [0, 0], [0, cell.leftbottom]];
14317};
14318/* 2111 || 0111 */
14319var p17 = function (cell) {
14320 return [[1, 0], [cell.bottomright, 0], [0, cell.lefttop], [0, 1], [1, 1]];
14321};
14322/* 1112 || 1110 */
14323var p18 = function (cell) {
14324 return [[1, 1], [1, cell.righttop], [cell.bottomleft, 0], [0, 0], [0, 1]];
14325};
14326/* 1121 || 1101 */
14327var p19 = function (cell) {
14328 return [[1, cell.righttop], [1, cell.rightbottom], [0, cell.lefttop], [0, 1], [cell.topleft, 1]];
14329};
14330/* 1200 || 1022 */
14331var p20 = function (cell) {
14332 return [[1, 1], [1, cell.righttop], [cell.bottomright, 0], [cell.bottomleft, 0], [cell.topright, 1]];
14333};
14334/* 0120 || 2102 */
14335var p21 = function (cell) {
14336 return [[1, cell.rightbottom], [1, 0], [cell.bottomright, 0], [0, cell.leftbottom], [0, cell.lefttop]];
14337};
14338/* 0012 || 2210 */
14339var p22 = function (cell) {
14340 return [[cell.topright, 1], [cell.bottomleft, 0], [0, 0], [0, cell.leftbottom], [cell.topleft, 1]];
14341};
14342/* 2001 || 0221 */
14343var p23 = function (cell) {
14344 return [[cell.bottomright, 0], [cell.bottomleft, 0], [0, cell.lefttop], [0, 1], [cell.topleft, 1]];
14345};
14346/* 1002 || 1220 */
14347var p24 = function (cell) {
14348 return [[1, 1], [1, cell.righttop], [0, cell.leftbottom], [0, cell.lefttop], [cell.topright, 1]];
14349};
14350/* 2100 || 0122 */
14351var p25 = function (cell) {
14352 return [[1, cell.rightbottom], [1, 0], [cell.bottomright, 0], [cell.topleft, 1], [cell.topright, 1]];
14353};
14354/* 0210 || 2012 */
14355var p26 = function (cell) {
14356 return [[1, cell.righttop], [1, cell.rightbottom], [cell.bottomleft, 0], [0, 0], [0, cell.leftbottom]];
14357};
14358/* 0021 || 2201 */
14359/*hexagon cases */
14360var p27 = function (cell) {
14361 return [[1, cell.rightbottom], [1, 0], [0, 0], [0, cell.leftbottom], [cell.topleft, 1], [cell.topright, 1]];
14362};
14363/* 0211 || 2011 */
14364var p28 = function (cell) {
14365 return [[1, 1], [1, 0], [cell.bottomright, 0], [0, cell.leftbottom], [0, cell.lefttop], [cell.topright, 1]];
14366};
14367/* 2110 || 0112 */
14368var p29 = function (cell) {
14369 return [[1, 1], [1, cell.righttop], [cell.bottomright, 0], [cell.bottomleft, 0], [0, cell.lefttop], [0, 1]];
14370};
14371/* 1102 || 1120 */
14372var p30 = function (cell) {
14373 return [[1, cell.righttop], [1, cell.rightbottom], [cell.bottomleft, 0], [0, 0], [0, 1], [cell.topleft, 1]];
14374};
14375/* 1021 || 1201 */
14376var p31 = function (cell) {
14377 return [[1, 1], [1, cell.righttop], [cell.bottomleft, 0], [0, 0], [0, cell.leftbottom], [cell.topright, 1]];
14378};
14379/* 2101 || 0121 */
14380var p32 = function (cell) {
14381 return [[1, cell.rightbottom], [1, 0], [cell.bottomright, 0], [0, cell.lefttop], [0, 1], [cell.topleft, 1]];
14382};
14383/* 1012 || 1210 */
14384/* 8-sided cases */
14385var p33 = function (cell) {
14386 return [[1, cell.righttop], [1, cell.rightbottom], [cell.bottomright, 0], [cell.bottomleft, 0], [0, cell.leftbottom], [0, cell.lefttop], [cell.topleft, 1], [cell.topright, 1]];
14387};
14388/* flipped == 1 state for 0202 and 2020 */
14389/* 6-sided cases */
14390var p34 = function (cell) {
14391 return [[1, 1], [1, cell.righttop], [cell.bottomleft, 0], [0, 0], [0, cell.leftbottom], [cell.topright, 1]];
14392};
14393/* 0101 with flipped == 1 || 2121 with flipped == 1 */
14394var p35 = function (cell) {
14395 return [[1, cell.rightbottom], [1, 0], [cell.bottomright, 0], [0, cell.lefttop], [0, 1], [cell.topleft, 1]];
14396};
14397/* 1010 with flipped == 1 || 1212 with flipped == 1 */
14398/* 7-sided cases */
14399var p36 = function (cell) {
14400 return [[1, 1], [1, cell.righttop], [cell.bottomright, 0], [cell.bottomleft, 0], [0, cell.leftbottom], [0, cell.lefttop], [cell.topright, 1]];
14401};
14402/* 2120 with flipped == 1 || 0102 with flipped == 1 */
14403var p37 = function (cell) {
14404 return [[1, cell.righttop], [1, cell.rightbottom], [cell.bottomleft, 0], [0, 0], [0, cell.leftbottom], [cell.topleft, 1], [cell.topright, 1]];
14405};
14406/* 2021 with flipped == 1 || 0201 with flipped == 1 */
14407var p38 = function (cell) {
14408 return [[1, cell.righttop], [1, cell.rightbottom], [cell.bottomright, 0], [cell.bottomleft, 0], [0, cell.lefttop], [0, 1], [cell.topleft, 1]];
14409};
14410/* 1202 with flipped == 1 || 1020 with flipped == 1 */
14411var p39 = function (cell) {
14412 return [[1, cell.rightbottom], [1, 0], [cell.bottomright, 0], [0, cell.leftbottom], [0, cell.lefttop], [cell.topleft, 1], [cell.topright, 1]];
14413};
14414/* 0212 with flipped == 1 || 2010 with flipped == 1 */
14415
14416
14417
14418/*
14419 The lookup tables for edge number given the polygon
14420 is entered at a specific location
14421*/
14422
14423var isoBandEdgeRT = [];
14424var isoBandEdgeRB = [];
14425var isoBandEdgeBR = [];
14426var isoBandEdgeBL = [];
14427var isoBandEdgeLB = [];
14428var isoBandEdgeLT = [];
14429var isoBandEdgeTL = [];
14430var isoBandEdgeTR = [];
14431
14432/* triangle cases */
14433isoBandEdgeBL[1] = isoBandEdgeLB[1] = 18;
14434isoBandEdgeBL[169] = isoBandEdgeLB[169] = 18;
14435isoBandEdgeBR[4] = isoBandEdgeRB[4] = 12;
14436isoBandEdgeBR[166] = isoBandEdgeRB[166] = 12;
14437isoBandEdgeRT[16] = isoBandEdgeTR[16] = 4;
14438isoBandEdgeRT[154] = isoBandEdgeTR[154] = 4;
14439isoBandEdgeLT[64] = isoBandEdgeTL[64] = 22;
14440isoBandEdgeLT[106] = isoBandEdgeTL[106] = 22;
14441
14442/* trapezoid cases */
14443isoBandEdgeBR[2] = isoBandEdgeLT[2] = 17;
14444isoBandEdgeBL[2] = isoBandEdgeLB[2] = 18;
14445isoBandEdgeBR[168] = isoBandEdgeLT[168] = 17;
14446isoBandEdgeBL[168] = isoBandEdgeLB[168] = 18;
14447isoBandEdgeRT[8] = isoBandEdgeBL[8] = 9;
14448isoBandEdgeRB[8] = isoBandEdgeBR[8] = 12;
14449isoBandEdgeRT[162] = isoBandEdgeBL[162] = 9;
14450isoBandEdgeRB[162] = isoBandEdgeBR[162] = 12;
14451isoBandEdgeRT[32] = isoBandEdgeTR[32] = 4;
14452isoBandEdgeRB[32] = isoBandEdgeTL[32] = 1;
14453isoBandEdgeRT[138] = isoBandEdgeTR[138] = 4;
14454isoBandEdgeRB[138] = isoBandEdgeTL[138] = 1;
14455isoBandEdgeLB[128] = isoBandEdgeTR[128] = 21;
14456isoBandEdgeLT[128] = isoBandEdgeTL[128] = 22;
14457isoBandEdgeLB[42] = isoBandEdgeTR[42] = 21;
14458isoBandEdgeLT[42] = isoBandEdgeTL[42] = 22;
14459
14460/* rectangle cases */
14461isoBandEdgeRB[5] = isoBandEdgeLB[5] = 14;
14462isoBandEdgeRB[165] = isoBandEdgeLB[165] = 14;
14463isoBandEdgeBR[20] = isoBandEdgeTR[20] = 6;
14464isoBandEdgeBR[150] = isoBandEdgeTR[150] = 6;
14465isoBandEdgeRT[80] = isoBandEdgeLT[80] = 11;
14466isoBandEdgeRT[90] = isoBandEdgeLT[90] = 11;
14467isoBandEdgeBL[65] = isoBandEdgeTL[65] = 3;
14468isoBandEdgeBL[105] = isoBandEdgeTL[105] = 3;
14469isoBandEdgeRT[160] = isoBandEdgeLT[160] = 11;
14470isoBandEdgeRB[160] = isoBandEdgeLB[160] = 14;
14471isoBandEdgeRT[10] = isoBandEdgeLT[10] = 11;
14472isoBandEdgeRB[10] = isoBandEdgeLB[10] = 14;
14473isoBandEdgeBR[130] = isoBandEdgeTR[130] = 6;
14474isoBandEdgeBL[130] = isoBandEdgeTL[130] = 3;
14475isoBandEdgeBR[40] = isoBandEdgeTR[40] = 6;
14476isoBandEdgeBL[40] = isoBandEdgeTL[40] = 3;
14477
14478/* pentagon cases */
14479isoBandEdgeRB[101] = isoBandEdgeTL[101] = 1;
14480isoBandEdgeRB[69] = isoBandEdgeTL[69] = 1;
14481isoBandEdgeLB[149] = isoBandEdgeTR[149] = 21;
14482isoBandEdgeLB[21] = isoBandEdgeTR[21] = 21;
14483isoBandEdgeBR[86] = isoBandEdgeLT[86] = 17;
14484isoBandEdgeBR[84] = isoBandEdgeLT[84] = 17;
14485isoBandEdgeRT[89] = isoBandEdgeBL[89] = 9;
14486isoBandEdgeRT[81] = isoBandEdgeBL[81] = 9;
14487isoBandEdgeRT[96] = isoBandEdgeTL[96] = 0;
14488isoBandEdgeRB[96] = isoBandEdgeLT[96] = 15;
14489isoBandEdgeRT[74] = isoBandEdgeTL[74] = 0;
14490isoBandEdgeRB[74] = isoBandEdgeLT[74] = 15;
14491isoBandEdgeRT[24] = isoBandEdgeBR[24] = 8;
14492isoBandEdgeBL[24] = isoBandEdgeTR[24] = 7;
14493isoBandEdgeRT[146] = isoBandEdgeBR[146] = 8;
14494isoBandEdgeBL[146] = isoBandEdgeTR[146] = 7;
14495isoBandEdgeRB[6] = isoBandEdgeLT[6] = 15;
14496isoBandEdgeBR[6] = isoBandEdgeLB[6] = 16;
14497isoBandEdgeRB[164] = isoBandEdgeLT[164] = 15;
14498isoBandEdgeBR[164] = isoBandEdgeLB[164] = 16;
14499isoBandEdgeBL[129] = isoBandEdgeTR[129] = 7;
14500isoBandEdgeLB[129] = isoBandEdgeTL[129] = 20;
14501isoBandEdgeBL[41] = isoBandEdgeTR[41] = 7;
14502isoBandEdgeLB[41] = isoBandEdgeTL[41] = 20;
14503isoBandEdgeBR[66] = isoBandEdgeTL[66] = 2;
14504isoBandEdgeBL[66] = isoBandEdgeLT[66] = 19;
14505isoBandEdgeBR[104] = isoBandEdgeTL[104] = 2;
14506isoBandEdgeBL[104] = isoBandEdgeLT[104] = 19;
14507isoBandEdgeRT[144] = isoBandEdgeLB[144] = 10;
14508isoBandEdgeLT[144] = isoBandEdgeTR[144] = 23;
14509isoBandEdgeRT[26] = isoBandEdgeLB[26] = 10;
14510isoBandEdgeLT[26] = isoBandEdgeTR[26] = 23;
14511isoBandEdgeRB[36] = isoBandEdgeTR[36] = 5;
14512isoBandEdgeBR[36] = isoBandEdgeTL[36] = 2;
14513isoBandEdgeRB[134] = isoBandEdgeTR[134] = 5;
14514isoBandEdgeBR[134] = isoBandEdgeTL[134] = 2;
14515isoBandEdgeRT[9] = isoBandEdgeLB[9] = 10;
14516isoBandEdgeRB[9] = isoBandEdgeBL[9] = 13;
14517isoBandEdgeRT[161] = isoBandEdgeLB[161] = 10;
14518isoBandEdgeRB[161] = isoBandEdgeBL[161] = 13;
14519
14520/* hexagon cases */
14521isoBandEdgeRB[37] = isoBandEdgeTR[37] = 5;
14522isoBandEdgeLB[37] = isoBandEdgeTL[37] = 20;
14523isoBandEdgeRB[133] = isoBandEdgeTR[133] = 5;
14524isoBandEdgeLB[133] = isoBandEdgeTL[133] = 20;
14525isoBandEdgeBR[148] = isoBandEdgeLB[148] = 16;
14526isoBandEdgeLT[148] = isoBandEdgeTR[148] = 23;
14527isoBandEdgeBR[22] = isoBandEdgeLB[22] = 16;
14528isoBandEdgeLT[22] = isoBandEdgeTR[22] = 23;
14529isoBandEdgeRT[82] = isoBandEdgeBR[82] = 8;
14530isoBandEdgeBL[82] = isoBandEdgeLT[82] = 19;
14531isoBandEdgeRT[88] = isoBandEdgeBR[88] = 8;
14532isoBandEdgeBL[88] = isoBandEdgeLT[88] = 19;
14533isoBandEdgeRT[73] = isoBandEdgeTL[73] = 0;
14534isoBandEdgeRB[73] = isoBandEdgeBL[73] = 13;
14535isoBandEdgeRT[97] = isoBandEdgeTL[97] = 0;
14536isoBandEdgeRB[97] = isoBandEdgeBL[97] = 13;
14537isoBandEdgeRT[145] = isoBandEdgeBL[145] = 9;
14538isoBandEdgeLB[145] = isoBandEdgeTR[145] = 21;
14539isoBandEdgeRT[25] = isoBandEdgeBL[25] = 9;
14540isoBandEdgeLB[25] = isoBandEdgeTR[25] = 21;
14541isoBandEdgeRB[70] = isoBandEdgeTL[70] = 1;
14542isoBandEdgeBR[70] = isoBandEdgeLT[70] = 17;
14543isoBandEdgeRB[100] = isoBandEdgeTL[100] = 1;
14544isoBandEdgeBR[100] = isoBandEdgeLT[100] = 17;
14545
14546/* 8-sided cases */
14547isoBandEdgeRT[34] = isoBandEdgeBL[34] = 9;
14548isoBandEdgeRB[34] = isoBandEdgeBR[34] = 12;
14549isoBandEdgeLB[34] = isoBandEdgeTR[34] = 21;
14550isoBandEdgeLT[34] = isoBandEdgeTL[34] = 22;
14551isoBandEdgeRT[136] = isoBandEdgeTR[136] = 4;
14552isoBandEdgeRB[136] = isoBandEdgeTL[136] = 1;
14553isoBandEdgeBR[136] = isoBandEdgeLT[136] = 17;
14554isoBandEdgeBL[136] = isoBandEdgeLB[136] = 18;
14555isoBandEdgeRT[35] = isoBandEdgeTR[35] = 4;
14556isoBandEdgeRB[35] = isoBandEdgeBR[35] = 12;
14557isoBandEdgeBL[35] = isoBandEdgeLB[35] = 18;
14558isoBandEdgeLT[35] = isoBandEdgeTL[35] = 22;
14559
14560/* 6-sided cases */
14561isoBandEdgeRT[153] = isoBandEdgeTR[153] = 4;
14562isoBandEdgeBL[153] = isoBandEdgeLB[153] = 18;
14563isoBandEdgeRB[102] = isoBandEdgeBR[102] = 12;
14564isoBandEdgeLT[102] = isoBandEdgeTL[102] = 22;
14565isoBandEdgeRT[155] = isoBandEdgeBL[155] = 9;
14566isoBandEdgeLB[155] = isoBandEdgeTR[155] = 23;
14567isoBandEdgeRB[103] = isoBandEdgeTL[103] = 1;
14568isoBandEdgeBR[103] = isoBandEdgeLT[103] = 17;
14569
14570/* 7-sided cases */
14571isoBandEdgeRT[152] = isoBandEdgeTR[152] = 4;
14572isoBandEdgeBR[152] = isoBandEdgeLT[152] = 17;
14573isoBandEdgeBL[152] = isoBandEdgeLB[152] = 18;
14574isoBandEdgeRT[156] = isoBandEdgeBR[156] = 8;
14575isoBandEdgeBL[156] = isoBandEdgeLB[156] = 18;
14576isoBandEdgeLT[156] = isoBandEdgeTR[156] = 23;
14577isoBandEdgeRT[137] = isoBandEdgeTR[137] = 4;
14578isoBandEdgeRB[137] = isoBandEdgeTL[137] = 1;
14579isoBandEdgeBL[137] = isoBandEdgeLB[137] = 18;
14580isoBandEdgeRT[139] = isoBandEdgeTR[139] = 4;
14581isoBandEdgeRB[139] = isoBandEdgeBL[139] = 13;
14582isoBandEdgeLB[139] = isoBandEdgeTL[139] = 20;
14583isoBandEdgeRT[98] = isoBandEdgeBL[98] = 9;
14584isoBandEdgeRB[98] = isoBandEdgeBR[98] = 12;
14585isoBandEdgeLT[98] = isoBandEdgeTL[98] = 22;
14586isoBandEdgeRT[99] = isoBandEdgeTL[99] = 0;
14587isoBandEdgeRB[99] = isoBandEdgeBR[99] = 12;
14588isoBandEdgeBL[99] = isoBandEdgeLT[99] = 19;
14589isoBandEdgeRB[38] = isoBandEdgeBR[38] = 12;
14590isoBandEdgeLB[38] = isoBandEdgeTR[38] = 21;
14591isoBandEdgeLT[38] = isoBandEdgeTL[38] = 22;
14592isoBandEdgeRB[39] = isoBandEdgeTR[39] = 5;
14593isoBandEdgeBR[39] = isoBandEdgeLB[39] = 16;
14594isoBandEdgeLT[39] = isoBandEdgeTL[39] = 22;
14595
14596/*
14597 The lookup tables for all different polygons that
14598 may appear within a grid cell
14599*/
14600
14601var polygon_table = [];
14602
14603/* triangle cases */
14604polygon_table[1] = polygon_table[169] = p00; /* 2221 || 0001 */
14605polygon_table[4] = polygon_table[166] = p01; /* 2212 || 0010 */
14606polygon_table[16] = polygon_table[154] = p02; /* 2122 || 0100 */
14607polygon_table[64] = polygon_table[106] = p03; /* 1222 || 1000 */
14608
14609/* trapezoid cases */
14610polygon_table[168] = polygon_table[2] = p04; /* 2220 || 0002 */
14611polygon_table[162] = polygon_table[8] = p05; /* 2202 || 0020 */
14612polygon_table[138] = polygon_table[32] = p06; /* 2022 || 0200 */
14613polygon_table[42] = polygon_table[128] = p07; /* 0222 || 2000 */
14614
14615/* rectangle cases */
14616polygon_table[5] = polygon_table[165] = p08; /* 0011 || 2211 */
14617polygon_table[20] = polygon_table[150] = p09; /* 0110 || 2112 */
14618polygon_table[80] = polygon_table[90] = p10; /* 1100 || 1122 */
14619polygon_table[65] = polygon_table[105] = p11; /* 1001 || 1221 */
14620polygon_table[160] = polygon_table[10] = p12; /* 2200 || 0022 */
14621polygon_table[130] = polygon_table[40] = p13; /* 2002 || 0220 */
14622
14623/* square case */
14624polygon_table[85] = p14; /* 1111 */
14625
14626/* pentagon cases */
14627polygon_table[101] = polygon_table[69] = p15; /* 1211 || 1011 */
14628polygon_table[149] = polygon_table[21] = p16; /* 2111 || 0111 */
14629polygon_table[86] = polygon_table[84] = p17; /* 1112 || 1110 */
14630polygon_table[89] = polygon_table[81] = p18; /* 1121 || 1101 */
14631polygon_table[96] = polygon_table[74] = p19; /* 1200 || 1022 */
14632polygon_table[24] = polygon_table[146] = p20; /* 0120 || 2102 */
14633polygon_table[6] = polygon_table[164] = p21; /* 0012 || 2210 */
14634polygon_table[129] = polygon_table[41] = p22; /* 2001 || 0221 */
14635polygon_table[66] = polygon_table[104] = p23; /* 1002 || 1220 */
14636polygon_table[144] = polygon_table[26] = p24; /* 2100 || 0122 */
14637polygon_table[36] = polygon_table[134] = p25; /* 0210 || 2012 */
14638polygon_table[9] = polygon_table[161] = p26; /* 0021 || 2201 */
14639
14640/* hexagon cases */
14641polygon_table[37] = polygon_table[133] = p27; /* 0211 || 2011 */
14642polygon_table[148] = polygon_table[22] = p28; /* 2110 || 0112 */
14643polygon_table[82] = polygon_table[88] = p29; /* 1102 || 1120 */
14644polygon_table[73] = polygon_table[97] = p30; /* 1021 || 1201 */
14645polygon_table[145] = polygon_table[25] = p31; /* 2101 || 0121 */
14646polygon_table[70] = polygon_table[100] = p32; /* 1012 || 1210 */
14647
14648/* 8-sided cases */
14649polygon_table[34] = function (c) { return [p07(c), p05(c)]; }; /* 0202 || 2020 with flipped == 0 */
14650polygon_table[35] = p33; /* flipped == 1 state for 0202 and 2020 */
14651polygon_table[136] = function (c) { return [p06(c), p04(c)]; }; /* 2020 || 0202 with flipped == 0 */
14652
14653/* 6-sided cases */
14654polygon_table[153] = function (c) { return [p02(c), p00(c)]; }; /* 0101 with flipped == 0 || 2121 with flipped == 2 */
14655polygon_table[102] = function (c) { return [p01(c), p03(c)]; }; /* 1010 with flipped == 0 || 1212 with flipped == 2 */
14656polygon_table[155] = p34; /* 0101 with flipped == 1 || 2121 with flipped == 1 */
14657polygon_table[103] = p35; /* 1010 with flipped == 1 || 1212 with flipped == 1 */
14658
14659/* 7-sided cases */
14660polygon_table[152] = function (c) { return [p02(c), p04(c)]; }; /* 2120 with flipped == 2 || 0102 with flipped == 0 */
14661polygon_table[156] = p36; /* 2120 with flipped == 1 || 0102 with flipped == 1 */
14662polygon_table[137] = function (c) { return [p06(c), p00(c)]; }; /* 2021 with flipped == 2 || 0201 with flipped == 0 */
14663polygon_table[139] = p37; /* 2021 with flipped == 1 || 0201 with flipped == 1 */
14664polygon_table[98] = function (c) { return [p05(c), p03(c)]; }; /* 1202 with flipped == 2 || 1020 with flipped == 0 */
14665polygon_table[99] = p38; /* 1202 with flipped == 1 || 1020 with flipped == 1 */
14666polygon_table[38] = function (c) { return [p01(c), p07(c)]; }; /* 0212 with flipped == 2 || 2010 with flipped == 0 */
14667polygon_table[39] = p39; /* 0212 with flipped == 1 || 2010 with flipped == 1 */
14668
14669
14670/*
14671####################################
14672Some small helper functions
14673####################################
14674*/
14675
14676/* assume that x1 == 1 && x0 == 0 */
14677function interpolateX$1(y, y0, y1) {
14678 return (y - y0) / (y1 - y0);
14679}
14680
14681function isArray(myArray) {
14682 return myArray.constructor.toString().indexOf('Array') > -1;
14683}
14684
14685/*
14686####################################
14687Below is the actual Marching Squares implementation
14688####################################
14689*/
14690
14691function computeBandGrid(data, minV, bandwidth) {
14692 var rows = data.length - 1;
14693 var cols = data[0].length - 1;
14694 var BandGrid = { rows: rows, cols: cols, cells: [] };
14695
14696 var maxV = minV + Math.abs(bandwidth);
14697
14698 for (var j = 0; j < rows; ++j) {
14699 BandGrid.cells[j] = [];
14700 for (var i = 0; i < cols; ++i) {
14701 /* compose the 4-trit corner representation */
14702 var cval = 0;
14703
14704 var tl = data[j + 1][i];
14705 var tr = data[j + 1][i + 1];
14706 var br = data[j][i + 1];
14707 var bl = data[j][i];
14708
14709 if (isNaN(tl) || isNaN(tr) || isNaN(br) || isNaN(bl)) {
14710 continue;
14711 }
14712
14713 cval |= (tl < minV) ? 0 : (tl > maxV) ? 128 : 64;
14714 cval |= (tr < minV) ? 0 : (tr > maxV) ? 32 : 16;
14715 cval |= (br < minV) ? 0 : (br > maxV) ? 8 : 4;
14716 cval |= (bl < minV) ? 0 : (bl > maxV) ? 2 : 1;
14717
14718 var cval_real = +cval;
14719
14720 /* resolve ambiguity via averaging */
14721 var flipped = 0;
14722 if ((cval === 17) || /* 0101 */
14723 (cval === 18) || /* 0102 */
14724 (cval === 33) || /* 0201 */
14725 (cval === 34) || /* 0202 */
14726 (cval === 38) || /* 0212 */
14727 (cval === 68) || /* 1010 */
14728 (cval === 72) || /* 1020 */
14729 (cval === 98) || /* 1202 */
14730 (cval === 102) || /* 1212 */
14731 (cval === 132) || /* 2010 */
14732 (cval === 136) || /* 2020 */
14733 (cval === 137) || /* 2021 */
14734 (cval === 152) || /* 2120 */
14735 (cval === 153) /* 2121 */
14736 ) {
14737 var average = (tl + tr + br + bl) / 4;
14738 /* set flipped state */
14739 flipped = (average > maxV) ? 2 : (average < minV) ? 0 : 1;
14740
14741 /* adjust cval for flipped cases */
14742
14743 /* 8-sided cases */
14744 if (cval === 34) {
14745 if (flipped === 1) {
14746 cval = 35;
14747 } else if (flipped === 0) {
14748 cval = 136;
14749 }
14750 } else if (cval === 136) {
14751 if (flipped === 1) {
14752 cval = 35;
14753 flipped = 4;
14754 } else if (flipped === 0) {
14755 cval = 34;
14756 }
14757 }
14758
14759 /* 6-sided polygon cases */
14760 else if (cval === 17) {
14761 if (flipped === 1) {
14762 cval = 155;
14763 flipped = 4;
14764 } else if (flipped === 0) {
14765 cval = 153;
14766 }
14767 } else if (cval === 68) {
14768 if (flipped === 1) {
14769 cval = 103;
14770 flipped = 4;
14771 } else if (flipped === 0) {
14772 cval = 102;
14773 }
14774 } else if (cval === 153) {
14775 if (flipped === 1)
14776 cval = 155;
14777 } else if (cval === 102) {
14778 if (flipped === 1)
14779 cval = 103;
14780 }
14781
14782 /* 7-sided polygon cases */
14783 else if (cval === 152) {
14784 if (flipped < 2) {
14785 cval = 156;
14786 flipped = 1;
14787 }
14788 } else if (cval === 137) {
14789 if (flipped < 2) {
14790 cval = 139;
14791 flipped = 1;
14792 }
14793 } else if (cval === 98) {
14794 if (flipped < 2) {
14795 cval = 99;
14796 flipped = 1;
14797 }
14798 } else if (cval === 38) {
14799 if (flipped < 2) {
14800 cval = 39;
14801 flipped = 1;
14802 }
14803 } else if (cval === 18) {
14804 if (flipped > 0) {
14805 cval = 156;
14806 flipped = 4;
14807 } else {
14808 cval = 152;
14809 }
14810 } else if (cval === 33) {
14811 if (flipped > 0) {
14812 cval = 139;
14813 flipped = 4;
14814 } else {
14815 cval = 137;
14816 }
14817 } else if (cval === 72) {
14818 if (flipped > 0) {
14819 cval = 99;
14820 flipped = 4;
14821 } else {
14822 cval = 98;
14823 }
14824 } else if (cval === 132) {
14825 if (flipped > 0) {
14826 cval = 39;
14827 flipped = 4;
14828 } else {
14829 cval = 38;
14830 }
14831 }
14832 }
14833
14834 /* add cell to BandGrid if it contains at least one polygon-side */
14835 if ((cval != 0) && (cval != 170)) {
14836 var topleft, topright, bottomleft, bottomright,
14837 righttop, rightbottom, lefttop, leftbottom;
14838
14839 topleft = topright = bottomleft = bottomright = righttop =
14840 rightbottom = lefttop = leftbottom = 0.5;
14841
14842 var edges = [];
14843
14844 /* do interpolation here */
14845 /* 1st Triangles */
14846 if (cval === 1) { /* 0001 */
14847 bottomleft = 1 - interpolateX$1(minV, br, bl);
14848 leftbottom = 1 - interpolateX$1(minV, tl, bl);
14849 edges.push(isoBandEdgeBL[cval]);
14850 } else if (cval === 169) { /* 2221 */
14851 bottomleft = interpolateX$1(maxV, bl, br);
14852 leftbottom = interpolateX$1(maxV, bl, tl);
14853 edges.push(isoBandEdgeBL[cval]);
14854 } else if (cval === 4) { /* 0010 */
14855 rightbottom = 1 - interpolateX$1(minV, tr, br);
14856 bottomright = interpolateX$1(minV, bl, br);
14857 edges.push(isoBandEdgeRB[cval]);
14858 } else if (cval === 166) { /* 2212 */
14859 rightbottom = interpolateX$1(maxV, br, tr);
14860 bottomright = 1 - interpolateX$1(maxV, br, bl);
14861 edges.push(isoBandEdgeRB[cval]);
14862 } else if (cval === 16) { /* 0100 */
14863 righttop = interpolateX$1(minV, br, tr);
14864 topright = interpolateX$1(minV, tl, tr);
14865 edges.push(isoBandEdgeRT[cval]);
14866 } else if (cval === 154) { /* 2122 */
14867 righttop = 1 - interpolateX$1(maxV, tr, br);
14868 topright = 1 - interpolateX$1(maxV, tr, tl);
14869 edges.push(isoBandEdgeRT[cval]);
14870 } else if (cval === 64) { /* 1000 */
14871 lefttop = interpolateX$1(minV, bl, tl);
14872 topleft = 1 - interpolateX$1(minV, tr, tl);
14873 edges.push(isoBandEdgeLT[cval]);
14874 } else if (cval === 106) { /* 1222 */
14875 lefttop = 1 - interpolateX$1(maxV, tl, bl);
14876 topleft = interpolateX$1(maxV, tl, tr);
14877 edges.push(isoBandEdgeLT[cval]);
14878 }
14879 /* 2nd Trapezoids */
14880 else if (cval === 168) { /* 2220 */
14881 bottomright = interpolateX$1(maxV, bl, br);
14882 bottomleft = interpolateX$1(minV, bl, br);
14883 leftbottom = interpolateX$1(minV, bl, tl);
14884 lefttop = interpolateX$1(maxV, bl, tl);
14885 edges.push(isoBandEdgeBR[cval]);
14886 edges.push(isoBandEdgeBL[cval]);
14887 } else if (cval === 2) { /* 0002 */
14888 bottomright = 1 - interpolateX$1(minV, br, bl);
14889 bottomleft = 1 - interpolateX$1(maxV, br, bl);
14890 leftbottom = 1 - interpolateX$1(maxV, tl, bl);
14891 lefttop = 1 - interpolateX$1(minV, tl, bl);
14892 edges.push(isoBandEdgeBR[cval]);
14893 edges.push(isoBandEdgeBL[cval]);
14894 } else if (cval === 162) { /* 2202 */
14895 righttop = interpolateX$1(maxV, br, tr);
14896 rightbottom = interpolateX$1(minV, br, tr);
14897 bottomright = 1 - interpolateX$1(minV, br, bl);
14898 bottomleft = 1 - interpolateX$1(maxV, br, bl);
14899 edges.push(isoBandEdgeBR[cval]);
14900 edges.push(isoBandEdgeBL[cval]);
14901 } else if (cval === 8) { /* 0020 */
14902 righttop = 1 - interpolateX$1(minV, tr, br);
14903 rightbottom = 1 - interpolateX$1(maxV, tr, br);
14904 bottomright = interpolateX$1(maxV, bl, br);
14905 bottomleft = interpolateX$1(minV, bl, br);
14906 edges.push(isoBandEdgeRT[cval]);
14907 edges.push(isoBandEdgeRB[cval]);
14908 } else if (cval === 138) { /* 2022 */
14909 righttop = 1 - interpolateX$1(minV, tr, br);
14910 rightbottom = 1 - interpolateX$1(maxV, tr, br);
14911 topleft = 1 - interpolateX$1(maxV, tr, tl);
14912 topright = 1 - interpolateX$1(minV, tr, tl);
14913 edges.push(isoBandEdgeRT[cval]);
14914 edges.push(isoBandEdgeRB[cval]);
14915 } else if (cval === 32) { /* 0200 */
14916 righttop = interpolateX$1(maxV, br, tr);
14917 rightbottom = interpolateX$1(minV, br, tr);
14918 topleft = interpolateX$1(minV, tl, tr);
14919 topright = interpolateX$1(maxV, tl, tr);
14920 edges.push(isoBandEdgeRT[cval]);
14921 edges.push(isoBandEdgeRB[cval]);
14922 } else if (cval === 42) { /* 0222 */
14923 leftbottom = 1 - interpolateX$1(maxV, tl, bl);
14924 lefttop = 1 - interpolateX$1(minV, tl, bl);
14925 topleft = interpolateX$1(minV, tl, tr);
14926 topright = interpolateX$1(maxV, tl, tr);
14927 edges.push(isoBandEdgeLB[cval]);
14928 edges.push(isoBandEdgeLT[cval]);
14929 } else if (cval === 128) { /* 2000 */
14930 leftbottom = interpolateX$1(minV, bl, tl);
14931 lefttop = interpolateX$1(maxV, bl, tl);
14932 topleft = 1 - interpolateX$1(maxV, tr, tl);
14933 topright = 1 - interpolateX$1(minV, tr, tl);
14934 edges.push(isoBandEdgeLB[cval]);
14935 edges.push(isoBandEdgeLT[cval]);
14936 }
14937
14938 /* 3rd rectangle cases */
14939 if (cval === 5) { /* 0011 */
14940 rightbottom = 1 - interpolateX$1(minV, tr, br);
14941 leftbottom = 1 - interpolateX$1(minV, tl, bl);
14942 edges.push(isoBandEdgeRB[cval]);
14943 } else if (cval === 165) { /* 2211 */
14944 rightbottom = interpolateX$1(maxV, br, tr);
14945 leftbottom = interpolateX$1(maxV, bl, tl);
14946 edges.push(isoBandEdgeRB[cval]);
14947 } else if (cval === 20) { /* 0110 */
14948 bottomright = interpolateX$1(minV, bl, br);
14949 topright = interpolateX$1(minV, tl, tr);
14950 edges.push(isoBandEdgeBR[cval]);
14951 } else if (cval === 150) { /* 2112 */
14952 bottomright = 1 - interpolateX$1(maxV, br, bl);
14953 topright = 1 - interpolateX$1(maxV, tr, tl);
14954 edges.push(isoBandEdgeBR[cval]);
14955 } else if (cval === 80) { /* 1100 */
14956 righttop = interpolateX$1(minV, br, tr);
14957 lefttop = interpolateX$1(minV, bl, tl);
14958 edges.push(isoBandEdgeRT[cval]);
14959 } else if (cval === 90) { /* 1122 */
14960 righttop = 1 - interpolateX$1(maxV, tr, br);
14961 lefttop = 1 - interpolateX$1(maxV, tl, bl);
14962 edges.push(isoBandEdgeRT[cval]);
14963 } else if (cval === 65) { /* 1001 */
14964 bottomleft = 1 - interpolateX$1(minV, br, bl);
14965 topleft = 1 - interpolateX$1(minV, tr, tl);
14966 edges.push(isoBandEdgeBL[cval]);
14967 } else if (cval === 105) { /* 1221 */
14968 bottomleft = interpolateX$1(maxV, bl, br);
14969 topleft = interpolateX$1(maxV, tl, tr);
14970 edges.push(isoBandEdgeBL[cval]);
14971 } else if (cval === 160) { /* 2200 */
14972 righttop = interpolateX$1(maxV, br, tr);
14973 rightbottom = interpolateX$1(minV, br, tr);
14974 leftbottom = interpolateX$1(minV, bl, tl);
14975 lefttop = interpolateX$1(maxV, bl, tl);
14976 edges.push(isoBandEdgeRT[cval]);
14977 edges.push(isoBandEdgeRB[cval]);
14978 } else if (cval === 10) { /* 0022 */
14979 righttop = 1 - interpolateX$1(minV, tr, br);
14980 rightbottom = 1 - interpolateX$1(maxV, tr, br);
14981 leftbottom = 1 - interpolateX$1(maxV, tl, bl);
14982 lefttop = 1 - interpolateX$1(minV, tl, bl);
14983 edges.push(isoBandEdgeRT[cval]);
14984 edges.push(isoBandEdgeRB[cval]);
14985 } else if (cval === 130) { /* 2002 */
14986 bottomright = 1 - interpolateX$1(minV, br, bl);
14987 bottomleft = 1 - interpolateX$1(maxV, br, bl);
14988 topleft = 1 - interpolateX$1(maxV, tr, tl);
14989 topright = 1 - interpolateX$1(minV, tr, tl);
14990 edges.push(isoBandEdgeBR[cval]);
14991 edges.push(isoBandEdgeBL[cval]);
14992 } else if (cval === 40) { /* 0220 */
14993 bottomright = interpolateX$1(maxV, bl, br);
14994 bottomleft = interpolateX$1(minV, bl, br);
14995 topleft = interpolateX$1(minV, tl, tr);
14996 topright = interpolateX$1(maxV, tl, tr);
14997 edges.push(isoBandEdgeBR[cval]);
14998 edges.push(isoBandEdgeBL[cval]);
14999 }
15000
15001 /* 4th single pentagon cases */
15002 else if (cval === 101) { /* 1211 */
15003 rightbottom = interpolateX$1(maxV, br, tr);
15004 topleft = interpolateX$1(maxV, tl, tr);
15005 edges.push(isoBandEdgeRB[cval]);
15006 } else if (cval === 69) { /* 1011 */
15007 rightbottom = 1 - interpolateX$1(minV, tr, br);
15008 topleft = 1 - interpolateX$1(minV, tr, tl);
15009 edges.push(isoBandEdgeRB[cval]);
15010 } else if (cval === 149) { /* 2111 */
15011 leftbottom = interpolateX$1(maxV, bl, tl);
15012 topright = 1 - interpolateX$1(maxV, tr, tl);
15013 edges.push(isoBandEdgeLB[cval]);
15014 } else if (cval === 21) { /* 0111 */
15015 leftbottom = 1 - interpolateX$1(minV, tl, bl);
15016 topright = interpolateX$1(minV, tl, tr);
15017 edges.push(isoBandEdgeLB[cval]);
15018 } else if (cval === 86) { /* 1112 */
15019 bottomright = 1 - interpolateX$1(maxV, br, bl);
15020 lefttop = 1 - interpolateX$1(maxV, tl, bl);
15021 edges.push(isoBandEdgeBR[cval]);
15022 } else if (cval === 84) { /* 1110 */
15023 bottomright = interpolateX$1(minV, bl, br);
15024 lefttop = interpolateX$1(minV, bl, tl);
15025 edges.push(isoBandEdgeBR[cval]);
15026 } else if (cval === 89) { /* 1121 */
15027 righttop = 1 - interpolateX$1(maxV, tr, br);
15028 bottomleft = interpolateX$1(maxV, bl, br);
15029 edges.push(isoBandEdgeBL[cval]);
15030 } else if (cval === 81) { /* 1101 */
15031 righttop = interpolateX$1(minV, br, tr);
15032 bottomleft = 1 - interpolateX$1(minV, br, bl);
15033 edges.push(isoBandEdgeBL[cval]);
15034 } else if (cval === 96) { /* 1200 */
15035 righttop = interpolateX$1(maxV, br, tr);
15036 rightbottom = interpolateX$1(minV, br, tr);
15037 lefttop = interpolateX$1(minV, bl, tl);
15038 topleft = interpolateX$1(maxV, tl, tr);
15039 edges.push(isoBandEdgeRT[cval]);
15040 edges.push(isoBandEdgeRB[cval]);
15041 } else if (cval === 74) { /* 1022 */
15042 righttop = 1 - interpolateX$1(minV, tr, br);
15043 rightbottom = 1 - interpolateX$1(maxV, tr, br);
15044 lefttop = 1 - interpolateX$1(maxV, tl, bl);
15045 topleft = 1 - interpolateX$1(minV, tr, tl);
15046 edges.push(isoBandEdgeRT[cval]);
15047 edges.push(isoBandEdgeRB[cval]);
15048 } else if (cval === 24) { /* 0120 */
15049 righttop = 1 - interpolateX$1(maxV, tr, br);
15050 bottomright = interpolateX$1(maxV, bl, br);
15051 bottomleft = interpolateX$1(minV, bl, br);
15052 topright = interpolateX$1(minV, tl, tr);
15053 edges.push(isoBandEdgeRT[cval]);
15054 edges.push(isoBandEdgeBL[cval]);
15055 } else if (cval === 146) { /* 2102 */
15056 righttop = interpolateX$1(minV, br, tr);
15057 bottomright = 1 - interpolateX$1(minV, br, bl);
15058 bottomleft = 1 - interpolateX$1(maxV, br, bl);
15059 topright = 1 - interpolateX$1(maxV, tr, tl);
15060 edges.push(isoBandEdgeRT[cval]);
15061 edges.push(isoBandEdgeBL[cval]);
15062 } else if (cval === 6) { /* 0012 */
15063 rightbottom = 1 - interpolateX$1(minV, tr, br);
15064 bottomright = 1 - interpolateX$1(maxV, br, bl);
15065 leftbottom = 1 - interpolateX$1(maxV, tl, bl);
15066 lefttop = 1 - interpolateX$1(minV, tl, bl);
15067 edges.push(isoBandEdgeRB[cval]);
15068 edges.push(isoBandEdgeBR[cval]);
15069 } else if (cval === 164) { /* 2210 */
15070 rightbottom = interpolateX$1(maxV, br, tr);
15071 bottomright = interpolateX$1(minV, bl, br);
15072 leftbottom = interpolateX$1(minV, bl, tl);
15073 lefttop = interpolateX$1(maxV, bl, tl);
15074 edges.push(isoBandEdgeRB[cval]);
15075 edges.push(isoBandEdgeBR[cval]);
15076 } else if (cval === 129) { /* 2001 */
15077 bottomleft = 1 - interpolateX$1(minV, br, bl);
15078 leftbottom = interpolateX$1(maxV, bl, tl);
15079 topleft = 1 - interpolateX$1(maxV, tr, tl);
15080 topright = 1 - interpolateX$1(minV, tr, tl);
15081 edges.push(isoBandEdgeBL[cval]);
15082 edges.push(isoBandEdgeLB[cval]);
15083 } else if (cval === 41) { /* 0221 */
15084 bottomleft = interpolateX$1(maxV, bl, br);
15085 leftbottom = 1 - interpolateX$1(minV, tl, bl);
15086 topleft = interpolateX$1(minV, tl, tr);
15087 topright = interpolateX$1(maxV, tl, tr);
15088 edges.push(isoBandEdgeBL[cval]);
15089 edges.push(isoBandEdgeLB[cval]);
15090 } else if (cval === 66) { /* 1002 */
15091 bottomright = 1 - interpolateX$1(minV, br, bl);
15092 bottomleft = 1 - interpolateX$1(maxV, br, bl);
15093 lefttop = 1 - interpolateX$1(maxV, tl, bl);
15094 topleft = 1 - interpolateX$1(minV, tr, tl);
15095 edges.push(isoBandEdgeBR[cval]);
15096 edges.push(isoBandEdgeBL[cval]);
15097 } else if (cval === 104) { /* 1220 */
15098 bottomright = interpolateX$1(maxV, bl, br);
15099 bottomleft = interpolateX$1(minV, bl, br);
15100 lefttop = interpolateX$1(minV, bl, tl);
15101 topleft = interpolateX$1(maxV, tl, tr);
15102 edges.push(isoBandEdgeBL[cval]);
15103 edges.push(isoBandEdgeTL[cval]);
15104 } else if (cval === 144) { /* 2100 */
15105 righttop = interpolateX$1(minV, br, tr);
15106 leftbottom = interpolateX$1(minV, bl, tl);
15107 lefttop = interpolateX$1(maxV, bl, tl);
15108 topright = 1 - interpolateX$1(maxV, tr, tl);
15109 edges.push(isoBandEdgeRT[cval]);
15110 edges.push(isoBandEdgeLT[cval]);
15111 } else if (cval === 26) { /* 0122 */
15112 righttop = 1 - interpolateX$1(maxV, tr, br);
15113 leftbottom = 1 - interpolateX$1(maxV, tl, bl);
15114 lefttop = 1 - interpolateX$1(minV, tl, bl);
15115 topright = interpolateX$1(minV, tl, tr);
15116 edges.push(isoBandEdgeRT[cval]);
15117 edges.push(isoBandEdgeLT[cval]);
15118 } else if (cval === 36) { /* 0210 */
15119 rightbottom = interpolateX$1(maxV, br, tr);
15120 bottomright = interpolateX$1(minV, bl, br);
15121 topleft = interpolateX$1(minV, tl, tr);
15122 topright = interpolateX$1(maxV, tl, tr);
15123 edges.push(isoBandEdgeRB[cval]);
15124 edges.push(isoBandEdgeBR[cval]);
15125 } else if (cval === 134) { /* 2012 */
15126 rightbottom = 1 - interpolateX$1(minV, tr, br);
15127 bottomright = 1 - interpolateX$1(maxV, br, bl);
15128 topleft = 1 - interpolateX$1(maxV, tr, tl);
15129 topright = 1 - interpolateX$1(minV, tr, tl);
15130 edges.push(isoBandEdgeRB[cval]);
15131 edges.push(isoBandEdgeBR[cval]);
15132 } else if (cval === 9) { /* 0021 */
15133 righttop = 1 - interpolateX$1(minV, tr, br);
15134 rightbottom = 1 - interpolateX$1(maxV, tr, br);
15135 bottomleft = interpolateX$1(maxV, bl, br);
15136 leftbottom = 1 - interpolateX$1(minV, tl, bl);
15137 edges.push(isoBandEdgeRT[cval]);
15138 edges.push(isoBandEdgeRB[cval]);
15139 } else if (cval === 161) { /* 2201 */
15140 righttop = interpolateX$1(maxV, br, tr);
15141 rightbottom = interpolateX$1(minV, br, tr);
15142 bottomleft = 1 - interpolateX$1(minV, br, bl);
15143 leftbottom = interpolateX$1(maxV, bl, tl);
15144 edges.push(isoBandEdgeRT[cval]);
15145 edges.push(isoBandEdgeRB[cval]);
15146 }
15147
15148 /* 5th single hexagon cases */
15149 else if (cval === 37) { /* 0211 */
15150 rightbottom = interpolateX$1(maxV, br, tr);
15151 leftbottom = 1 - interpolateX$1(minV, tl, bl);
15152 topleft = interpolateX$1(minV, tl, tr);
15153 topright = interpolateX$1(maxV, tl, tr);
15154 edges.push(isoBandEdgeRB[cval]);
15155 edges.push(isoBandEdgeLB[cval]);
15156 } else if (cval === 133) { /* 2011 */
15157 rightbottom = 1 - interpolateX$1(minV, tr, br);
15158 leftbottom = interpolateX$1(maxV, bl, tl);
15159 topleft = 1 - interpolateX$1(maxV, tr, tl);
15160 topright = 1 - interpolateX$1(minV, tr, tl);
15161 edges.push(isoBandEdgeRB[cval]);
15162 edges.push(isoBandEdgeLB[cval]);
15163 } else if (cval === 148) { /* 2110 */
15164 bottomright = interpolateX$1(minV, bl, br);
15165 leftbottom = interpolateX$1(minV, bl, tl);
15166 lefttop = interpolateX$1(maxV, bl, tl);
15167 topright = 1 - interpolateX$1(maxV, tr, tl);
15168 edges.push(isoBandEdgeBR[cval]);
15169 edges.push(isoBandEdgeLT[cval]);
15170 } else if (cval === 22) { /* 0112 */
15171 bottomright = 1 - interpolateX$1(maxV, br, bl);
15172 leftbottom = 1 - interpolateX$1(maxV, tl, bl);
15173 lefttop = 1 - interpolateX$1(minV, tl, bl);
15174 topright = interpolateX$1(minV, tl, tr);
15175 edges.push(isoBandEdgeBR[cval]);
15176 edges.push(isoBandEdgeLT[cval]);
15177 } else if (cval === 82) { /* 1102 */
15178 righttop = interpolateX$1(minV, br, tr);
15179 bottomright = 1 - interpolateX$1(minV, br, bl);
15180 bottomleft = 1 - interpolateX$1(maxV, br, bl);
15181 lefttop = 1 - interpolateX$1(maxV, tl, bl);
15182 edges.push(isoBandEdgeRT[cval]);
15183 edges.push(isoBandEdgeBL[cval]);
15184 } else if (cval === 88) { /* 1120 */
15185 righttop = 1 - interpolateX$1(maxV, tr, br);
15186 bottomright = interpolateX$1(maxV, bl, br);
15187 bottomleft = interpolateX$1(minV, bl, br);
15188 lefttop = interpolateX$1(minV, bl, tl);
15189 edges.push(isoBandEdgeRT[cval]);
15190 edges.push(isoBandEdgeBL[cval]);
15191 } else if (cval === 73) { /* 1021 */
15192 righttop = 1 - interpolateX$1(minV, tr, br);
15193 rightbottom = 1 - interpolateX$1(maxV, tr, br);
15194 bottomleft = interpolateX$1(maxV, bl, br);
15195 topleft = 1 - interpolateX$1(minV, tr, tl);
15196 edges.push(isoBandEdgeRT[cval]);
15197 edges.push(isoBandEdgeRB[cval]);
15198 } else if (cval === 97) { /* 1201 */
15199 righttop = interpolateX$1(maxV, br, tr);
15200 rightbottom = interpolateX$1(minV, br, tr);
15201 bottomleft = 1 - interpolateX$1(minV, br, bl);
15202 topleft = interpolateX$1(maxV, tl, tr);
15203 edges.push(isoBandEdgeRT[cval]);
15204 edges.push(isoBandEdgeRB[cval]);
15205 } else if (cval === 145) { /* 2101 */
15206 righttop = interpolateX$1(minV, br, tr);
15207 bottomleft = 1 - interpolateX$1(minV, br, bl);
15208 leftbottom = interpolateX$1(maxV, bl, tl);
15209 topright = 1 - interpolateX$1(maxV, tr, tl);
15210 edges.push(isoBandEdgeRT[cval]);
15211 edges.push(isoBandEdgeLB[cval]);
15212 } else if (cval === 25) { /* 0121 */
15213 righttop = 1 - interpolateX$1(maxV, tr, br);
15214 bottomleft = interpolateX$1(maxV, bl, br);
15215 leftbottom = 1 - interpolateX$1(minV, tl, bl);
15216 topright = interpolateX$1(minV, tl, tr);
15217 edges.push(isoBandEdgeRT[cval]);
15218 edges.push(isoBandEdgeLB[cval]);
15219 } else if (cval === 70) { /* 1012 */
15220 rightbottom = 1 - interpolateX$1(minV, tr, br);
15221 bottomright = 1 - interpolateX$1(maxV, br, bl);
15222 lefttop = 1 - interpolateX$1(maxV, tl, bl);
15223 topleft = 1 - interpolateX$1(minV, tr, tl);
15224 edges.push(isoBandEdgeRB[cval]);
15225 edges.push(isoBandEdgeBR[cval]);
15226 } else if (cval === 100) { /* 1210 */
15227 rightbottom = interpolateX$1(maxV, br, tr);
15228 bottomright = interpolateX$1(minV, bl, br);
15229 lefttop = interpolateX$1(minV, bl, tl);
15230 topleft = interpolateX$1(maxV, tl, tr);
15231 edges.push(isoBandEdgeRB[cval]);
15232 edges.push(isoBandEdgeBR[cval]);
15233 }
15234
15235 /* 8-sided cases */
15236 else if (cval === 34) { /* 0202 || 2020 with flipped == 0 */
15237 if (flipped === 0) {
15238 righttop = 1 - interpolateX$1(minV, tr, br);
15239 rightbottom = 1 - interpolateX$1(maxV, tr, br);
15240 bottomright = interpolateX$1(maxV, bl, br);
15241 bottomleft = interpolateX$1(minV, bl, br);
15242 leftbottom = interpolateX$1(minV, bl, tl);
15243 lefttop = interpolateX$1(maxV, bl, tl);
15244 topleft = 1 - interpolateX$1(maxV, tr, tl);
15245 topright = 1 - interpolateX$1(minV, tr, tl);
15246 } else {
15247 righttop = interpolateX$1(maxV, br, tr);
15248 rightbottom = interpolateX$1(minV, br, tr);
15249 bottomright = 1 - interpolateX$1(minV, br, bl);
15250 bottomleft = 1 - interpolateX$1(maxV, br, bl);
15251 leftbottom = 1 - interpolateX$1(maxV, tl, bl);
15252 lefttop = 1 - interpolateX$1(minV, tl, bl);
15253 topleft = interpolateX$1(minV, tl, tr);
15254 topright = interpolateX$1(maxV, tl, tr);
15255 }
15256 edges.push(isoBandEdgeRT[cval]);
15257 edges.push(isoBandEdgeRB[cval]);
15258 edges.push(isoBandEdgeLB[cval]);
15259 edges.push(isoBandEdgeLT[cval]);
15260 } else if (cval === 35) { /* flipped == 1 state for 0202, and 2020 with flipped == 4*/
15261 if (flipped === 4) {
15262 righttop = 1 - interpolateX$1(minV, tr, br);
15263 rightbottom = 1 - interpolateX$1(maxV, tr, br);
15264 bottomright = interpolateX$1(maxV, bl, br);
15265 bottomleft = interpolateX$1(minV, bl, br);
15266 leftbottom = interpolateX$1(minV, bl, tl);
15267 lefttop = interpolateX$1(maxV, bl, tl);
15268 topleft = 1 - interpolateX$1(maxV, tr, tl);
15269 topright = 1 - interpolateX$1(minV, tr, tl);
15270 } else {
15271 righttop = interpolateX$1(maxV, br, tr);
15272 rightbottom = interpolateX$1(minV, br, tr);
15273 bottomright = 1 - interpolateX$1(minV, br, bl);
15274 bottomleft = 1 - interpolateX$1(maxV, br, bl);
15275 leftbottom = 1 - interpolateX$1(maxV, tl, bl);
15276 lefttop = 1 - interpolateX$1(minV, tl, bl);
15277 topleft = interpolateX$1(minV, tl, tr);
15278 topright = interpolateX$1(maxV, tl, tr);
15279 }
15280 edges.push(isoBandEdgeRT[cval]);
15281 edges.push(isoBandEdgeRB[cval]);
15282 edges.push(isoBandEdgeBL[cval]);
15283 edges.push(isoBandEdgeLT[cval]);
15284 } else if (cval === 136) { /* 2020 || 0202 with flipped == 0 */
15285 if (flipped === 0) {
15286 righttop = interpolateX$1(maxV, br, tr);
15287 rightbottom = interpolateX$1(minV, br, tr);
15288 bottomright = 1 - interpolateX$1(minV, br, bl);
15289 bottomleft = 1 - interpolateX$1(maxV, br, bl);
15290 leftbottom = 1 - interpolateX$1(maxV, tl, bl);
15291 lefttop = 1 - interpolateX$1(minV, tl, bl);
15292 topleft = interpolateX$1(minV, tl, tr);
15293 topright = interpolateX$1(maxV, tl, tr);
15294 } else {
15295 righttop = 1 - interpolateX$1(minV, tr, br);
15296 rightbottom = 1 - interpolateX$1(maxV, tr, br);
15297 bottomright = interpolateX$1(maxV, bl, br);
15298 bottomleft = interpolateX$1(minV, bl, br);
15299 leftbottom = interpolateX$1(minV, bl, tl);
15300 lefttop = interpolateX$1(maxV, bl, tl);
15301 topleft = 1 - interpolateX$1(maxV, tr, tl);
15302 topright = 1 - interpolateX$1(minV, tr, tl);
15303 }
15304 edges.push(isoBandEdgeRT[cval]);
15305 edges.push(isoBandEdgeRB[cval]);
15306 edges.push(isoBandEdgeLB[cval]);
15307 edges.push(isoBandEdgeLT[cval]);
15308 }
15309
15310 /* 6-sided polygon cases */
15311 else if (cval === 153) { /* 0101 with flipped == 0 || 2121 with flipped == 2 */
15312 if (flipped === 0) {
15313 righttop = interpolateX$1(minV, br, tr);
15314 bottomleft = 1 - interpolateX$1(minV, br, bl);
15315 leftbottom = 1 - interpolateX$1(minV, tl, bl);
15316 topright = interpolateX$1(minV, tl, tr);
15317 } else {
15318 righttop = 1 - interpolateX$1(maxV, tr, br);
15319 bottomleft = interpolateX$1(maxV, bl, br);
15320 leftbottom = interpolateX$1(maxV, bl, tl);
15321 topright = 1 - interpolateX$1(maxV, tr, tl);
15322 }
15323 edges.push(isoBandEdgeRT[cval]);
15324 edges.push(isoBandEdgeBL[cval]);
15325 } else if (cval === 102) { /* 1010 with flipped == 0 || 1212 with flipped == 2 */
15326 if (flipped === 0) {
15327 rightbottom = 1 - interpolateX$1(minV, tr, br);
15328 bottomright = interpolateX$1(minV, bl, br);
15329 lefttop = interpolateX$1(minV, bl, tl);
15330 topleft = 1 - interpolateX$1(minV, tr, tl);
15331 } else {
15332 rightbottom = interpolateX$1(maxV, br, tr);
15333 bottomright = 1 - interpolateX$1(maxV, br, bl);
15334 lefttop = 1 - interpolateX$1(maxV, tl, bl);
15335 topleft = interpolateX$1(maxV, tl, tr);
15336 }
15337 edges.push(isoBandEdgeRB[cval]);
15338 edges.push(isoBandEdgeLT[cval]);
15339 } else if (cval === 155) { /* 0101 with flipped == 4 || 2121 with flipped == 1 */
15340 if (flipped === 4) {
15341 righttop = interpolateX$1(minV, br, tr);
15342 bottomleft = 1 - interpolateX$1(minV, br, bl);
15343 leftbottom = 1 - interpolateX$1(minV, tl, bl);
15344 topright = interpolateX$1(minV, tl, tr);
15345 } else {
15346 righttop = 1 - interpolateX$1(maxV, tr, br);
15347 bottomleft = interpolateX$1(maxV, bl, br);
15348 leftbottom = interpolateX$1(maxV, bl, tl);
15349 topright = 1 - interpolateX$1(maxV, tr, tl);
15350 }
15351 edges.push(isoBandEdgeRT[cval]);
15352 edges.push(isoBandEdgeLB[cval]);
15353 } else if (cval === 103) { /* 1010 with flipped == 4 || 1212 with flipped == 1 */
15354 if (flipped === 4) {
15355 rightbottom = 1 - interpolateX$1(minV, tr, br);
15356 bottomright = interpolateX$1(minV, bl, br);
15357 lefttop = interpolateX$1(minV, bl, tl);
15358 topleft = 1 - interpolateX$1(minV, tr, tl);
15359 } else {
15360 rightbottom = interpolateX$1(maxV, br, tr);
15361 bottomright = 1 - interpolateX$1(maxV, br, bl);
15362 lefttop = 1 - interpolateX$1(maxV, tl, bl);
15363 topleft = interpolateX$1(maxV, tl, tr);
15364 }
15365 edges.push(isoBandEdgeRB[cval]);
15366 edges.push(isoBandEdgeBR[cval]);
15367 }
15368
15369 /* 7-sided polygon cases */
15370 else if (cval === 152) { /* 2120 with flipped == 2 || 0102 with flipped == 0 */
15371 if (flipped === 0) {
15372 righttop = interpolateX$1(minV, br, tr);
15373 bottomright = 1 - interpolateX$1(minV, br, bl);
15374 bottomleft = 1 - interpolateX$1(maxV, br, bl);
15375 leftbottom = 1 - interpolateX$1(maxV, tl, bl);
15376 lefttop = 1 - interpolateX$1(minV, tl, bl);
15377 topright = interpolateX$1(minV, tl, tr);
15378 } else {
15379 righttop = 1 - interpolateX$1(maxV, tr, br);
15380 bottomright = interpolateX$1(maxV, bl, br);
15381 bottomleft = interpolateX$1(minV, bl, br);
15382 leftbottom = interpolateX$1(minV, bl, tl);
15383 lefttop = interpolateX$1(maxV, bl, tl);
15384 topright = 1 - interpolateX$1(maxV, tr, tl);
15385 }
15386 edges.push(isoBandEdgeRT[cval]);
15387 edges.push(isoBandEdgeBR[cval]);
15388 edges.push(isoBandEdgeBL[cval]);
15389 } else if (cval === 156) { /* 2120 with flipped == 1 || 0102 with flipped == 4 */
15390 if (flipped === 4) {
15391 righttop = interpolateX$1(minV, br, tr);
15392 bottomright = 1 - interpolateX$1(minV, br, bl);
15393 bottomleft = 1 - interpolateX$1(maxV, br, bl);
15394 leftbottom = 1 - interpolateX$1(maxV, tl, bl);
15395 lefttop = 1 - interpolateX$1(minV, tl, bl);
15396 topright = interpolateX$1(minV, tl, tr);
15397 } else {
15398 righttop = 1 - interpolateX$1(maxV, tr, br);
15399 bottomright = interpolateX$1(maxV, bl, br);
15400 bottomleft = interpolateX$1(minV, bl, br);
15401 leftbottom = interpolateX$1(minV, bl, tl);
15402 lefttop = interpolateX$1(maxV, bl, tl);
15403 topright = 1 - interpolateX$1(maxV, tr, tl);
15404 }
15405 edges.push(isoBandEdgeRT[cval]);
15406 edges.push(isoBandEdgeBL[cval]);
15407 edges.push(isoBandEdgeLT[cval]);
15408 } else if (cval === 137) { /* 2021 with flipped == 2 || 0201 with flipped == 0 */
15409 if (flipped === 0) {
15410 righttop = interpolateX$1(maxV, br, tr);
15411 rightbottom = interpolateX$1(minV, br, tr);
15412 bottomleft = 1 - interpolateX$1(minV, br, bl);
15413 leftbottom = 1 - interpolateX$1(minV, tl, bl);
15414 topleft = interpolateX$1(minV, tl, tr);
15415 topright = interpolateX$1(maxV, tl, tr);
15416 } else {
15417 righttop = 1 - interpolateX$1(minV, tr, br);
15418 rightbottom = 1 - interpolateX$1(maxV, tr, br);
15419 bottomleft = interpolateX$1(maxV, bl, br);
15420 leftbottom = interpolateX$1(maxV, bl, tl);
15421 topleft = 1 - interpolateX$1(maxV, tr, tl);
15422 topright = 1 - interpolateX$1(minV, tr, tl);
15423 }
15424 edges.push(isoBandEdgeRT[cval]);
15425 edges.push(isoBandEdgeRB[cval]);
15426 edges.push(isoBandEdgeBL[cval]);
15427 } else if (cval === 139) { /* 2021 with flipped == 1 || 0201 with flipped == 4 */
15428 if (flipped === 4) {
15429 righttop = interpolateX$1(maxV, br, tr);
15430 rightbottom = interpolateX$1(minV, br, tr);
15431 bottomleft = 1 - interpolateX$1(minV, br, bl);
15432 leftbottom = 1 - interpolateX$1(minV, tl, bl);
15433 topleft = interpolateX$1(minV, tl, tr);
15434 topright = interpolateX$1(maxV, tl, tr);
15435 } else {
15436 righttop = 1 - interpolateX$1(minV, tr, br);
15437 rightbottom = 1 - interpolateX$1(maxV, tr, br);
15438 bottomleft = interpolateX$1(maxV, bl, br);
15439 leftbottom = interpolateX$1(maxV, bl, tl);
15440 topleft = 1 - interpolateX$1(maxV, tr, tl);
15441 topright = 1 - interpolateX$1(minV, tr, tl);
15442 }
15443 edges.push(isoBandEdgeRT[cval]);
15444 edges.push(isoBandEdgeRB[cval]);
15445 edges.push(isoBandEdgeLB[cval]);
15446 } else if (cval === 98) { /* 1202 with flipped == 2 || 1020 with flipped == 0 */
15447 if (flipped === 0) {
15448 righttop = 1 - interpolateX$1(minV, tr, br);
15449 rightbottom = 1 - interpolateX$1(maxV, tr, br);
15450 bottomright = interpolateX$1(maxV, bl, br);
15451 bottomleft = interpolateX$1(minV, bl, br);
15452 lefttop = interpolateX$1(minV, bl, tl);
15453 topleft = 1 - interpolateX$1(minV, tr, tl);
15454 } else {
15455 righttop = interpolateX$1(maxV, br, tr);
15456 rightbottom = interpolateX$1(minV, br, tr);
15457 bottomright = 1 - interpolateX$1(minV, br, bl);
15458 bottomleft = 1 - interpolateX$1(maxV, br, bl);
15459 lefttop = 1 - interpolateX$1(maxV, tl, bl);
15460 topleft = interpolateX$1(maxV, tl, tr);
15461 }
15462 edges.push(isoBandEdgeRT[cval]);
15463 edges.push(isoBandEdgeRB[cval]);
15464 edges.push(isoBandEdgeLT[cval]);
15465 } else if (cval === 99) { /* 1202 with flipped == 1 || 1020 with flipped == 4 */
15466 if (flipped === 4) {
15467 righttop = 1 - interpolateX$1(minV, tr, br);
15468 rightbottom = 1 - interpolateX$1(maxV, tr, br);
15469 bottomright = interpolateX$1(maxV, bl, br);
15470 bottomleft = interpolateX$1(minV, bl, br);
15471 lefttop = interpolateX$1(minV, bl, tl);
15472 topleft = 1 - interpolateX$1(minV, tr, tl);
15473 } else {
15474 righttop = interpolateX$1(maxV, br, tr);
15475 rightbottom = interpolateX$1(minV, br, tr);
15476 bottomright = 1 - interpolateX$1(minV, br, bl);
15477 bottomleft = 1 - interpolateX$1(maxV, br, bl);
15478 lefttop = 1 - interpolateX$1(maxV, tl, bl);
15479 topleft = interpolateX$1(maxV, tl, tr);
15480 }
15481 edges.push(isoBandEdgeRT[cval]);
15482 edges.push(isoBandEdgeRB[cval]);
15483 edges.push(isoBandEdgeBL[cval]);
15484 } else if (cval === 38) { /* 0212 with flipped == 2 || 2010 with flipped == 0 */
15485 if (flipped === 0) {
15486 rightbottom = 1 - interpolateX$1(minV, tr, br);
15487 bottomright = interpolateX$1(minV, bl, br);
15488 leftbottom = interpolateX$1(minV, bl, tl);
15489 lefttop = interpolateX$1(maxV, bl, tl);
15490 topleft = 1 - interpolateX$1(maxV, tr, tl);
15491 topright = 1 - interpolateX$1(minV, tr, tl);
15492 } else {
15493 rightbottom = interpolateX$1(maxV, br, tr);
15494 bottomright = 1 - interpolateX$1(maxV, br, bl);
15495 leftbottom = 1 - interpolateX$1(maxV, tl, bl);
15496 lefttop = 1 - interpolateX$1(minV, tl, bl);
15497 topleft = interpolateX$1(minV, tl, tr);
15498 topright = interpolateX$1(maxV, tl, tr);
15499 }
15500 edges.push(isoBandEdgeRB[cval]);
15501 edges.push(isoBandEdgeLB[cval]);
15502 edges.push(isoBandEdgeLT[cval]);
15503 } else if (cval === 39) { /* 0212 with flipped == 1 || 2010 with flipped == 4 */
15504 if (flipped === 4) {
15505 rightbottom = 1 - interpolateX$1(minV, tr, br);
15506 bottomright = interpolateX$1(minV, bl, br);
15507 leftbottom = interpolateX$1(minV, bl, tl);
15508 lefttop = interpolateX$1(maxV, bl, tl);
15509 topleft = 1 - interpolateX$1(maxV, tr, tl);
15510 topright = 1 - interpolateX$1(minV, tr, tl);
15511 } else {
15512 rightbottom = interpolateX$1(maxV, br, tr);
15513 bottomright = 1 - interpolateX$1(maxV, br, bl);
15514 leftbottom = 1 - interpolateX$1(maxV, tl, bl);
15515 lefttop = 1 - interpolateX$1(minV, tl, bl);
15516 topleft = interpolateX$1(minV, tl, tr);
15517 topright = interpolateX$1(maxV, tl, tr);
15518 }
15519 edges.push(isoBandEdgeRB[cval]);
15520 edges.push(isoBandEdgeBR[cval]);
15521 edges.push(isoBandEdgeLT[cval]);
15522 } else if (cval === 85) {
15523 righttop = 1;
15524 rightbottom = 0;
15525 bottomright = 1;
15526 bottomleft = 0;
15527 leftbottom = 0;
15528 lefttop = 1;
15529 topleft = 0;
15530 topright = 1;
15531 }
15532
15533 if (topleft < 0 || topleft > 1 || topright < 0 || topright > 1 || righttop < 0 || righttop > 1 || bottomright < 0 || bottomright > 1 || leftbottom < 0 || leftbottom > 1 || lefttop < 0 || lefttop > 1) {
15534 console.log('MarchingSquaresJS-isoBands: ' + cval + ' ' + cval_real + ' ' + tl + ',' + tr + ',' + br + ',' + bl + ' ' + flipped + ' ' + topleft + ' ' + topright + ' ' + righttop + ' ' + rightbottom + ' ' + bottomright + ' ' + bottomleft + ' ' + leftbottom + ' ' + lefttop);
15535 }
15536
15537 BandGrid.cells[j][i] = {
15538 cval: cval,
15539 cval_real: cval_real,
15540 flipped: flipped,
15541 topleft: topleft,
15542 topright: topright,
15543 righttop: righttop,
15544 rightbottom: rightbottom,
15545 bottomright: bottomright,
15546 bottomleft: bottomleft,
15547 leftbottom: leftbottom,
15548 lefttop: lefttop,
15549 edges: edges
15550 };
15551 }
15552 }
15553 }
15554
15555 return BandGrid;
15556}
15557
15558function BandGrid2AreaPaths(grid) {
15559 var areas = [];
15560 var rows = grid.rows;
15561 var cols = grid.cols;
15562 var currentPolygon = [];
15563
15564 for (var j = 0; j < rows; j++) {
15565 for (var i = 0; i < cols; i++) {
15566 if ((typeof grid.cells[j][i] !== 'undefined') && (grid.cells[j][i].edges.length > 0)) {
15567 /* trace back polygon path starting from this cell */
15568
15569 var cell = grid.cells[j][i];
15570
15571 /* get start coordinates */
15572
15573 var prev = getStartXY(cell),
15574 next = null,
15575 p = i,
15576 q = j;
15577
15578 if (prev !== null) {
15579 currentPolygon.push([prev.p[0] + p, prev.p[1] + q]);
15580 //console.log(cell);
15581 //console.log("coords: " + (prev.p[0] + p) + " " + (prev.p[1] + q));
15582 }
15583
15584 do {
15585 //console.log(p + "," + q);
15586 //console.log(grid.cells[q][p]);
15587 //console.log(grid.cells[q][p].edges);
15588 //console.log("from : " + prev.x + " " + prev.y + " " + prev.o);
15589
15590 next = getExitXY(grid.cells[q][p], prev.x, prev.y, prev.o);
15591 if (next !== null) {
15592 //console.log("coords: " + (next.p[0] + p) + " " + (next.p[1] + q));
15593 currentPolygon.push([next.p[0] + p, next.p[1] + q]);
15594 p += next.x;
15595 q += next.y;
15596 prev = next;
15597 } else {
15598 //console.log("getExitXY() returned null!");
15599 break;
15600 }
15601 //console.log("to : " + next.x + " " + next.y + " " + next.o);
15602 /* special case, where we've reached the grid boundaries */
15603 if ((q < 0) || (q >= rows) || (p < 0) || (p >= cols) || (typeof grid.cells[q][p] === 'undefined')) {
15604 /* to create a closed path, we need to trace our way
15605 arround the missing data, until we find an entry
15606 point again
15607 */
15608
15609 /* set back coordinates of current cell */
15610 p -= next.x;
15611 q -= next.y;
15612
15613 //console.log("reached boundary at " + p + " " + q);
15614
15615 var missing = traceOutOfGridPath(grid, p, q, next.x, next.y, next.o);
15616 if (missing !== null) {
15617 missing.path.forEach(function (pp) {
15618 //console.log("coords: " + (pp[0]) + " " + (pp[1]));
15619 currentPolygon.push(pp);
15620 });
15621 p = missing.i;
15622 q = missing.j;
15623 prev = missing;
15624 } else {
15625 break;
15626 }
15627 //console.log(grid.cells[q][p]);
15628 }
15629 } while ((typeof grid.cells[q][p] !== 'undefined') &&
15630 (grid.cells[q][p].edges.length > 0));
15631
15632 areas.push(currentPolygon);
15633 //console.log("next polygon");
15634 //console.log(currentPolygon);
15635 currentPolygon = [];
15636 if (grid.cells[j][i].edges.length > 0)
15637 i--;
15638 }
15639 }
15640 }
15641 return areas;
15642}
15643
15644function traceOutOfGridPath(grid, i, j, d_x, d_y, d_o) {
15645 var cell = grid.cells[j][i];
15646 var cval = cell.cval_real;
15647 var p = i + d_x,
15648 q = j + d_y;
15649 var path = [];
15650 var closed = false;
15651
15652 while (!closed) {
15653 //console.log("processing cell " + p + "," + q + " " + d_x + " " + d_y + " " + d_o);
15654 if ((typeof grid.cells[q] === 'undefined') || (typeof grid.cells[q][p] === 'undefined')) {
15655 //console.log("which is undefined");
15656 /* we can't move on, so we have to change direction to proceed further */
15657
15658 /* go back to previous cell */
15659 q -= d_y;
15660 p -= d_x;
15661 cell = grid.cells[q][p];
15662 cval = cell.cval_real;
15663
15664 /* check where we've left defined cells of the grid... */
15665 if (d_y === -1) { /* we came from top */
15666 if (d_o === 0) { /* exit left */
15667 if (cval & Node3) { /* lower left node is within range, so we move left */
15668 path.push([p, q]);
15669 d_x = -1;
15670 d_y = 0;
15671 d_o = 0;
15672 } else if (cval & Node2) { /* lower right node is within range, so we move right */
15673 path.push([p + 1, q]);
15674 d_x = 1;
15675 d_y = 0;
15676 d_o = 0;
15677 } else { /* close the path */
15678 path.push([p + cell.bottomright, q]);
15679 d_x = 0;
15680 d_y = 1;
15681 d_o = 1;
15682 closed = true;
15683 break;
15684 }
15685 } else if (cval & Node3) {
15686 path.push([p, q]);
15687 d_x = -1;
15688 d_y = 0;
15689 d_o = 0;
15690 } else if (cval & Node2) {
15691 path.push([p + cell.bottomright, q]);
15692 d_x = 0;
15693 d_y = 1;
15694 d_o = 1;
15695 closed = true;
15696 break;
15697 } else {
15698 path.push([p + cell.bottomleft, q]);
15699 d_x = 0;
15700 d_y = 1;
15701 d_o = 0;
15702 closed = true;
15703 break;
15704 }
15705 } else if (d_y === 1) { /* we came from bottom */
15706 //console.log("we came from bottom and hit a non-existing cell " + (p + d_x) + "," + (q + d_y) + "!");
15707 if (d_o === 0) { /* exit left */
15708 if (cval & Node1) { /* top right node is within range, so we move right */
15709 path.push([p + 1, q + 1]);
15710 d_x = 1;
15711 d_y = 0;
15712 d_o = 1;
15713 } else if (!(cval & Node0)) { /* found entry within same cell */
15714 path.push([p + cell.topright, q + 1]);
15715 d_x = 0;
15716 d_y = -1;
15717 d_o = 1;
15718 closed = true;
15719 //console.log("found entry from bottom at " + p + "," + q);
15720 break;
15721 } else {
15722 path.push([p + cell.topleft, q + 1]);
15723 d_x = 0;
15724 d_y = -1;
15725 d_o = 0;
15726 closed = true;
15727 break;
15728 }
15729 } else if (cval & Node1) {
15730 path.push([p + 1, q + 1]);
15731 d_x = 1;
15732 d_y = 0;
15733 d_o = 1;
15734 } else { /* move right */
15735 path.push([p + 1, q + 1]);
15736 d_x = 1;
15737 d_y = 0;
15738 d_o = 1;
15739 //console.log("wtf");
15740 //break;
15741 }
15742 } else if (d_x === -1) { /* we came from right */
15743 //console.log("we came from right and hit a non-existing cell at " + (p + d_x) + "," + (q + d_y) + "!");
15744 if (d_o === 0) {
15745 //console.log("continue at bottom");
15746 if (cval & Node0) {
15747 path.push([p, q + 1]);
15748 d_x = 0;
15749 d_y = 1;
15750 d_o = 0;
15751 //console.log("moving upwards to " + (p + d_x) + "," + (q + d_y) + "!");
15752 } else if (!(cval & Node3)) { /* there has to be an entry into the regular grid again! */
15753 //console.log("exiting top");
15754 path.push([p, q + cell.lefttop]);
15755 d_x = 1;
15756 d_y = 0;
15757 d_o = 1;
15758 closed = true;
15759 break;
15760 } else {
15761 //console.log("exiting bottom");
15762 path.push([p, q + cell.leftbottom]);
15763 d_x = 1;
15764 d_y = 0;
15765 d_o = 0;
15766 closed = true;
15767 break;
15768 }
15769 } else {
15770 //console.log("continue at top");
15771 if (cval & Node0) {
15772 path.push([p, q + 1]);
15773 d_x = 0;
15774 d_y = 1;
15775 d_o = 0;
15776 //console.log("moving upwards to " + (p + d_x) + "," + (q + d_y) + "!");
15777 } else { /* */
15778 console.log('MarchingSquaresJS-isoBands: wtf');
15779 break;
15780 }
15781 }
15782 } else if (d_x === 1) { /* we came from left */
15783 //console.log("we came from left and hit a non-existing cell " + (p + d_x) + "," + (q + d_y) + "!");
15784 if (d_o === 0) { /* exit bottom */
15785 if (cval & Node2) {
15786 path.push([p + 1, q]);
15787 d_x = 0;
15788 d_y = -1;
15789 d_o = 1;
15790 } else {
15791 path.push([p + 1, q + cell.rightbottom]);
15792 d_x = -1;
15793 d_y = 0;
15794 d_o = 0;
15795 closed = true;
15796 break;
15797 }
15798 } else { /* exit top */
15799 if (cval & Node2) {
15800 path.push([p + 1, q]);
15801 d_x = 0;
15802 d_y = -1;
15803 d_o = 1;
15804 } else if (!(cval & Node1)) {
15805 path.push([p + 1, q + cell.rightbottom]);
15806 d_x = -1;
15807 d_y = 0;
15808 d_o = 0;
15809 closed = true;
15810 break;
15811 } else {
15812 path.push([p + 1, q + cell.righttop]);
15813 d_x = -1;
15814 d_y = 0;
15815 d_o = 1;
15816 break;
15817 }
15818 }
15819 } else { /* we came from the same cell */
15820 console.log('MarchingSquaresJS-isoBands: we came from nowhere!');
15821 break;
15822 }
15823
15824 } else { /* try to find an entry into the regular grid again! */
15825 cell = grid.cells[q][p];
15826 cval = cell.cval_real;
15827 //console.log("which is defined");
15828
15829 if (d_x === -1) {
15830 if (d_o === 0) {
15831 /* try to go downwards */
15832 if ((typeof grid.cells[q - 1] !== 'undefined') && (typeof grid.cells[q - 1][p] !== 'undefined')) {
15833 d_x = 0;
15834 d_y = -1;
15835 d_o = 1;
15836 } else if (cval & Node3) { /* proceed searching in x-direction */
15837 //console.log("proceeding in x-direction!");
15838 path.push([p, q]);
15839 } else { /* we must have found an entry into the regular grid */
15840 path.push([p + cell.bottomright, q]);
15841 d_x = 0;
15842 d_y = 1;
15843 d_o = 1;
15844 closed = true;
15845 //console.log("found entry from bottom at " + p + "," + q);
15846 break;
15847 }
15848 } else if (cval & Node0) { /* proceed searchin in x-direction */
15849 console.log('MarchingSquaresJS-isoBands: proceeding in x-direction!');
15850 } else { /* we must have found an entry into the regular grid */
15851 console.log('MarchingSquaresJS-isoBands: found entry from top at ' + p + ',' + q);
15852 break;
15853 }
15854 } else if (d_x === 1) {
15855 if (d_o === 0) {
15856 console.log('MarchingSquaresJS-isoBands: wtf');
15857 break;
15858 } else {
15859 /* try to go upwards */
15860 if ((typeof grid.cells[q + 1] !== 'undefined') && (typeof grid.cells[q + 1][p] !== 'undefined')) {
15861 d_x = 0;
15862 d_y = 1;
15863 d_o = 0;
15864 } else if (cval & Node1) {
15865 path.push([p + 1, q + 1]);
15866 d_x = 1;
15867 d_y = 0;
15868 d_o = 1;
15869 } else { /* found an entry point into regular grid! */
15870 path.push([p + cell.topleft, q + 1]);
15871 d_x = 0;
15872 d_y = -1;
15873 d_o = 0;
15874 closed = true;
15875 //console.log("found entry from bottom at " + p + "," + q);
15876 break;
15877 }
15878 }
15879 } else if (d_y === -1) {
15880 if (d_o === 1) {
15881 /* try to go right */
15882 if (typeof grid.cells[q][p + 1] !== 'undefined') {
15883 d_x = 1;
15884 d_y = 0;
15885 d_o = 1;
15886 } else if (cval & Node2) {
15887 path.push([p + 1, q]);
15888 d_x = 0;
15889 d_y = -1;
15890 d_o = 1;
15891 } else { /* found entry into regular grid! */
15892 path.push([p + 1, q + cell.righttop]);
15893 d_x = -1;
15894 d_y = 0;
15895 d_o = 1;
15896 closed = true;
15897 //console.log("found entry from top at " + p + "," + q);
15898 break;
15899 }
15900 } else {
15901 console.log('MarchingSquaresJS-isoBands: wtf');
15902 break;
15903 }
15904 } else if (d_y === 1) {
15905 if (d_o === 0) {
15906 //console.log("we came from bottom left and proceed to the left");
15907 /* try to go left */
15908 if (typeof grid.cells[q][p - 1] !== 'undefined') {
15909 d_x = -1;
15910 d_y = 0;
15911 d_o = 0;
15912 } else if (cval & Node0) {
15913 path.push([p, q + 1]);
15914 d_x = 0;
15915 d_y = 1;
15916 d_o = 0;
15917 } else { /* found an entry point into regular grid! */
15918 path.push([p, q + cell.leftbottom]);
15919 d_x = 1;
15920 d_y = 0;
15921 d_o = 0;
15922 closed = true;
15923 //console.log("found entry from bottom at " + p + "," + q);
15924 break;
15925 }
15926 } else {
15927 //console.log("we came from bottom right and proceed to the right");
15928 console.log('MarchingSquaresJS-isoBands: wtf');
15929 break;
15930 }
15931 } else {
15932 console.log('MarchingSquaresJS-isoBands: where did we came from???');
15933 break;
15934 }
15935
15936 }
15937
15938 p += d_x;
15939 q += d_y;
15940 //console.log("going on to " + p + "," + q + " via " + d_x + " " + d_y + " " + d_o);
15941
15942 if ((p === i) && (q === j)) { /* bail out, once we've closed a circle path */
15943 break;
15944 }
15945
15946 }
15947
15948 //console.log("exit with " + p + "," + q + " " + d_x + " " + d_y + " " + d_o);
15949 return { path: path, i: p, j: q, x: d_x, y: d_y, o: d_o };
15950}
15951
15952function deleteEdge(cell, edgeIdx) {
15953 delete cell.edges[edgeIdx];
15954 for (var k = edgeIdx + 1; k < cell.edges.length; k++) {
15955 cell.edges[k - 1] = cell.edges[k];
15956 }
15957 cell.edges.pop();
15958}
15959
15960function getStartXY(cell) {
15961
15962 if (cell.edges.length > 0) {
15963 var e = cell.edges[cell.edges.length - 1];
15964 //console.log("starting with edge " + e);
15965 var cval = cell.cval_real;
15966 switch (e) {
15967 case 0: if (cval & Node1) { /* node 1 within range */
15968 return {p: [1, cell.righttop], x: -1, y: 0, o: 1};
15969 } else { /* node 1 below or above threshold */
15970 return {p: [cell.topleft, 1], x: 0, y: -1, o: 0};
15971 }
15972 case 1: if (cval & Node2) {
15973 return {p: [cell.topleft, 1], x: 0, y: -1, o: 0};
15974 } else {
15975 return {p: [1, cell.rightbottom], x: -1, y: 0, o: 0};
15976 }
15977 case 2: if (cval & Node2) {
15978 return {p: [cell.bottomright, 0], x: 0, y: 1, o: 1};
15979 } else {
15980 return {p: [cell.topleft, 1], x: 0, y: -1, o: 0};
15981 }
15982 case 3: if (cval & Node3) {
15983 return {p: [cell.topleft, 1], x: 0, y: -1, o: 0};
15984 } else {
15985 return {p: [cell.bottomleft, 0], x: 0, y: 1, o: 0};
15986 }
15987 case 4: if (cval & Node1) {
15988 return {p: [1, cell.righttop], x: -1, y: 0, o: 1};
15989 } else {
15990 return {p: [cell.topright, 1], x: 0, y: -1, o: 1};
15991 }
15992 case 5: if (cval & Node2) {
15993 return {p: [cell.topright, 1], x: 0, y: -1, o: 1};
15994 } else {
15995 return {p: [1, cell.rightbottom], x: -1, y: 0, o: 0};
15996 }
15997 case 6: if (cval & Node2) {
15998 return {p: [cell.bottomright, 0], x: 0, y: 1, o: 1};
15999 } else {
16000 return {p: [cell.topright, 1], x: 0, y: -1, o: 1};
16001 }
16002 case 7: if (cval & Node3) {
16003 return {p: [cell.topright, 1], x: 0, y: -1, o: 1};
16004 } else {
16005 return {p: [cell.bottomleft, 0], x: 0, y: 1, o: 0};
16006 }
16007 case 8: if (cval & Node2) {
16008 return {p: [cell.bottomright, 0], x: 0, y: 1, o: 1};
16009 } else {
16010 return {p: [1, cell.righttop], x: -1, y: 0, o: 1};
16011 }
16012 case 9: if (cval & Node3) {
16013 return {p: [1, cell.righttop], x: -1, y: 0, o: 1};
16014 } else {
16015 return {p: [cell.bottomleft, 0], x: 0, y: 1, o: 0};
16016 }
16017 case 10: if (cval & Node3) {
16018 return {p: [0, cell.leftbottom], x: 1, y: 0, o: 0};
16019 } else {
16020 return {p: [1, cell.righttop], x: -1, y: 0, o: 1};
16021 }
16022 case 11: if (cval & Node0) {
16023 return {p: [1, cell.righttop], x: -1, y: 0, o: 1};
16024 } else {
16025 return {p: [0, cell.lefttop], x: 1, y: 0, o: 1};
16026 }
16027 case 12: if (cval & Node2) {
16028 return {p: [cell.bottomright, 0], x: 0, y: 1, o: 1};
16029 } else {
16030 return {p: [1, cell.rightbottom], x: -1, y: 0, o: 0};
16031 }
16032 case 13: if (cval & Node3) {
16033 return {p: [1, cell.rightbottom], x: -1, y: 0, o: 0};
16034 } else {
16035 return {p: [cell.bottomleft, 0], x: 0, y: 1, o: 0};
16036 }
16037 case 14: if (cval & Node3) {
16038 return {p: [0, cell.leftbottom], x: 1, y: 0, o: 0};
16039 } else {
16040 return {p: [1, cell.rightbottom], x: -1, y: 0, o: 0};
16041 }
16042 case 15: if (cval & Node0) {
16043 return {p: [1, cell.rightbottom], x: -1, y: 0, o: 0};
16044 } else {
16045 return {p: [0, cell.lefttop], x: 1, y: 0, o: 1};
16046 }
16047 case 16: if (cval & Node2) {
16048 return {p: [cell.bottomright, 0], x: 0, y: 1, o: 1};
16049 } else {
16050 return {p: [0, cell.leftbottom], x: 1, y: 0, o: 0};
16051 }
16052 case 17: if (cval & Node0) {
16053 return {p: [cell.bottomright, 0], x: 0, y: 1, o: 1};
16054 } else {
16055 return {p: [0, cell.lefttop], x: 1, y: 0, o: 1};
16056 }
16057 case 18: if (cval & Node3) {
16058 return {p: [0, cell.leftbottom], x: 1, y: 0, o: 0};
16059 } else {
16060 return {p: [cell.bottomleft, 0], x: 0, y: 1, o: 0};
16061 }
16062 case 19: if (cval & Node0) {
16063 return {p: [cell.bottomleft, 0], x: 0, y: 1, o: 0};
16064 } else {
16065 return {p: [0, cell.lefttop], x: 1, y: 0, o: 1};
16066 }
16067 case 20: if (cval & Node0) {
16068 return {p: [cell.topleft, 1], x: 0, y: -1, o: 0};
16069 } else {
16070 return {p: [0, cell.leftbottom], x: 1, y: 0, o: 0};
16071 }
16072 case 21: if (cval & Node1) {
16073 return {p: [0, cell.leftbottom], x: 1, y: 0, o: 0};
16074 } else {
16075 return {p: [cell.topright, 1], x: 0, y: -1, o: 1};
16076 }
16077 case 22: if (cval & Node0) {
16078 return {p: [cell.topleft, 1], x: 0, y: -1, o: 0};
16079 } else {
16080 return {p: [0, cell.lefttop], x: 1, y: 0, o: 1};
16081 }
16082 case 23: if (cval & Node1) {
16083 return {p: [0, cell.lefttop], x: 1, y: 0, o: 1};
16084 } else {
16085 return {p: [cell.topright, 1], x: 0, y: -1, o: 1};
16086 }
16087 default: console.log('MarchingSquaresJS-isoBands: edge index out of range!');
16088 console.log(cell);
16089 break;
16090 }
16091 }
16092
16093 return null;
16094}
16095
16096function getExitXY(cell, x, y, o) {
16097
16098 var e, id_x, d_x, d_y, cval = cell.cval;
16099 var d_o;
16100
16101 switch (x) {
16102 case -1: switch (o) {
16103 case 0: e = isoBandEdgeRB[cval];
16104 d_x = isoBandNextXRB[cval];
16105 d_y = isoBandNextYRB[cval];
16106 d_o = isoBandNextORB[cval];
16107 break;
16108 default: e = isoBandEdgeRT[cval];
16109 d_x = isoBandNextXRT[cval];
16110 d_y = isoBandNextYRT[cval];
16111 d_o = isoBandNextORT[cval];
16112 break;
16113 }
16114 break;
16115 case 1: switch (o) {
16116 case 0: e = isoBandEdgeLB[cval];
16117 d_x = isoBandNextXLB[cval];
16118 d_y = isoBandNextYLB[cval];
16119 d_o = isoBandNextOLB[cval];
16120 break;
16121 default: e = isoBandEdgeLT[cval];
16122 d_x = isoBandNextXLT[cval];
16123 d_y = isoBandNextYLT[cval];
16124 d_o = isoBandNextOLT[cval];
16125 break;
16126 }
16127 break;
16128 default: switch (y) {
16129 case -1: switch (o) {
16130 case 0: e = isoBandEdgeTL[cval];
16131 d_x = isoBandNextXTL[cval];
16132 d_y = isoBandNextYTL[cval];
16133 d_o = isoBandNextOTL[cval];
16134 break;
16135 default: e = isoBandEdgeTR[cval];
16136 d_x = isoBandNextXTR[cval];
16137 d_y = isoBandNextYTR[cval];
16138 d_o = isoBandNextOTR[cval];
16139 break;
16140 }
16141 break;
16142 case 1: switch (o) {
16143 case 0: e = isoBandEdgeBL[cval];
16144 d_x = isoBandNextXBL[cval];
16145 d_y = isoBandNextYBL[cval];
16146 d_o = isoBandNextOBL[cval];
16147 break;
16148 default: e = isoBandEdgeBR[cval];
16149 d_x = isoBandNextXBR[cval];
16150 d_y = isoBandNextYBR[cval];
16151 d_o = isoBandNextOBR[cval];
16152 break;
16153 }
16154 break;
16155 default: break;
16156 }
16157 break;
16158 }
16159
16160 id_x = cell.edges.indexOf(e);
16161 if (typeof cell.edges[id_x] !== 'undefined') {
16162 deleteEdge(cell, id_x);
16163 } else {
16164 //console.log("wrong edges...");
16165 //console.log(x + " " + y + " " + o);
16166 //console.log(cell);
16167 return null;
16168 }
16169
16170 cval = cell.cval_real;
16171
16172 switch (e) {
16173 case 0: if (cval & Node1) { /* node 1 within range */
16174 x = cell.topleft;
16175 y = 1;
16176 } else { /* node 1 below or above threshold */
16177 x = 1;
16178 y = cell.righttop;
16179 }
16180 break;
16181 case 1: if (cval & Node2) {
16182 x = 1;
16183 y = cell.rightbottom;
16184 } else {
16185 x = cell.topleft;
16186 y = 1;
16187 }
16188 break;
16189 case 2: if (cval & Node2) {
16190 x = cell.topleft;
16191 y = 1;
16192 } else {
16193 x = cell.bottomright;
16194 y = 0;
16195 }
16196 break;
16197 case 3: if (cval & Node3) {
16198 x = cell.bottomleft;
16199 y = 0;
16200 } else {
16201 x = cell.topleft;
16202 y = 1;
16203 }
16204 break;
16205 case 4: if (cval & Node1) {
16206 x = cell.topright;
16207 y = 1;
16208 } else {
16209 x = 1;
16210 y = cell.righttop;
16211 }
16212 break;
16213 case 5: if (cval & Node2) {
16214 x = 1;
16215 y = cell.rightbottom;
16216 } else {
16217 x = cell.topright;
16218 y = 1;
16219 }
16220 break;
16221 case 6: if (cval & Node2) {
16222 x = cell.topright;
16223 y = 1;
16224 } else {
16225 x = cell.bottomright;
16226 y = 0;
16227 }
16228 break;
16229 case 7: if (cval & Node3) {
16230 x = cell.bottomleft;
16231 y = 0;
16232 } else {
16233 x = cell.topright;
16234 y = 1;
16235 }
16236 break;
16237 case 8: if (cval & Node2) {
16238 x = 1;
16239 y = cell.righttop;
16240 } else {
16241 x = cell.bottomright;
16242 y = 0;
16243 }
16244 break;
16245 case 9: if (cval & Node3) {
16246 x = cell.bottomleft;
16247 y = 0;
16248 } else {
16249 x = 1;
16250 y = cell.righttop;
16251 }
16252 break;
16253 case 10: if (cval & Node3) {
16254 x = 1;
16255 y = cell.righttop;
16256 } else {
16257 x = 0;
16258 y = cell.leftbottom;
16259 }
16260 break;
16261 case 11: if (cval & Node0) {
16262 x = 0;
16263 y = cell.lefttop;
16264 } else {
16265 x = 1;
16266 y = cell.righttop;
16267 }
16268 break;
16269 case 12: if (cval & Node2) {
16270 x = 1;
16271 y = cell.rightbottom;
16272 } else {
16273 x = cell.bottomright;
16274 y = 0;
16275 }
16276 break;
16277 case 13: if (cval & Node3) {
16278 x = cell.bottomleft;
16279 y = 0;
16280 } else {
16281 x = 1;
16282 y = cell.rightbottom;
16283 }
16284 break;
16285 case 14: if (cval & Node3) {
16286 x = 1;
16287 y = cell.rightbottom;
16288 } else {
16289 x = 0;
16290 y = cell.leftbottom;
16291 }
16292 break;
16293 case 15: if (cval & Node0) {
16294 x = 0;
16295 y = cell.lefttop;
16296 } else {
16297 x = 1;
16298 y = cell.rightbottom;
16299 }
16300 break;
16301 case 16: if (cval & Node2) {
16302 x = 0;
16303 y = cell.leftbottom;
16304 } else {
16305 x = cell.bottomright;
16306 y = 0;
16307 }
16308 break;
16309 case 17: if (cval & Node0) {
16310 x = 0;
16311 y = cell.lefttop;
16312 } else {
16313 x = cell.bottomright;
16314 y = 0;
16315 }
16316 break;
16317 case 18: if (cval & Node3) {
16318 x = cell.bottomleft;
16319 y = 0;
16320 } else {
16321 x = 0;
16322 y = cell.leftbottom;
16323 }
16324 break;
16325 case 19: if (cval & Node0) {
16326 x = 0;
16327 y = cell.lefttop;
16328 } else {
16329 x = cell.bottomleft;
16330 y = 0;
16331 }
16332 break;
16333 case 20: if (cval & Node0) {
16334 x = 0;
16335 y = cell.leftbottom;
16336 } else {
16337 x = cell.topleft;
16338 y = 1;
16339 }
16340 break;
16341 case 21: if (cval & Node1) {
16342 x = cell.topright;
16343 y = 1;
16344 } else {
16345 x = 0;
16346 y = cell.leftbottom;
16347 }
16348 break;
16349 case 22: if (cval & Node0) {
16350 x = 0;
16351 y = cell.lefttop;
16352 } else {
16353 x = cell.topleft;
16354 y = 1;
16355 }
16356 break;
16357 case 23: if (cval & Node1) {
16358 x = cell.topright;
16359 y = 1;
16360 } else {
16361 x = 0;
16362 y = cell.lefttop;
16363 }
16364 break;
16365 default: console.log('MarchingSquaresJS-isoBands: edge index out of range!');
16366 console.log(cell);
16367 return null;
16368 }
16369
16370 if ((typeof x === 'undefined') || (typeof y === 'undefined') ||
16371 (typeof d_x === 'undefined') || (typeof d_y === 'undefined') ||
16372 (typeof d_o === 'undefined')) {
16373 console.log('MarchingSquaresJS-isoBands: undefined value!');
16374 console.log(cell);
16375 console.log(x + ' ' + y + ' ' + d_x + ' ' + d_y + ' ' + d_o);
16376 }
16377 return {p: [x, y], x: d_x, y: d_y, o: d_o};
16378}
16379
16380function BandGrid2Areas(grid) {
16381 var areas = [];
16382 var area_idx = 0;
16383
16384 grid.cells.forEach(function (g, j) {
16385 g.forEach(function (gg, i) {
16386 if (typeof gg !== 'undefined') {
16387 var a = polygon_table[gg.cval](gg);
16388 if ((typeof a === 'object') && isArray(a)) {
16389 if ((typeof a[0] === 'object') && isArray(a[0])) {
16390 if ((typeof a[0][0] === 'object') && isArray(a[0][0])) {
16391 a.forEach(function (aa) {
16392 aa.forEach(function (aaa) {
16393 aaa[0] += i;
16394 aaa[1] += j;
16395 });
16396 areas[area_idx++] = aa;
16397 });
16398 } else {
16399 a.forEach(function (aa) {
16400 aa[0] += i;
16401 aa[1] += j;
16402 });
16403 areas[area_idx++] = a;
16404 }
16405 } else {
16406 console.log('MarchingSquaresJS-isoBands: bandcell polygon with malformed coordinates');
16407 }
16408 } else {
16409 console.log('MarchingSquaresJS-isoBands: bandcell polygon with null coordinates');
16410 }
16411 }
16412 });
16413 });
16414
16415 return areas;
16416}
16417
16418/**
16419 * Takes a grid {@link FeatureCollection} of {@link Point} features with z-values and an array of
16420 * value breaks and generates filled contour isobands.
16421 *
16422 * @name isobands
16423 * @param {FeatureCollection<Point>} pointGrid input points
16424 * @param {Array<number>} breaks where to draw contours
16425 * @param {Object} [options={}] options on output
16426 * @param {string} [options.zProperty='elevation'] the property name in `points` from which z-values will be pulled
16427 * @param {Object} [options.commonProperties={}] GeoJSON properties passed to ALL isobands
16428 * @param {Array<Object>} [options.breaksProperties=[]] GeoJSON properties passed, in order, to the correspondent isoband (order defined by breaks)
16429 * @returns {FeatureCollection<MultiPolygon>} a FeatureCollection of {@link MultiPolygon} features representing isobands
16430 */
16431function isobands(pointGrid, breaks, options) {
16432 // Optional parameters
16433 options = options || {};
16434 if (!isObject(options)) throw new Error('options is invalid');
16435 var zProperty = options.zProperty || 'elevation';
16436 var commonProperties = options.commonProperties || {};
16437 var breaksProperties = options.breaksProperties || [];
16438
16439 // Validation
16440 collectionOf(pointGrid, 'Point', 'Input must contain Points');
16441 if (!breaks) throw new Error('breaks is required');
16442 if (!Array.isArray(breaks)) throw new Error('breaks is not an Array');
16443 if (!isObject(commonProperties)) throw new Error('commonProperties is not an Object');
16444 if (!Array.isArray(breaksProperties)) throw new Error('breaksProperties is not an Array');
16445
16446 // Isoband methods
16447 var matrix = gridToMatrix$1(pointGrid, {zProperty: zProperty, flip: true});
16448 var contours = createContourLines(matrix, breaks, zProperty);
16449 contours = rescaleContours(contours, matrix, pointGrid);
16450
16451 var multipolygons = contours.map(function (contour, index) {
16452 if (breaksProperties[index] && !isObject(breaksProperties[index])) {
16453 throw new Error('Each mappedProperty is required to be an Object');
16454 }
16455 // collect all properties
16456 var contourProperties = Object.assign(
16457 {},
16458 commonProperties,
16459 breaksProperties[index]
16460 );
16461 contourProperties[zProperty] = contour[zProperty];
16462 var multiP = multiPolygon(contour.groupedRings, contourProperties);
16463 return multiP;
16464 });
16465
16466 return featureCollection(multipolygons);
16467}
16468
16469/**
16470 * Creates the contours lines (featuresCollection of polygon features) from the 2D data grid
16471 *
16472 * Marchingsquares process the grid data as a 3D representation of a function on a 2D plane, therefore it
16473 * assumes the points (x-y coordinates) are one 'unit' distance. The result of the IsoBands function needs to be
16474 * rescaled, with turfjs, to the original area and proportions on the map
16475 *
16476 * @private
16477 * @param {Array<Array<number>>} matrix Grid Data
16478 * @param {Array<number>} breaks Breaks
16479 * @param {string} [property='elevation'] Property
16480 * @returns {Array<any>} contours
16481 */
16482function createContourLines(matrix, breaks, property) {
16483
16484 var contours = [];
16485 for (var i = 1; i < breaks.length; i++) {
16486 var lowerBand = +breaks[i - 1]; // make sure the breaks value is a number
16487 var upperBand = +breaks[i];
16488
16489 var isobandsCoords = isoBands(matrix, lowerBand, upperBand - lowerBand);
16490 // as per GeoJson rules for creating a Polygon, make sure the first element
16491 // in the array of LinearRings represents the exterior ring (i.e. biggest area),
16492 // and any subsequent elements represent interior rings (i.e. smaller area);
16493 // this avoids rendering issues of the MultiPolygons on the map
16494 var nestedRings = orderByArea(isobandsCoords);
16495 var groupedRings = groupNestedRings(nestedRings);
16496 var obj = {};
16497 obj['groupedRings'] = groupedRings;
16498 obj[property] = lowerBand + '-' + upperBand;
16499 contours.push(obj);
16500 }
16501 return contours;
16502}
16503
16504/**
16505 * Transform isobands of 2D grid to polygons for the map
16506 *
16507 * @private
16508 * @param {Array<any>} contours Contours
16509 * @param {Array<Array<number>>} matrix Grid Data
16510 * @param {Object} points Points by Latitude
16511 * @returns {Array<any>} contours
16512 */
16513function rescaleContours(contours, matrix, points$$1) {
16514
16515 // get dimensions (on the map) of the original grid
16516 var gridBbox = bbox(points$$1); // [ minX, minY, maxX, maxY ]
16517 var originalWidth = gridBbox[2] - gridBbox[0];
16518 var originalHeigth = gridBbox[3] - gridBbox[1];
16519
16520 // get origin, which is the first point of the last row on the rectangular data on the map
16521 var x0 = gridBbox[0];
16522 var y0 = gridBbox[1];
16523 // get number of cells per side
16524 var matrixWidth = matrix[0].length - 1;
16525 var matrixHeight = matrix.length - 1;
16526 // calculate the scaling factor between matrix and rectangular grid on the map
16527 var scaleX = originalWidth / matrixWidth;
16528 var scaleY = originalHeigth / matrixHeight;
16529
16530 var resize = function (point$$1) {
16531 point$$1[0] = point$$1[0] * scaleX + x0;
16532 point$$1[1] = point$$1[1] * scaleY + y0;
16533 };
16534
16535 // resize and shift each point/line of the isobands
16536 contours.forEach(function (contour) {
16537 contour.groupedRings.forEach(function (lineRingSet) {
16538 lineRingSet.forEach(function (lineRing) {
16539 lineRing.forEach(resize);
16540 });
16541 });
16542 });
16543 return contours;
16544}
16545
16546
16547/* utility functions */
16548
16549
16550/**
16551 * Returns an array of coordinates (of LinearRings) in descending order by area
16552 *
16553 * @private
16554 * @param {Array<LineString>} ringsCoords array of closed LineString
16555 * @returns {Array} array of the input LineString ordered by area
16556 */
16557function orderByArea(ringsCoords) {
16558 var ringsWithArea = [];
16559 var areas = [];
16560 ringsCoords.forEach(function (coords) {
16561 // var poly = polygon([points]);
16562 var ringArea = area$1(polygon([coords]));
16563 // create an array of areas value
16564 areas.push(ringArea);
16565 // associate each lineRing with its area
16566 ringsWithArea.push({ring: coords, area: ringArea});
16567 });
16568 areas.sort(function (a, b) { // bigger --> smaller
16569 return b - a;
16570 });
16571 // create a new array of linearRings coordinates ordered by their area
16572 var orderedByArea = [];
16573 areas.forEach(function (area$$1) {
16574 for (var lr = 0; lr < ringsWithArea.length; lr++) {
16575 if (ringsWithArea[lr].area === area$$1) {
16576 orderedByArea.push(ringsWithArea[lr].ring);
16577 ringsWithArea.splice(lr, 1);
16578 break;
16579 }
16580 }
16581 });
16582 return orderedByArea;
16583}
16584
16585/**
16586 * Returns an array of arrays of coordinates, each representing
16587 * a set of (coordinates of) nested LinearRings,
16588 * i.e. the first ring contains all the others
16589 *
16590 * @private
16591 * @param {Array} orderedLinearRings array of coordinates (of LinearRings) in descending order by area
16592 * @returns {Array<Array>} Array of coordinates of nested LinearRings
16593 */
16594function groupNestedRings(orderedLinearRings) {
16595 // create a list of the (coordinates of) LinearRings
16596 var lrList = orderedLinearRings.map(function (lr) {
16597 return {lrCoordinates: lr, grouped: false};
16598 });
16599 var groupedLinearRingsCoords = [];
16600 while (!allGrouped(lrList)) {
16601 for (var i = 0; i < lrList.length; i++) {
16602 if (!lrList[i].grouped) {
16603 // create new group starting with the larger not already grouped ring
16604 var group = [];
16605 group.push(lrList[i].lrCoordinates);
16606 lrList[i].grouped = true;
16607 var outerMostPoly = polygon([lrList[i].lrCoordinates]);
16608 // group all the rings contained by the outermost ring
16609 for (var j = i + 1; j < lrList.length; j++) {
16610 if (!lrList[j].grouped) {
16611 var lrPoly = polygon([lrList[j].lrCoordinates]);
16612 if (isInside(lrPoly, outerMostPoly)) {
16613 group.push(lrList[j].lrCoordinates);
16614 lrList[j].grouped = true;
16615 }
16616 }
16617 }
16618 // insert the new group
16619 groupedLinearRingsCoords.push(group);
16620 }
16621 }
16622 }
16623 return groupedLinearRingsCoords;
16624}
16625
16626/**
16627 * @private
16628 * @param {Polygon} testPolygon polygon of interest
16629 * @param {Polygon} targetPolygon polygon you want to compare with
16630 * @returns {boolean} true if test-Polygon is inside target-Polygon
16631 */
16632function isInside(testPolygon, targetPolygon) {
16633 var points$$1 = explode(testPolygon);
16634 for (var i = 0; i < points$$1.features.length; i++) {
16635 if (!booleanPointInPolygon(points$$1.features[i], targetPolygon)) {
16636 return false;
16637 }
16638 }
16639 return true;
16640}
16641
16642/**
16643 * @private
16644 * @param {Array<Object>} list list of objects which might contain the 'group' attribute
16645 * @returns {boolean} true if all the objects in the list are marked as grouped
16646 */
16647function allGrouped(list) {
16648 for (var i = 0; i < list.length; i++) {
16649 if (list[i].grouped === false) {
16650 return false;
16651 }
16652 }
16653 return true;
16654}
16655
16656/**
16657 * Rotates any geojson Feature or Geometry of a specified angle, around its `centroid` or a given `pivot` point;
16658 * all rotations follow the right-hand rule: https://en.wikipedia.org/wiki/Right-hand_rule
16659 *
16660 * @name transformRotate
16661 * @param {GeoJSON} geojson object to be rotated
16662 * @param {number} angle of rotation (along the vertical axis), from North in decimal degrees, negative clockwise
16663 * @param {Object} [options={}] Optional parameters
16664 * @param {Coord} [options.pivot='centroid'] point around which the rotation will be performed
16665 * @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated (significant performance increase if true)
16666 * @returns {GeoJSON} the rotated GeoJSON feature
16667 * @example
16668 * var poly = turf.polygon([[[0,29],[3.5,29],[2.5,32],[0,29]]]);
16669 * var options = {pivot: [0, 25]};
16670 * var rotatedPoly = turf.transformRotate(poly, 10, options);
16671 *
16672 * //addToMap
16673 * var addToMap = [poly, rotatedPoly];
16674 * rotatedPoly.properties = {stroke: '#F00', 'stroke-width': 4};
16675 */
16676function transformRotate(geojson, angle, options) {
16677 // Optional parameters
16678 options = options || {};
16679 if (!isObject(options)) throw new Error('options is invalid');
16680 var pivot = options.pivot;
16681 var mutate = options.mutate;
16682
16683 // Input validation
16684 if (!geojson) throw new Error('geojson is required');
16685 if (angle === undefined || angle === null || isNaN(angle)) throw new Error('angle is required');
16686
16687 // Shortcut no-rotation
16688 if (angle === 0) return geojson;
16689
16690 // Use centroid of GeoJSON if pivot is not provided
16691 if (!pivot) pivot = centroid(geojson);
16692
16693 // Clone geojson to avoid side effects
16694 if (mutate === false || mutate === undefined) geojson = clone(geojson);
16695
16696 // Rotate each coordinate
16697 coordEach(geojson, function (pointCoords) {
16698 var initialAngle = rhumbBearing(pivot, pointCoords);
16699 var finalAngle = initialAngle + angle;
16700 var distance = rhumbDistance(pivot, pointCoords);
16701 var newCoords = getCoords(rhumbDestination(pivot, distance, finalAngle));
16702 pointCoords[0] = newCoords[0];
16703 pointCoords[1] = newCoords[1];
16704 });
16705 return geojson;
16706}
16707
16708/**
16709 * Scale a GeoJSON from a given point by a factor of scaling (ex: factor=2 would make the GeoJSON 200% larger).
16710 * If a FeatureCollection is provided, the origin point will be calculated based on each individual Feature.
16711 *
16712 * @name transformScale
16713 * @param {GeoJSON} geojson GeoJSON to be scaled
16714 * @param {number} factor of scaling, positive or negative values greater than 0
16715 * @param {Object} [options={}] Optional parameters
16716 * @param {string|Coord} [options.origin='centroid'] Point from which the scaling will occur (string options: sw/se/nw/ne/center/centroid)
16717 * @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated (significant performance increase if true)
16718 * @returns {GeoJSON} scaled GeoJSON
16719 * @example
16720 * var poly = turf.polygon([[[0,29],[3.5,29],[2.5,32],[0,29]]]);
16721 * var scaledPoly = turf.transformScale(poly, 3);
16722 *
16723 * //addToMap
16724 * var addToMap = [poly, scaledPoly];
16725 * scaledPoly.properties = {stroke: '#F00', 'stroke-width': 4};
16726 */
16727function transformScale(geojson, factor, options) {
16728 // Optional parameters
16729 options = options || {};
16730 if (!isObject(options)) throw new Error('options is invalid');
16731 var origin = options.origin;
16732 var mutate = options.mutate;
16733
16734 // Input validation
16735 if (!geojson) throw new Error('geojson required');
16736 if (typeof factor !== 'number' || factor === 0) throw new Error('invalid factor');
16737 var originIsPoint = Array.isArray(origin) || typeof origin === 'object';
16738
16739 // Clone geojson to avoid side effects
16740 if (mutate !== true) geojson = clone(geojson);
16741
16742 // Scale each Feature separately
16743 if (geojson.type === 'FeatureCollection' && !originIsPoint) {
16744 featureEach(geojson, function (feature$$1, index) {
16745 geojson.features[index] = scale(feature$$1, factor, origin);
16746 });
16747 return geojson;
16748 }
16749 // Scale Feature/Geometry
16750 return scale(geojson, factor, origin);
16751}
16752
16753/**
16754 * Scale Feature/Geometry
16755 *
16756 * @private
16757 * @param {Feature|Geometry} feature GeoJSON Feature/Geometry
16758 * @param {number} factor of scaling, positive or negative values greater than 0
16759 * @param {string|Coord} [origin="centroid"] Point from which the scaling will occur (string options: sw/se/nw/ne/center/centroid)
16760 * @returns {Feature|Geometry} scaled GeoJSON Feature/Geometry
16761 */
16762function scale(feature$$1, factor, origin) {
16763 // Default params
16764 var isPoint = getType(feature$$1) === 'Point';
16765 origin = defineOrigin(feature$$1, origin);
16766
16767 // Shortcut no-scaling
16768 if (factor === 1 || isPoint) return feature$$1;
16769
16770 // Scale each coordinate
16771 coordEach(feature$$1, function (coord) {
16772 var originalDistance = rhumbDistance(origin, coord);
16773 var bearing = rhumbBearing(origin, coord);
16774 var newDistance = originalDistance * factor;
16775 var newCoord = getCoords(rhumbDestination(origin, newDistance, bearing));
16776 coord[0] = newCoord[0];
16777 coord[1] = newCoord[1];
16778 if (coord.length === 3) coord[2] *= factor;
16779 });
16780
16781 return feature$$1;
16782}
16783
16784/**
16785 * Define Origin
16786 *
16787 * @private
16788 * @param {GeoJSON} geojson GeoJSON
16789 * @param {string|Coord} origin sw/se/nw/ne/center/centroid
16790 * @returns {Feature<Point>} Point origin
16791 */
16792function defineOrigin(geojson, origin) {
16793 // Default params
16794 if (origin === undefined || origin === null) origin = 'centroid';
16795
16796 // Input Coord
16797 if (Array.isArray(origin) || typeof origin === 'object') return getCoord(origin);
16798
16799 // Define BBox
16800 var bbox$$1 = (geojson.bbox) ? geojson.bbox : bbox(geojson);
16801 var west = bbox$$1[0];
16802 var south = bbox$$1[1];
16803 var east = bbox$$1[2];
16804 var north = bbox$$1[3];
16805
16806 switch (origin) {
16807 case 'sw':
16808 case 'southwest':
16809 case 'westsouth':
16810 case 'bottomleft':
16811 return point([west, south]);
16812 case 'se':
16813 case 'southeast':
16814 case 'eastsouth':
16815 case 'bottomright':
16816 return point([east, south]);
16817 case 'nw':
16818 case 'northwest':
16819 case 'westnorth':
16820 case 'topleft':
16821 return point([west, north]);
16822 case 'ne':
16823 case 'northeast':
16824 case 'eastnorth':
16825 case 'topright':
16826 return point([east, north]);
16827 case 'center':
16828 return center(geojson);
16829 case undefined:
16830 case null:
16831 case 'centroid':
16832 return centroid(geojson);
16833 default:
16834 throw new Error('invalid origin');
16835 }
16836}
16837
16838/**
16839 * Moves any geojson Feature or Geometry of a specified distance along a Rhumb Line
16840 * on the provided direction angle.
16841 *
16842 * @name transformTranslate
16843 * @param {GeoJSON} geojson object to be translated
16844 * @param {number} distance length of the motion; negative values determine motion in opposite direction
16845 * @param {number} direction of the motion; angle from North in decimal degrees, positive clockwise
16846 * @param {Object} [options={}] Optional parameters
16847 * @param {string} [options.units='kilometers'] in which `distance` will be express; miles, kilometers, degrees, or radians
16848 * @param {number} [options.zTranslation=0] length of the vertical motion, same unit of distance
16849 * @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated (significant performance increase if true)
16850 * @returns {GeoJSON} the translated GeoJSON object
16851 * @example
16852 * var poly = turf.polygon([[[0,29],[3.5,29],[2.5,32],[0,29]]]);
16853 * var translatedPoly = turf.transformTranslate(poly, 100, 35);
16854 *
16855 * //addToMap
16856 * var addToMap = [poly, translatedPoly];
16857 * translatedPoly.properties = {stroke: '#F00', 'stroke-width': 4};
16858 */
16859function transformTranslate(geojson, distance, direction, options) {
16860 // Optional parameters
16861 options = options || {};
16862 if (!isObject(options)) throw new Error('options is invalid');
16863 var units = options.units;
16864 var zTranslation = options.zTranslation;
16865 var mutate = options.mutate;
16866
16867 // Input validation
16868 if (!geojson) throw new Error('geojson is required');
16869 if (distance === undefined || distance === null || isNaN(distance)) throw new Error('distance is required');
16870 if (zTranslation && typeof zTranslation !== 'number' && isNaN(zTranslation)) throw new Error('zTranslation is not a number');
16871
16872 // Shortcut no-motion
16873 zTranslation = (zTranslation !== undefined) ? zTranslation : 0;
16874 if (distance === 0 && zTranslation === 0) return geojson;
16875
16876 if (direction === undefined || direction === null || isNaN(direction)) throw new Error('direction is required');
16877
16878 // Invert with negative distances
16879 if (distance < 0) {
16880 distance = -distance;
16881 direction = -direction;
16882 }
16883
16884 // Clone geojson to avoid side effects
16885 if (mutate === false || mutate === undefined) geojson = clone(geojson);
16886
16887 // Translate each coordinate
16888 coordEach(geojson, function (pointCoords) {
16889 var newCoords = getCoords(rhumbDestination(pointCoords, distance, direction, {units: units}));
16890 pointCoords[0] = newCoords[0];
16891 pointCoords[1] = newCoords[1];
16892 if (zTranslation && pointCoords.length === 3) pointCoords[2] += zTranslation;
16893 });
16894 return geojson;
16895}
16896
16897/**
16898 * https://github.com/rook2pawn/node-intersection
16899 *
16900 * Author @rook2pawn
16901 */
16902
16903/**
16904 * AB
16905 *
16906 * @private
16907 * @param {Array<Array<number>>} segment - 2 vertex line segment
16908 * @returns {Array<number>} coordinates [x, y]
16909 */
16910function ab(segment) {
16911 var start = segment[0];
16912 var end = segment[1];
16913 return [end[0] - start[0], end[1] - start[1]];
16914}
16915
16916/**
16917 * Cross Product
16918 *
16919 * @private
16920 * @param {Array<number>} v1 coordinates [x, y]
16921 * @param {Array<number>} v2 coordinates [x, y]
16922 * @returns {Array<number>} Cross Product
16923 */
16924function crossProduct(v1, v2) {
16925 return (v1[0] * v2[1]) - (v2[0] * v1[1]);
16926}
16927
16928/**
16929 * Add
16930 *
16931 * @private
16932 * @param {Array<number>} v1 coordinates [x, y]
16933 * @param {Array<number>} v2 coordinates [x, y]
16934 * @returns {Array<number>} Add
16935 */
16936function add(v1, v2) {
16937 return [v1[0] + v2[0], v1[1] + v2[1]];
16938}
16939
16940/**
16941 * Sub
16942 *
16943 * @private
16944 * @param {Array<number>} v1 coordinates [x, y]
16945 * @param {Array<number>} v2 coordinates [x, y]
16946 * @returns {Array<number>} Sub
16947 */
16948function sub(v1, v2) {
16949 return [v1[0] - v2[0], v1[1] - v2[1]];
16950}
16951
16952/**
16953 * scalarMult
16954 *
16955 * @private
16956 * @param {number} s scalar
16957 * @param {Array<number>} v coordinates [x, y]
16958 * @returns {Array<number>} scalarMult
16959 */
16960function scalarMult(s, v) {
16961 return [s * v[0], s * v[1]];
16962}
16963
16964/**
16965 * Intersect Segments
16966 *
16967 * @private
16968 * @param {Array<number>} a coordinates [x, y]
16969 * @param {Array<number>} b coordinates [x, y]
16970 * @returns {Array<number>} intersection
16971 */
16972function intersectSegments(a, b) {
16973 var p = a[0];
16974 var r = ab(a);
16975 var q = b[0];
16976 var s = ab(b);
16977
16978 var cross = crossProduct(r, s);
16979 var qmp = sub(q, p);
16980 var numerator = crossProduct(qmp, s);
16981 var t = numerator / cross;
16982 var intersection = add(p, scalarMult(t, r));
16983 return intersection;
16984}
16985
16986/**
16987 * Is Parallel
16988 *
16989 * @private
16990 * @param {Array<number>} a coordinates [x, y]
16991 * @param {Array<number>} b coordinates [x, y]
16992 * @returns {boolean} true if a and b are parallel (or co-linear)
16993 */
16994function isParallel(a, b) {
16995 var r = ab(a);
16996 var s = ab(b);
16997 return (crossProduct(r, s) === 0);
16998}
16999
17000/**
17001 * Intersection
17002 *
17003 * @private
17004 * @param {Array<number>} a coordinates [x, y]
17005 * @param {Array<number>} b coordinates [x, y]
17006 * @returns {Array<number>|boolean} true if a and b are parallel (or co-linear)
17007 */
17008function intersection(a, b) {
17009 if (isParallel(a, b)) return false;
17010 return intersectSegments(a, b);
17011}
17012
17013/**
17014 * Takes a {@link LineString|line} and returns a {@link LineString|line} at offset by the specified distance.
17015 *
17016 * @name lineOffset
17017 * @param {Geometry|Feature<LineString|MultiLineString>} geojson input GeoJSON
17018 * @param {number} distance distance to offset the line (can be of negative value)
17019 * @param {Object} [options={}] Optional parameters
17020 * @param {string} [options.units='kilometers'] can be degrees, radians, miles, kilometers, inches, yards, meters
17021 * @returns {Feature<LineString|MultiLineString>} Line offset from the input line
17022 * @example
17023 * var line = turf.lineString([[-83, 30], [-84, 36], [-78, 41]], { "stroke": "#F00" });
17024 *
17025 * var offsetLine = turf.lineOffset(line, 2, {units: 'miles'});
17026 *
17027 * //addToMap
17028 * var addToMap = [offsetLine, line]
17029 * offsetLine.properties.stroke = "#00F"
17030 */
17031function lineOffset(geojson, distance, options) {
17032 // Optional parameters
17033 options = options || {};
17034 if (!isObject(options)) throw new Error('options is invalid');
17035 var units = options.units;
17036
17037 // Valdiation
17038 if (!geojson) throw new Error('geojson is required');
17039 if (distance === undefined || distance === null || isNaN(distance)) throw new Error('distance is required');
17040
17041 var type = getType(geojson);
17042 var properties = geojson.properties;
17043
17044 switch (type) {
17045 case 'LineString':
17046 return lineOffsetFeature(geojson, distance, units);
17047 case 'MultiLineString':
17048 var coords = [];
17049 flattenEach(geojson, function (feature$$1) {
17050 coords.push(lineOffsetFeature(feature$$1, distance, units).geometry.coordinates);
17051 });
17052 return multiLineString(coords, properties);
17053 default:
17054 throw new Error('geometry ' + type + ' is not supported');
17055 }
17056}
17057
17058/**
17059 * Line Offset
17060 *
17061 * @private
17062 * @param {Geometry|Feature<LineString>} line input line
17063 * @param {number} distance distance to offset the line (can be of negative value)
17064 * @param {string} [units=kilometers] units
17065 * @returns {Feature<LineString>} Line offset from the input line
17066 */
17067function lineOffsetFeature(line, distance, units) {
17068 var segments = [];
17069 var offsetDegrees = lengthToDegrees(distance, units);
17070 var coords = getCoords(line);
17071 var finalCoords = [];
17072 coords.forEach(function (currentCoords, index) {
17073 if (index !== coords.length - 1) {
17074 var segment = processSegment(currentCoords, coords[index + 1], offsetDegrees);
17075 segments.push(segment);
17076 if (index > 0) {
17077 var seg2Coords = segments[index - 1];
17078 var intersects = intersection(segment, seg2Coords);
17079
17080 // Handling for line segments that aren't straight
17081 if (intersects !== false) {
17082 seg2Coords[1] = intersects;
17083 segment[0] = intersects;
17084 }
17085
17086 finalCoords.push(seg2Coords[0]);
17087 if (index === coords.length - 2) {
17088 finalCoords.push(segment[0]);
17089 finalCoords.push(segment[1]);
17090 }
17091 }
17092 // Handling for lines that only have 1 segment
17093 if (coords.length === 2) {
17094 finalCoords.push(segment[0]);
17095 finalCoords.push(segment[1]);
17096 }
17097 }
17098 });
17099 return lineString(finalCoords, line.properties);
17100}
17101
17102/**
17103 * Process Segment
17104 * Inspiration taken from http://stackoverflow.com/questions/2825412/draw-a-parallel-line
17105 *
17106 * @private
17107 * @param {Array<number>} point1 Point coordinates
17108 * @param {Array<number>} point2 Point coordinates
17109 * @param {number} offset Offset
17110 * @returns {Array<Array<number>>} offset points
17111 */
17112function processSegment(point1, point2, offset) {
17113 var L = Math.sqrt((point1[0] - point2[0]) * (point1[0] - point2[0]) + (point1[1] - point2[1]) * (point1[1] - point2[1]));
17114
17115 var out1x = point1[0] + offset * (point2[1] - point1[1]) / L;
17116 var out2x = point2[0] + offset * (point2[1] - point1[1]) / L;
17117 var out1y = point1[1] + offset * (point1[0] - point2[0]) / L;
17118 var out2y = point2[1] + offset * (point1[0] - point2[0]) / L;
17119 return [[out1x, out1y], [out2x, out2y]];
17120}
17121
17122/**
17123 * Returns the direction of the point q relative to the vector p1 -> p2.
17124 *
17125 * Implementation of geos::algorithm::CGAlgorithm::orientationIndex()
17126 * (same as geos::algorithm::CGAlgorithm::computeOrientation())
17127 *
17128 * @param {number[]} p1 - the origin point of the vector
17129 * @param {number[]} p2 - the final point of the vector
17130 * @param {number[]} q - the point to compute the direction to
17131 *
17132 * @returns {number} - 1 if q is ccw (left) from p1->p2,
17133 * -1 if q is cw (right) from p1->p2,
17134 * 0 if q is colinear with p1->p2
17135 */
17136function orientationIndex(p1, p2, q) {
17137 var dx1 = p2[0] - p1[0],
17138 dy1 = p2[1] - p1[1],
17139 dx2 = q[0] - p2[0],
17140 dy2 = q[1] - p2[1];
17141
17142 return Math.sign(dx1 * dy2 - dx2 * dy1);
17143}
17144
17145/**
17146 * Checks if two envelopes are equal.
17147 *
17148 * The function assumes that the arguments are envelopes, i.e.: Rectangular polygon
17149 *
17150 * @param {Feature<Polygon>} env1 - Envelope
17151 * @param {Feature<Polygon>} env2 - Envelope
17152 * @returns {boolean} - True if the envelopes are equal
17153 */
17154function envelopeIsEqual(env1, env2) {
17155 var envX1 = env1.geometry.coordinates.map(function (c) { return c[0]; }),
17156 envY1 = env1.geometry.coordinates.map(function (c) { return c[1]; }),
17157 envX2 = env2.geometry.coordinates.map(function (c) { return c[0]; }),
17158 envY2 = env2.geometry.coordinates.map(function (c) { return c[1]; });
17159
17160 return Math.max(null, envX1) === Math.max(null, envX2) &&
17161 Math.max(null, envY1) === Math.max(null, envY2) &&
17162 Math.min(null, envX1) === Math.min(null, envX2) &&
17163 Math.min(null, envY1) === Math.min(null, envY2);
17164}
17165
17166/**
17167 * Check if a envelope is contained in other one.
17168 *
17169 * The function assumes that the arguments are envelopes, i.e.: Convex polygon
17170 * XXX: Envelopes are rectangular, checking if a point is inside a rectangule is something easy,
17171 * this could be further improved.
17172 *
17173 * @param {Feature<Polygon>} self - Envelope
17174 * @param {Feature<Polygon>} env - Envelope
17175 * @returns {boolean} - True if env is contained in self
17176 */
17177function envelopeContains(self, env) {
17178 return env.geometry.coordinates[0].every(function (c) { return booleanPointInPolygon(point(c), self); });
17179}
17180
17181/**
17182 * Checks if two coordinates are equal.
17183 *
17184 * @param {number[]} coord1 - First coordinate
17185 * @param {number[]} coord2 - Second coordinate
17186 * @returns {boolean} - True if coordinates are equal
17187 */
17188function coordinatesEqual(coord1, coord2) {
17189 return coord1[0] === coord2[0] && coord1[1] === coord2[1];
17190}
17191
17192/**
17193 * Node
17194 */
17195var Node$1 = function Node(coordinates) {
17196 this.id = Node.buildId(coordinates);
17197 this.coordinates = coordinates; //< {Number[]}
17198 this.innerEdges = []; //< {Edge[]}
17199
17200 // We wil store to (out) edges in an CCW order as geos::planargraph::DirectedEdgeStar does
17201 this.outerEdges = []; //< {Edge[]}
17202 this.outerEdgesSorted = false; //< {Boolean} flag that stores if the outer Edges had been sorted
17203};
17204
17205Node$1.buildId = function buildId (coordinates) {
17206 return coordinates.join(',');
17207};
17208
17209Node$1.prototype.removeInnerEdge = function removeInnerEdge (edge) {
17210 this.innerEdges = this.innerEdges.filter(function (e) { return e.from.id !== edge.from.id; });
17211};
17212
17213Node$1.prototype.removeOuterEdge = function removeOuterEdge (edge) {
17214 this.outerEdges = this.outerEdges.filter(function (e) { return e.to.id !== edge.to.id; });
17215};
17216
17217/**
17218 * Outer edges are stored CCW order.
17219 *
17220 * @memberof Node
17221 * @param {Edge} edge - Edge to add as an outerEdge.
17222 */
17223Node$1.prototype.addOuterEdge = function addOuterEdge (edge) {
17224 this.outerEdges.push(edge);
17225 this.outerEdgesSorted = false;
17226};
17227
17228/**
17229 * Sorts outer edges in CCW way.
17230 *
17231 * @memberof Node
17232 * @private
17233 */
17234Node$1.prototype.sortOuterEdges = function sortOuterEdges () {
17235 var this$1 = this;
17236
17237 if (!this.outerEdgesSorted) {
17238 //this.outerEdges.sort((a, b) => a.compareTo(b));
17239 // Using this comparator in order to be deterministic
17240 this.outerEdges.sort(function (a, b) {
17241 var aNode = a.to,
17242 bNode = b.to;
17243
17244 if (aNode.coordinates[0] - this$1.coordinates[0] >= 0 && bNode.coordinates[0] - this$1.coordinates[0] < 0)
17245 { return 1; }
17246 if (aNode.coordinates[0] - this$1.coordinates[0] < 0 && bNode.coordinates[0] - this$1.coordinates[0] >= 0)
17247 { return -1; }
17248
17249 if (aNode.coordinates[0] - this$1.coordinates[0] === 0 && bNode.coordinates[0] - this$1.coordinates[0] === 0) {
17250 if (aNode.coordinates[1] - this$1.coordinates[1] >= 0 || bNode.coordinates[1] - this$1.coordinates[1] >= 0)
17251 { return aNode.coordinates[1] - bNode.coordinates[1]; }
17252 return bNode.coordinates[1] - aNode.coordinates[1];
17253 }
17254
17255 var det = orientationIndex(this$1.coordinates, aNode.coordinates, bNode.coordinates);
17256 if (det < 0)
17257 { return 1; }
17258 if (det > 0)
17259 { return -1; }
17260
17261 var d1 = Math.pow(aNode.coordinates[0] - this$1.coordinates[0], 2) + Math.pow(aNode.coordinates[1] - this$1.coordinates[1], 2),
17262 d2 = Math.pow(bNode.coordinates[0] - this$1.coordinates[0], 2) + Math.pow(bNode.coordinates[1] - this$1.coordinates[1], 2);
17263
17264 return d1 - d2;
17265 });
17266 this.outerEdgesSorted = true;
17267 }
17268};
17269
17270/**
17271 * Retrieves outer edges.
17272 *
17273 * They are sorted if they aren't in the CCW order.
17274 *
17275 * @memberof Node
17276 * @returns {Edge[]} - List of outer edges sorted in a CCW order.
17277 */
17278Node$1.prototype.getOuterEdges = function getOuterEdges () {
17279 this.sortOuterEdges();
17280 return this.outerEdges;
17281};
17282
17283Node$1.prototype.getOuterEdge = function getOuterEdge (i) {
17284 this.sortOuterEdges();
17285 return this.outerEdges[i];
17286};
17287
17288Node$1.prototype.addInnerEdge = function addInnerEdge (edge) {
17289 this.innerEdges.push(edge);
17290};
17291
17292/**
17293 * This class is inspired by GEOS's geos::operation::polygonize::PolygonizeDirectedEdge
17294 */
17295var Edge = function Edge(from, to) {
17296 this.from = from; //< start
17297 this.to = to; //< End
17298
17299 this.next = undefined; //< The edge to be computed after
17300 this.label = undefined; //< Used in order to detect Cut Edges (Bridges)
17301 this.symetric = undefined; //< The symetric edge of this
17302 this.ring = undefined; //< EdgeRing in which the Edge is
17303
17304 this.from.addOuterEdge(this);
17305 this.to.addInnerEdge(this);
17306};
17307
17308/**
17309 * Removes edge from from and to nodes.
17310 */
17311Edge.prototype.getSymetric = function getSymetric () {
17312 if (!this.symetric) {
17313 this.symetric = new Edge(this.to, this.from);
17314 this.symetric.symetric = this;
17315 }
17316
17317 return this.symetric;
17318};
17319
17320Edge.prototype.deleteEdge = function deleteEdge () {
17321 this.from.removeOuterEdge(this);
17322 this.to.removeInnerEdge(this);
17323};
17324
17325/**
17326 * Compares Edge equallity.
17327 *
17328 * An edge is equal to another, if the from and to nodes are the same.
17329 *
17330 * @param {Edge} edge - Another Edge
17331 * @returns {boolean} - True if Edges are equal, False otherwise
17332 */
17333Edge.prototype.isEqual = function isEqual (edge) {
17334 return this.from.id === edge.from.id && this.to.id === edge.to.id;
17335};
17336
17337Edge.prototype.toString = function toString () {
17338 return ("Edge { " + (this.from.id) + " -> " + (this.to.id) + " }");
17339};
17340
17341/**
17342 * Returns a LineString representation of the Edge
17343 *
17344 * @returns {Feature<LineString>} - LineString representation of the Edge
17345 */
17346Edge.prototype.toLineString = function toLineString () {
17347 return lineString([this.from.coordinates, this.to.coordinates]);
17348};
17349
17350/**
17351 * Comparator of two edges.
17352 *
17353 * Implementation of geos::planargraph::DirectedEdge::compareTo.
17354 *
17355 * @param {Edge} edge - Another edge to compare with this one
17356 * @returns {number} -1 if this Edge has a greater angle with the positive x-axis than b,
17357 * 0 if the Edges are colinear,
17358 * 1 otherwise
17359 */
17360Edge.prototype.compareTo = function compareTo (edge) {
17361 return orientationIndex(edge.from.coordinates, edge.to.coordinates, this.to.coordinates);
17362};
17363
17364/**
17365 * Ring of edges which form a polygon.
17366 *
17367 * The ring may be either an outer shell or a hole.
17368 *
17369 * This class is inspired in GEOS's geos::operation::polygonize::EdgeRing
17370 */
17371var EdgeRing = function EdgeRing() {
17372 this.edges = [];
17373 this.polygon = undefined; //< Caches Polygon representation
17374 this.envelope = undefined; //< Caches Envelope representation
17375};
17376
17377var prototypeAccessors = { length: { configurable: true } };
17378
17379/**
17380 * Add an edge to the ring, inserting it in the last position.
17381 *
17382 * @memberof EdgeRing
17383 * @param {Edge} edge - Edge to be inserted
17384 */
17385EdgeRing.prototype.push = function push (edge) {
17386// Emulate Array getter ([]) behaviour
17387 this[this.edges.length] = edge;
17388 this.edges.push(edge);
17389 this.polygon = this.envelope = undefined;
17390};
17391
17392/**
17393 * Get Edge.
17394 *
17395 * @memberof EdgeRing
17396 * @param {number} i - Index
17397 * @returns {Edge} - Edge in the i position
17398 */
17399EdgeRing.prototype.get = function get (i) {
17400 return this.edges[i];
17401};
17402
17403/**
17404 * Getter of length property.
17405 *
17406 * @memberof EdgeRing
17407 * @returns {number} - Length of the edge ring.
17408 */
17409prototypeAccessors.length.get = function () {
17410 return this.edges.length;
17411};
17412
17413/**
17414 * Similar to Array.prototype.forEach for the list of Edges in the EdgeRing.
17415 *
17416 * @memberof EdgeRing
17417 * @param {Function} f - The same function to be passed to Array.prototype.forEach
17418 */
17419EdgeRing.prototype.forEach = function forEach (f) {
17420 this.edges.forEach(f);
17421};
17422
17423/**
17424 * Similar to Array.prototype.map for the list of Edges in the EdgeRing.
17425 *
17426 * @memberof EdgeRing
17427 * @param {Function} f - The same function to be passed to Array.prototype.map
17428 * @returns {Array} - The mapped values in the function
17429 */
17430EdgeRing.prototype.map = function map (f) {
17431 return this.edges.map(f);
17432};
17433
17434/**
17435 * Similar to Array.prototype.some for the list of Edges in the EdgeRing.
17436 *
17437 * @memberof EdgeRing
17438 * @param {Function} f - The same function to be passed to Array.prototype.some
17439 * @returns {boolean} - True if an Edge check the condition
17440 */
17441EdgeRing.prototype.some = function some (f) {
17442 return this.edges.some(f);
17443};
17444
17445/**
17446 * Check if the ring is valid in geomtry terms.
17447 *
17448 * A ring must have either 0 or 4 or more points. The first and the last must be
17449 * equal (in 2D)
17450 * geos::geom::LinearRing::validateConstruction
17451 *
17452 * @memberof EdgeRing
17453 * @returns {boolean} - Validity of the EdgeRing
17454 */
17455EdgeRing.prototype.isValid = function isValid () {
17456// TODO: stub
17457 return true;
17458};
17459
17460/**
17461 * Tests whether this ring is a hole.
17462 *
17463 * A ring is a hole if it is oriented counter-clockwise.
17464 * Similar implementation of geos::algorithm::CGAlgorithms::isCCW
17465 *
17466 * @memberof EdgeRing
17467 * @returns {boolean} - true: if it is a hole
17468 */
17469EdgeRing.prototype.isHole = function isHole () {
17470 var this$1 = this;
17471
17472// XXX: Assuming Ring is valid
17473// Find highest point
17474 var hiIndex = this.edges.reduce(function (high, edge, i) {
17475 if (edge.from.coordinates[1] > this$1.edges[high].from.coordinates[1])
17476 { high = i; }
17477 return high;
17478 }, 0),
17479 iPrev = (hiIndex === 0 ? this.length : hiIndex) - 1,
17480 iNext = (hiIndex + 1) % this.length,
17481 disc = orientationIndex(this.edges[iPrev].from.coordinates, this.edges[hiIndex].from.coordinates, this.edges[iNext].from.coordinates);
17482
17483 if (disc === 0)
17484 { return this.edges[iPrev].from.coordinates[0] > this.edges[iNext].from.coordinates[0]; }
17485 return disc > 0;
17486};
17487
17488/**
17489 * Creates a MultiPoint representing the EdgeRing (discarts edges directions).
17490 *
17491 * @memberof EdgeRing
17492 * @returns {Feature<MultiPoint>} - Multipoint representation of the EdgeRing
17493 */
17494EdgeRing.prototype.toMultiPoint = function toMultiPoint () {
17495 return multiPoint(this.edges.map(function (edge) { return edge.from.coordinates; }));
17496};
17497
17498/**
17499 * Creates a Polygon representing the EdgeRing.
17500 *
17501 * @memberof EdgeRing
17502 * @returns {Feature<Polygon>} - Polygon representation of the Edge Ring
17503 */
17504EdgeRing.prototype.toPolygon = function toPolygon () {
17505 if (this.polygon)
17506 { return this.polygon; }
17507 var coordinates = this.edges.map(function (edge) { return edge.from.coordinates; });
17508 coordinates.push(this.edges[0].from.coordinates);
17509 return (this.polygon = polygon([coordinates]));
17510};
17511
17512/**
17513 * Calculates the envelope of the EdgeRing.
17514 *
17515 * @memberof EdgeRing
17516 * @returns {Feature<Polygon>} - envelope
17517 */
17518EdgeRing.prototype.getEnvelope = function getEnvelope () {
17519 if (this.envelope)
17520 { return this.envelope; }
17521 return (this.envelope = envelope(this.toPolygon()));
17522};
17523
17524/**
17525 * `geos::operation::polygonize::EdgeRing::findEdgeRingContaining`
17526 *
17527 * @param {EdgeRing} testEdgeRing - EdgeRing to look in the list
17528 * @param {EdgeRing[]} shellList - List of EdgeRing in which to search
17529 *
17530 * @returns {EdgeRing} - EdgeRing which contains the testEdgeRing
17531 */
17532EdgeRing.findEdgeRingContaining = function findEdgeRingContaining (testEdgeRing, shellList) {
17533 var testEnvelope = testEdgeRing.getEnvelope();
17534
17535 var minEnvelope,
17536 minShell;
17537 shellList.forEach(function (shell) {
17538 var tryEnvelope = shell.getEnvelope();
17539
17540 if (minShell)
17541 { minEnvelope = minShell.getEnvelope(); }
17542
17543 // the hole envelope cannot equal the shell envelope
17544 if (envelopeIsEqual(tryEnvelope, testEnvelope))
17545 { return; }
17546
17547 if (envelopeContains(tryEnvelope, testEnvelope)) {
17548 var testPoint = testEdgeRing.map(function (edge) { return edge.from.coordinates; })
17549 .find(function (pt) { return !shell.some(function (edge) { return coordinatesEqual(pt, edge.from.coordinates); }); });
17550
17551 if (testPoint && shell.inside(point(testPoint))) {
17552 if (!minShell || envelopeContains(minEnvelope, tryEnvelope))
17553 { minShell = shell; }
17554 }
17555 }
17556 });
17557
17558 return minShell;
17559};
17560
17561/**
17562 * Checks if the point is inside the edgeRing
17563 *
17564 * @param {Feature<Point>} pt - Point to check if it is inside the edgeRing
17565 * @returns {boolean} - True if it is inside, False otherwise
17566 */
17567EdgeRing.prototype.inside = function inside (pt) {
17568 return booleanPointInPolygon(pt, this.toPolygon());
17569};
17570
17571Object.defineProperties( EdgeRing.prototype, prototypeAccessors );
17572
17573/**
17574 * Validates the geoJson.
17575 *
17576 * @param {GeoJSON} geoJson - input geoJson.
17577 * @throws {Error} if geoJson is invalid.
17578 */
17579function validateGeoJson(geoJson) {
17580 if (!geoJson)
17581 { throw new Error('No geojson passed'); }
17582
17583 if (geoJson.type !== 'FeatureCollection' &&
17584 geoJson.type !== 'GeometryCollection' &&
17585 geoJson.type !== 'MultiLineString' &&
17586 geoJson.type !== 'LineString' &&
17587 geoJson.type !== 'Feature'
17588 )
17589 { throw new Error(("Invalid input type '" + (geoJson.type) + "'. Geojson must be FeatureCollection, GeometryCollection, LineString, MultiLineString or Feature")); }
17590}
17591
17592/**
17593 * Represents a planar graph of edges and nodes that can be used to compute a polygonization.
17594 *
17595 * Although, this class is inspired by GEOS's `geos::operation::polygonize::PolygonizeGraph`,
17596 * it isn't a rewrite. As regards algorithm, this class implements the same logic, but it
17597 * isn't a javascript transcription of the C++ source.
17598 *
17599 * This graph is directed (both directions are created)
17600 */
17601var Graph = function Graph() {
17602 this.edges = []; //< {Edge[]} dirEdges
17603
17604 // The key is the `id` of the Node (ie: coordinates.join(','))
17605 this.nodes = {};
17606};
17607
17608/**
17609 * Removes Dangle Nodes (nodes with grade 1).
17610 */
17611Graph.fromGeoJson = function fromGeoJson (geoJson) {
17612 validateGeoJson(geoJson);
17613
17614 var graph = new Graph();
17615 flattenEach(geoJson, function (feature$$1) {
17616 featureOf(feature$$1, 'LineString', 'Graph::fromGeoJson');
17617 // When a LineString if formed by many segments, split them
17618 coordReduce(feature$$1, function (prev, cur) {
17619 if (prev) {
17620 var start = graph.getNode(prev),
17621 end = graph.getNode(cur);
17622
17623 graph.addEdge(start, end);
17624 }
17625 return cur;
17626 });
17627 });
17628
17629 return graph;
17630};
17631
17632/**
17633 * Creates or get a Node.
17634 *
17635 * @param {number[]} coordinates - Coordinates of the node
17636 * @returns {Node} - The created or stored node
17637 */
17638Graph.prototype.getNode = function getNode (coordinates) {
17639 var id = Node$1.buildId(coordinates);
17640 var node = this.nodes[id];
17641 if (!node)
17642 { node = this.nodes[id] = new Node$1(coordinates); }
17643
17644 return node;
17645};
17646
17647/**
17648 * Adds an Edge and its symetricall.
17649 *
17650 * Edges are added symetrically, i.e.: we also add its symetric
17651 *
17652 * @param {Node} from - Node which starts the Edge
17653 * @param {Node} to - Node which ends the Edge
17654 */
17655Graph.prototype.addEdge = function addEdge (from, to) {
17656 var edge = new Edge(from, to),
17657 symetricEdge = edge.getSymetric();
17658
17659 this.edges.push(edge);
17660 this.edges.push(symetricEdge);
17661};
17662
17663Graph.prototype.deleteDangles = function deleteDangles () {
17664 var this$1 = this;
17665
17666 Object.keys(this.nodes)
17667 .map(function (id) { return this$1.nodes[id]; })
17668 .forEach(function (node) { return this$1._removeIfDangle(node); });
17669};
17670
17671/**
17672 * Check if node is dangle, if so, remove it.
17673 *
17674 * It calls itself recursively, removing a dangling node might cause another dangling node
17675 *
17676 * @param {Node} node - Node to check if it's a dangle
17677 */
17678Graph.prototype._removeIfDangle = function _removeIfDangle (node) {
17679 var this$1 = this;
17680
17681// As edges are directed and symetrical, we count only innerEdges
17682 if (node.innerEdges.length <= 1) {
17683 var outerNodes = node.getOuterEdges().map(function (e) { return e.to; });
17684 this.removeNode(node);
17685 outerNodes.forEach(function (n) { return this$1._removeIfDangle(n); });
17686 }
17687};
17688
17689/**
17690 * Delete cut-edges (bridge edges).
17691 *
17692 * The graph will be traversed, all the edges will be labeled according the ring
17693 * in which they are. (The label is a number incremented by 1). Edges with the same
17694 * label are cut-edges.
17695 */
17696Graph.prototype.deleteCutEdges = function deleteCutEdges () {
17697 var this$1 = this;
17698
17699 this._computeNextCWEdges();
17700 this._findLabeledEdgeRings();
17701
17702 // Cut-edges (bridges) are edges where both edges have the same label
17703 this.edges.forEach(function (edge) {
17704 if (edge.label === edge.symetric.label) {
17705 this$1.removeEdge(edge.symetric);
17706 this$1.removeEdge(edge);
17707 }
17708 });
17709};
17710
17711/**
17712 * Set the `next` property of each Edge.
17713 *
17714 * The graph will be transversed in a CW form, so, we set the next of the symetrical edge as the previous one.
17715 * OuterEdges are sorted CCW.
17716 *
17717 * @param {Node} [node] - If no node is passed, the function calls itself for every node in the Graph
17718 */
17719Graph.prototype._computeNextCWEdges = function _computeNextCWEdges (node) {
17720 var this$1 = this;
17721
17722 if (typeof node === 'undefined') {
17723 Object.keys(this.nodes)
17724 .forEach(function (id) { return this$1._computeNextCWEdges(this$1.nodes[id]); });
17725 } else {
17726 node.getOuterEdges().forEach(function (edge, i) {
17727 node.getOuterEdge((i === 0 ? node.getOuterEdges().length : i) - 1).symetric.next = edge;
17728 });
17729 }
17730};
17731
17732/**
17733 * Computes the next edge pointers going CCW around the given node, for the given edgering label.
17734 *
17735 * This algorithm has the effect of converting maximal edgerings into minimal edgerings
17736 *
17737 * XXX: method literally transcribed from `geos::operation::polygonize::PolygonizeGraph::computeNextCCWEdges`,
17738 * could be written in a more javascript way.
17739 *
17740 * @param {Node} node - Node
17741 * @param {number} label - Ring's label
17742 */
17743Graph.prototype._computeNextCCWEdges = function _computeNextCCWEdges (node, label) {
17744 var edges = node.getOuterEdges();
17745 var firstOutDE,
17746 prevInDE;
17747
17748 for (var i = edges.length - 1; i >= 0; --i) {
17749 var de = edges[i],
17750 sym = de.symetric,
17751 outDE = (void 0),
17752 inDE = (void 0);
17753
17754 if (de.label === label)
17755 { outDE = de; }
17756
17757 if (sym.label === label)
17758 { inDE = sym; }
17759
17760 if (!outDE || !inDE) // This edge is not in edgering
17761 { continue; }
17762
17763 if (inDE)
17764 { prevInDE = inDE; }
17765
17766 if (outDE) {
17767 if (prevInDE) {
17768 prevInDE.next = outDE;
17769 prevInDE = undefined;
17770 }
17771
17772 if (!firstOutDE)
17773 { firstOutDE = outDE; }
17774 }
17775 }
17776
17777 if (prevInDE)
17778 { prevInDE.next = firstOutDE; }
17779};
17780
17781
17782/**
17783 * Finds rings and labels edges according to which rings are.
17784 *
17785 * The label is a number which is increased for each ring.
17786 *
17787 * @returns {Edge[]} edges that start rings
17788 */
17789Graph.prototype._findLabeledEdgeRings = function _findLabeledEdgeRings () {
17790 var edgeRingStarts = [];
17791 var label = 0;
17792 this.edges.forEach(function (edge) {
17793 if (edge.label >= 0)
17794 { return; }
17795
17796 edgeRingStarts.push(edge);
17797
17798 var e = edge;
17799 do {
17800 e.label = label;
17801 e = e.next;
17802 } while (!edge.isEqual(e));
17803
17804 label++;
17805 });
17806
17807 return edgeRingStarts;
17808};
17809
17810/**
17811 * Computes the EdgeRings formed by the edges in this graph.
17812 *
17813 * @returns {EdgeRing[]} - A list of all the EdgeRings in the graph.
17814 */
17815Graph.prototype.getEdgeRings = function getEdgeRings () {
17816 var this$1 = this;
17817
17818 this._computeNextCWEdges();
17819
17820 // Clear labels
17821 this.edges.forEach(function (edge) {
17822 edge.label = undefined;
17823 });
17824
17825 this._findLabeledEdgeRings().forEach(function (edge) {
17826 // convertMaximalToMinimalEdgeRings
17827 this$1._findIntersectionNodes(edge).forEach(function (node) {
17828 this$1._computeNextCCWEdges(node, edge.label);
17829 });
17830 });
17831
17832 var edgeRingList = [];
17833
17834 // find all edgerings
17835 this.edges.forEach(function (edge) {
17836 if (edge.ring)
17837 { return; }
17838 edgeRingList.push(this$1._findEdgeRing(edge));
17839 });
17840
17841 return edgeRingList;
17842};
17843
17844/**
17845 * Find all nodes in a Maxima EdgeRing which are self-intersection nodes.
17846 *
17847 * @param {Node} startEdge - Start Edge of the Ring
17848 * @returns {Node[]} - intersection nodes
17849 */
17850Graph.prototype._findIntersectionNodes = function _findIntersectionNodes (startEdge) {
17851 var intersectionNodes = [];
17852 var edge = startEdge;
17853 var loop = function () {
17854 // getDegree
17855 var degree = 0;
17856 edge.from.getOuterEdges().forEach(function (e) {
17857 if (e.label === startEdge.label)
17858 { ++degree; }
17859 });
17860
17861 if (degree > 1)
17862 { intersectionNodes.push(edge.from); }
17863
17864 edge = edge.next;
17865 };
17866
17867 do {
17868 loop();
17869 } while (!startEdge.isEqual(edge));
17870
17871 return intersectionNodes;
17872};
17873
17874/**
17875 * Get the edge-ring which starts from the provided Edge.
17876 *
17877 * @param {Edge} startEdge - starting edge of the edge ring
17878 * @returns {EdgeRing} - EdgeRing which start Edge is the provided one.
17879 */
17880Graph.prototype._findEdgeRing = function _findEdgeRing (startEdge) {
17881 var edge = startEdge;
17882 var edgeRing = new EdgeRing();
17883
17884 do {
17885 edgeRing.push(edge);
17886 edge.ring = edgeRing;
17887 edge = edge.next;
17888 } while (!startEdge.isEqual(edge));
17889
17890 return edgeRing;
17891};
17892
17893/**
17894 * Removes a node from the Graph.
17895 *
17896 * It also removes edges asociated to that node
17897 * @param {Node} node - Node to be removed
17898 */
17899Graph.prototype.removeNode = function removeNode (node) {
17900 var this$1 = this;
17901
17902 node.getOuterEdges().forEach(function (edge) { return this$1.removeEdge(edge); });
17903 node.innerEdges.forEach(function (edge) { return this$1.removeEdge(edge); });
17904 delete this.nodes[node.id];
17905};
17906
17907/**
17908 * Remove edge from the graph and deletes the edge.
17909 *
17910 * @param {Edge} edge - Edge to be removed
17911 */
17912Graph.prototype.removeEdge = function removeEdge (edge) {
17913 this.edges = this.edges.filter(function (e) { return !e.isEqual(edge); });
17914 edge.deleteEdge();
17915};
17916
17917/**
17918 * Polygonizes {@link LineString|(Multi)LineString(s)} into {@link Polygons}.
17919 *
17920 * Implementation of GEOSPolygonize function (`geos::operation::polygonize::Polygonizer`).
17921 *
17922 * Polygonizes a set of lines that represents edges in a planar graph. Edges must be correctly
17923 * noded, i.e., they must only meet at their endpoints.
17924 *
17925 * The implementation correctly handles:
17926 *
17927 * - Dangles: edges which have one or both ends which are not incident on another edge endpoint.
17928 * - Cut Edges (bridges): edges that are connected at both ends but which do not form part of a polygon.
17929 *
17930 * @name polygonize
17931 * @param {FeatureCollection|Geometry|Feature<LineString|MultiLineString>} geoJson Lines in order to polygonize
17932 * @returns {FeatureCollection<Polygon>} Polygons created
17933 * @throws {Error} if geoJson is invalid.
17934 */
17935function polygonize$1(geoJson) {
17936 var graph = Graph.fromGeoJson(geoJson);
17937
17938 // 1. Remove dangle node
17939 graph.deleteDangles();
17940
17941 // 2. Remove cut-edges (bridge edges)
17942 graph.deleteCutEdges();
17943
17944 // 3. Get all holes and shells
17945 var holes = [],
17946 shells = [];
17947
17948 graph.getEdgeRings()
17949 .filter(function (edgeRing) { return edgeRing.isValid(); })
17950 .forEach(function (edgeRing) {
17951 if (edgeRing.isHole())
17952 { holes.push(edgeRing); }
17953 else
17954 { shells.push(edgeRing); }
17955 });
17956
17957 // 4. Assign Holes to Shells
17958 holes.forEach(function (hole) {
17959 if (EdgeRing.findEdgeRingContaining(hole, shells))
17960 { shells.push(hole); }
17961 });
17962
17963 // 5. EdgeRings to Polygons
17964 return featureCollection(shells.map(function (shell) { return shell.toPolygon(); }));
17965}
17966
17967/**
17968 * Boolean-disjoint returns (TRUE) if the intersection of the two geometries is an empty set.
17969 *
17970 * @name booleanDisjoint
17971 * @param {Geometry|Feature<any>} feature1 GeoJSON Feature or Geometry
17972 * @param {Geometry|Feature<any>} feature2 GeoJSON Feature or Geometry
17973 * @returns {boolean} true/false
17974 * @example
17975 * var point = turf.point([2, 2]);
17976 * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]);
17977 *
17978 * turf.booleanDisjoint(line, point);
17979 * //=true
17980 */
17981function booleanDisjoint(feature1, feature2) {
17982 var boolean;
17983 flattenEach(feature1, function (flatten1) {
17984 flattenEach(feature2, function (flatten2) {
17985 if (boolean === false) return false;
17986 boolean = disjoint(flatten1.geometry, flatten2.geometry);
17987 });
17988 });
17989 return boolean;
17990}
17991
17992/**
17993 * Disjoint operation for simple Geometries (Point/LineString/Polygon)
17994 *
17995 * @private
17996 * @param {Geometry<any>} geom1 GeoJSON Geometry
17997 * @param {Geometry<any>} geom2 GeoJSON Geometry
17998 * @returns {boolean} true/false
17999 */
18000function disjoint(geom1, geom2) {
18001 switch (geom1.type) {
18002 case 'Point':
18003 switch (geom2.type) {
18004 case 'Point':
18005 return !compareCoords$1(geom1.coordinates, geom2.coordinates);
18006 case 'LineString':
18007 return !isPointOnLine$1(geom2, geom1);
18008 case 'Polygon':
18009 return !booleanPointInPolygon(geom1, geom2);
18010 }
18011 /* istanbul ignore next */
18012 break;
18013 case 'LineString':
18014 switch (geom2.type) {
18015 case 'Point':
18016 return !isPointOnLine$1(geom1, geom2);
18017 case 'LineString':
18018 return !isLineOnLine$1(geom1, geom2);
18019 case 'Polygon':
18020 return !isLineInPoly$1(geom2, geom1);
18021 }
18022 /* istanbul ignore next */
18023 break;
18024 case 'Polygon':
18025 switch (geom2.type) {
18026 case 'Point':
18027 return !booleanPointInPolygon(geom2, geom1);
18028 case 'LineString':
18029 return !isLineInPoly$1(geom1, geom2);
18030 case 'Polygon':
18031 return !isPolyInPoly$1(geom2, geom1);
18032 }
18033 }
18034}
18035
18036// http://stackoverflow.com/a/11908158/1979085
18037function isPointOnLine$1(lineString, point) {
18038 for (var i = 0; i < lineString.coordinates.length - 1; i++) {
18039 if (isPointOnLineSegment$2(lineString.coordinates[i], lineString.coordinates[i + 1], point.coordinates)) {
18040 return true;
18041 }
18042 }
18043 return false;
18044}
18045
18046function isLineOnLine$1(lineString1, lineString2) {
18047 var doLinesIntersect = lineIntersect(lineString1, lineString2);
18048 if (doLinesIntersect.features.length > 0) {
18049 return true;
18050 }
18051 return false;
18052}
18053
18054function isLineInPoly$1(polygon, lineString) {
18055 var doLinesIntersect = lineIntersect(lineString, polygonToLine(polygon));
18056 if (doLinesIntersect.features.length > 0) {
18057 return true;
18058 }
18059 return false;
18060}
18061
18062/**
18063 * Is Polygon (geom1) in Polygon (geom2)
18064 * Only takes into account outer rings
18065 * See http://stackoverflow.com/a/4833823/1979085
18066 *
18067 * @private
18068 * @param {Geometry|Feature<Polygon>} feature1 Polygon1
18069 * @param {Geometry|Feature<Polygon>} feature2 Polygon2
18070 * @returns {boolean} true/false
18071 */
18072function isPolyInPoly$1(feature1, feature2) {
18073 for (var i = 0; i < feature1.coordinates[0].length; i++) {
18074 if (booleanPointInPolygon(feature1.coordinates[0][i], feature2)) {
18075 return true;
18076 }
18077 }
18078 for (var i2 = 0; i2 < feature2.coordinates[0].length; i2++) {
18079 if (booleanPointInPolygon(feature2.coordinates[0][i2], feature1)) {
18080 return true;
18081 }
18082 }
18083 return false;
18084}
18085
18086function isPointOnLineSegment$2(LineSegmentStart, LineSegmentEnd, Point) {
18087 var dxc = Point[0] - LineSegmentStart[0];
18088 var dyc = Point[1] - LineSegmentStart[1];
18089 var dxl = LineSegmentEnd[0] - LineSegmentStart[0];
18090 var dyl = LineSegmentEnd[1] - LineSegmentStart[1];
18091 var cross = dxc * dyl - dyc * dxl;
18092 if (cross !== 0) {
18093 return false;
18094 }
18095 if (Math.abs(dxl) >= Math.abs(dyl)) {
18096 if (dxl > 0) {
18097 return LineSegmentStart[0] <= Point[0] && Point[0] <= LineSegmentEnd[0];
18098 } else {
18099 return LineSegmentEnd[0] <= Point[0] && Point[0] <= LineSegmentStart[0];
18100 }
18101 } else if (dyl > 0) {
18102 return LineSegmentStart[1] <= Point[1] && Point[1] <= LineSegmentEnd[1];
18103 } else {
18104 return LineSegmentEnd[1] <= Point[1] && Point[1] <= LineSegmentStart[1];
18105 }
18106}
18107
18108/**
18109 * compareCoords
18110 *
18111 * @private
18112 * @param {Position} pair1 point [x,y]
18113 * @param {Position} pair2 point [x,y]
18114 * @returns {boolean} true/false if coord pairs match
18115 */
18116function compareCoords$1(pair1, pair2) {
18117 return pair1[0] === pair2[0] && pair1[1] === pair2[1];
18118}
18119
18120/**
18121 * Boolean-contains returns True if the second geometry is completely contained by the first geometry.
18122 * The interiors of both geometries must intersect and, the interior and boundary of the secondary (geometry b)
18123 * must not intersect the exterior of the primary (geometry a).
18124 * Boolean-contains returns the exact opposite result of the `@turf/boolean-within`.
18125 *
18126 * @name booleanContains
18127 * @param {Geometry|Feature<any>} feature1 GeoJSON Feature or Geometry
18128 * @param {Geometry|Feature<any>} feature2 GeoJSON Feature or Geometry
18129 * @returns {boolean} true/false
18130 * @example
18131 * var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]);
18132 * var point = turf.point([1, 2]);
18133 *
18134 * turf.booleanContains(line, point);
18135 * //=true
18136 */
18137function booleanContains(feature1, feature2) {
18138 var type1 = getType(feature1);
18139 var type2 = getType(feature2);
18140 var geom1 = getGeom(feature1);
18141 var geom2 = getGeom(feature2);
18142 var coords1 = getCoords(feature1);
18143 var coords2 = getCoords(feature2);
18144
18145 switch (type1) {
18146 case 'Point':
18147 switch (type2) {
18148 case 'Point':
18149 return compareCoords$2(coords1, coords2);
18150 default:
18151 throw new Error('feature2 ' + type2 + ' geometry not supported');
18152 }
18153 case 'MultiPoint':
18154 switch (type2) {
18155 case 'Point':
18156 return isPointInMultiPoint$1(geom1, geom2);
18157 case 'MultiPoint':
18158 return isMultiPointInMultiPoint$1(geom1, geom2);
18159 default:
18160 throw new Error('feature2 ' + type2 + ' geometry not supported');
18161 }
18162 case 'LineString':
18163 switch (type2) {
18164 case 'Point':
18165 return booleanPointOnLine(geom2, geom1, {ignoreEndVertices: true});
18166 case 'LineString':
18167 return isLineOnLine$2(geom1, geom2);
18168 case 'MultiPoint':
18169 return isMultiPointOnLine$1(geom1, geom2);
18170 default:
18171 throw new Error('feature2 ' + type2 + ' geometry not supported');
18172 }
18173 case 'Polygon':
18174 switch (type2) {
18175 case 'Point':
18176 return booleanPointInPolygon(geom2, geom1, {ignoreBoundary: true});
18177 case 'LineString':
18178 return isLineInPoly$2(geom1, geom2);
18179 case 'Polygon':
18180 return isPolyInPoly$2(geom1, geom2);
18181 case 'MultiPoint':
18182 return isMultiPointInPoly$1(geom1, geom2);
18183 default:
18184 throw new Error('feature2 ' + type2 + ' geometry not supported');
18185 }
18186 default:
18187 throw new Error('feature1 ' + type1 + ' geometry not supported');
18188 }
18189}
18190
18191function isPointInMultiPoint$1(multiPoint, point) {
18192 var i;
18193 var output = false;
18194 for (i = 0; i < multiPoint.coordinates.length; i++) {
18195 if (compareCoords$2(multiPoint.coordinates[i], point.coordinates)) {
18196 output = true;
18197 break;
18198 }
18199 }
18200 return output;
18201}
18202
18203function isMultiPointInMultiPoint$1(multiPoint1, multiPoint2) {
18204 for (var i = 0; i < multiPoint2.coordinates.length; i++) {
18205 var matchFound = false;
18206 for (var i2 = 0; i2 < multiPoint1.coordinates.length; i2++) {
18207 if (compareCoords$2(multiPoint2.coordinates[i], multiPoint1.coordinates[i2])) {
18208 matchFound = true;
18209 break;
18210 }
18211 }
18212 if (!matchFound) {
18213 return false;
18214 }
18215 }
18216 return true;
18217}
18218
18219
18220function isMultiPointOnLine$1(lineString, multiPoint) {
18221 var haveFoundInteriorPoint = false;
18222 for (var i = 0; i < multiPoint.coordinates.length; i++) {
18223 if (booleanPointOnLine(multiPoint.coordinates[i], lineString, {ignoreEndVertices: true})) {
18224 haveFoundInteriorPoint = true;
18225 }
18226 if (!booleanPointOnLine(multiPoint.coordinates[i], lineString)) {
18227 return false;
18228 }
18229 }
18230 if (haveFoundInteriorPoint) {
18231 return true;
18232 }
18233 return false;
18234}
18235
18236function isMultiPointInPoly$1(polygon, multiPoint) {
18237 for (var i = 0; i < multiPoint.coordinates.length; i++) {
18238 if (!booleanPointInPolygon(multiPoint.coordinates[i], polygon, {ignoreBoundary: true})) {
18239 return false;
18240 }
18241 }
18242 return true;
18243}
18244
18245function isLineOnLine$2(lineString1, lineString2) {
18246 var haveFoundInteriorPoint = false;
18247 for (var i = 0; i < lineString2.coordinates.length; i++) {
18248 if (booleanPointOnLine({type: 'Point', coordinates: lineString2.coordinates[i]}, lineString1, { ignoreEndVertices: true })) {
18249 haveFoundInteriorPoint = true;
18250 }
18251 if (!booleanPointOnLine({type: 'Point', coordinates: lineString2.coordinates[i]}, lineString1, {ignoreEndVertices: false })) {
18252 return false;
18253 }
18254 }
18255 return haveFoundInteriorPoint;
18256}
18257
18258function isLineInPoly$2(polygon, linestring) {
18259 var output = false;
18260 var i = 0;
18261
18262 var polyBbox = bbox(polygon);
18263 var lineBbox = bbox(linestring);
18264 if (!doBBoxOverlap$1(polyBbox, lineBbox)) {
18265 return false;
18266 }
18267 for (i; i < linestring.coordinates.length - 1; i++) {
18268 var midPoint = getMidpoint$1(linestring.coordinates[i], linestring.coordinates[i + 1]);
18269 if (booleanPointInPolygon({type: 'Point', coordinates: midPoint}, polygon, { ignoreBoundary: true })) {
18270 output = true;
18271 break;
18272 }
18273 }
18274 return output;
18275}
18276
18277/**
18278 * Is Polygon2 in Polygon1
18279 * Only takes into account outer rings
18280 *
18281 * @private
18282 * @param {Geometry|Feature<Polygon>} feature1 Polygon1
18283 * @param {Geometry|Feature<Polygon>} feature2 Polygon2
18284 * @returns {boolean} true/false
18285 */
18286function isPolyInPoly$2(feature1, feature2) {
18287 var poly1Bbox = bbox(feature1);
18288 var poly2Bbox = bbox(feature2);
18289 if (!doBBoxOverlap$1(poly1Bbox, poly2Bbox)) {
18290 return false;
18291 }
18292 for (var i = 0; i < feature2.coordinates[0].length; i++) {
18293 if (!booleanPointInPolygon(feature2.coordinates[0][i], feature1)) {
18294 return false;
18295 }
18296 }
18297 return true;
18298}
18299
18300function doBBoxOverlap$1(bbox1, bbox2) {
18301 if (bbox1[0] > bbox2[0]) return false;
18302 if (bbox1[2] < bbox2[2]) return false;
18303 if (bbox1[1] > bbox2[1]) return false;
18304 if (bbox1[3] < bbox2[3]) return false;
18305 return true;
18306}
18307
18308/**
18309 * compareCoords
18310 *
18311 * @private
18312 * @param {Position} pair1 point [x,y]
18313 * @param {Position} pair2 point [x,y]
18314 * @returns {boolean} true/false if coord pairs match
18315 */
18316function compareCoords$2(pair1, pair2) {
18317 return pair1[0] === pair2[0] && pair1[1] === pair2[1];
18318}
18319
18320function getMidpoint$1(pair1, pair2) {
18321 return [(pair1[0] + pair2[0]) / 2, (pair1[1] + pair2[1]) / 2];
18322}
18323
18324/**
18325 * Boolean-Crosses returns True if the intersection results in a geometry whose dimension is one less than
18326 * the maximum dimension of the two source geometries and the intersection set is interior to
18327 * both source geometries.
18328 *
18329 * Boolean-Crosses returns t (TRUE) for only multipoint/polygon, multipoint/linestring, linestring/linestring, linestring/polygon, and linestring/multipolygon comparisons.
18330 *
18331 * @name booleanCrosses
18332 * @param {Geometry|Feature<any>} feature1 GeoJSON Feature or Geometry
18333 * @param {Geometry|Feature<any>} feature2 GeoJSON Feature or Geometry
18334 * @returns {boolean} true/false
18335 * @example
18336 * var line1 = turf.lineString([[-2, 2], [4, 2]]);
18337 * var line2 = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]);
18338 *
18339 * var cross = turf.booleanCrosses(line1, line2);
18340 * //=true
18341 */
18342function booleanCrosses(feature1, feature2) {
18343 var type1 = getType(feature1);
18344 var type2 = getType(feature2);
18345 var geom1 = getGeom(feature1);
18346 var geom2 = getGeom(feature2);
18347
18348 switch (type1) {
18349 case 'MultiPoint':
18350 switch (type2) {
18351 case 'LineString':
18352 return doMultiPointAndLineStringCross(geom1, geom2);
18353 case 'Polygon':
18354 return doesMultiPointCrossPoly(geom1, geom2);
18355 default:
18356 throw new Error('feature2 ' + type2 + ' geometry not supported');
18357 }
18358 case 'LineString':
18359 switch (type2) {
18360 case 'MultiPoint': // An inverse operation
18361 return doMultiPointAndLineStringCross(geom2, geom1);
18362 case 'LineString':
18363 return doLineStringsCross(geom1, geom2);
18364 case 'Polygon':
18365 return doLineStringAndPolygonCross(geom1, geom2);
18366 default:
18367 throw new Error('feature2 ' + type2 + ' geometry not supported');
18368 }
18369 case 'Polygon':
18370 switch (type2) {
18371 case 'MultiPoint': // An inverse operation
18372 return doesMultiPointCrossPoly(geom2, geom1);
18373 case 'LineString': // An inverse operation
18374 return doLineStringAndPolygonCross(geom2, geom1);
18375 default:
18376 throw new Error('feature2 ' + type2 + ' geometry not supported');
18377 }
18378 default:
18379 throw new Error('feature1 ' + type1 + ' geometry not supported');
18380 }
18381}
18382
18383function doMultiPointAndLineStringCross(multiPoint$$1, lineString$$1) {
18384 var foundIntPoint = false;
18385 var foundExtPoint = false;
18386 var pointLength = multiPoint$$1.coordinates.length;
18387 var i = 0;
18388 while (i < pointLength && !foundIntPoint && !foundExtPoint) {
18389 for (var i2 = 0; i2 < lineString$$1.coordinates.length - 1; i2++) {
18390 var incEndVertices = true;
18391 if (i2 === 0 || i2 === lineString$$1.coordinates.length - 2) {
18392 incEndVertices = false;
18393 }
18394 if (isPointOnLineSegment$3(lineString$$1.coordinates[i2], lineString$$1.coordinates[i2 + 1], multiPoint$$1.coordinates[i], incEndVertices)) {
18395 foundIntPoint = true;
18396 } else {
18397 foundExtPoint = true;
18398 }
18399 }
18400 i++;
18401 }
18402 return foundIntPoint && foundExtPoint;
18403}
18404
18405function doLineStringsCross(lineString1, lineString2) {
18406 var doLinesIntersect = lineIntersect(lineString1, lineString2);
18407 if (doLinesIntersect.features.length > 0) {
18408 for (var i = 0; i < lineString1.coordinates.length - 1; i++) {
18409 for (var i2 = 0; i2 < lineString2.coordinates.length - 1; i2++) {
18410 var incEndVertices = true;
18411 if (i2 === 0 || i2 === lineString2.coordinates.length - 2) {
18412 incEndVertices = false;
18413 }
18414 if (isPointOnLineSegment$3(lineString1.coordinates[i], lineString1.coordinates[i + 1], lineString2.coordinates[i2], incEndVertices)) {
18415 return true;
18416 }
18417 }
18418 }
18419 }
18420 return false;
18421}
18422
18423function doLineStringAndPolygonCross(lineString$$1, polygon$$1) {
18424 var doLinesIntersect = lineIntersect(lineString$$1, polygonToLine(polygon$$1));
18425 if (doLinesIntersect.features.length > 0) {
18426 return true;
18427 }
18428 return false;
18429}
18430
18431function doesMultiPointCrossPoly(multiPoint$$1, polygon$$1) {
18432 var foundIntPoint = false;
18433 var foundExtPoint = false;
18434 var pointLength = multiPoint$$1.coordinates[0].length;
18435 var i = 0;
18436 while (i < pointLength && foundIntPoint && foundExtPoint) {
18437 if (booleanPointInPolygon(point(multiPoint$$1.coordinates[0][i]), polygon$$1)) {
18438 foundIntPoint = true;
18439 } else {
18440 foundExtPoint = true;
18441 }
18442 i++;
18443 }
18444
18445 return foundExtPoint && foundExtPoint;
18446}
18447
18448/**
18449 * Is a point on a line segment
18450 * Only takes into account outer rings
18451 * See http://stackoverflow.com/a/4833823/1979085
18452 *
18453 * @private
18454 * @param {number[]} lineSegmentStart coord pair of start of line
18455 * @param {number[]} lineSegmentEnd coord pair of end of line
18456 * @param {number[]} pt coord pair of point to check
18457 * @param {boolean} incEnd whether the point is allowed to fall on the line ends
18458 * @returns {boolean} true/false
18459 */
18460function isPointOnLineSegment$3(lineSegmentStart, lineSegmentEnd, pt, incEnd) {
18461 var dxc = pt[0] - lineSegmentStart[0];
18462 var dyc = pt[1] - lineSegmentStart[1];
18463 var dxl = lineSegmentEnd[0] - lineSegmentStart[0];
18464 var dyl = lineSegmentEnd[1] - lineSegmentStart[1];
18465 var cross = dxc * dyl - dyc * dxl;
18466 if (cross !== 0) {
18467 return false;
18468 }
18469 if (incEnd) {
18470 if (Math.abs(dxl) >= Math.abs(dyl)) {
18471 return dxl > 0 ? lineSegmentStart[0] <= pt[0] && pt[0] <= lineSegmentEnd[0] : lineSegmentEnd[0] <= pt[0] && pt[0] <= lineSegmentStart[0];
18472 }
18473 return dyl > 0 ? lineSegmentStart[1] <= pt[1] && pt[1] <= lineSegmentEnd[1] : lineSegmentEnd[1] <= pt[1] && pt[1] <= lineSegmentStart[1];
18474 } else {
18475 if (Math.abs(dxl) >= Math.abs(dyl)) {
18476 return dxl > 0 ? lineSegmentStart[0] < pt[0] && pt[0] < lineSegmentEnd[0] : lineSegmentEnd[0] < pt[0] && pt[0] < lineSegmentStart[0];
18477 }
18478 return dyl > 0 ? lineSegmentStart[1] < pt[1] && pt[1] < lineSegmentEnd[1] : lineSegmentEnd[1] < pt[1] && pt[1] < lineSegmentStart[1];
18479 }
18480}
18481
18482var keys = createCommonjsModule(function (module, exports) {
18483exports = module.exports = typeof Object.keys === 'function'
18484 ? Object.keys : shim;
18485
18486exports.shim = shim;
18487function shim (obj) {
18488 var keys = [];
18489 for (var key in obj) keys.push(key);
18490 return keys;
18491}
18492});
18493
18494var keys_1 = keys.shim;
18495
18496var is_arguments = createCommonjsModule(function (module, exports) {
18497var supportsArgumentsClass = (function(){
18498 return Object.prototype.toString.call(arguments)
18499})() == '[object Arguments]';
18500
18501exports = module.exports = supportsArgumentsClass ? supported : unsupported;
18502
18503exports.supported = supported;
18504function supported(object) {
18505 return Object.prototype.toString.call(object) == '[object Arguments]';
18506}
18507
18508exports.unsupported = unsupported;
18509function unsupported(object){
18510 return object &&
18511 typeof object == 'object' &&
18512 typeof object.length == 'number' &&
18513 Object.prototype.hasOwnProperty.call(object, 'callee') &&
18514 !Object.prototype.propertyIsEnumerable.call(object, 'callee') ||
18515 false;
18516}
18517});
18518
18519var is_arguments_1 = is_arguments.supported;
18520var is_arguments_2 = is_arguments.unsupported;
18521
18522var deepEqual_1 = createCommonjsModule(function (module) {
18523var pSlice = Array.prototype.slice;
18524
18525
18526
18527var deepEqual = module.exports = function (actual, expected, opts) {
18528 if (!opts) opts = {};
18529 // 7.1. All identical values are equivalent, as determined by ===.
18530 if (actual === expected) {
18531 return true;
18532
18533 } else if (actual instanceof Date && expected instanceof Date) {
18534 return actual.getTime() === expected.getTime();
18535
18536 // 7.3. Other pairs that do not both pass typeof value == 'object',
18537 // equivalence is determined by ==.
18538 } else if (!actual || !expected || typeof actual != 'object' && typeof expected != 'object') {
18539 return opts.strict ? actual === expected : actual == expected;
18540
18541 // 7.4. For all other Object pairs, including Array objects, equivalence is
18542 // determined by having the same number of owned properties (as verified
18543 // with Object.prototype.hasOwnProperty.call), the same set of keys
18544 // (although not necessarily the same order), equivalent values for every
18545 // corresponding key, and an identical 'prototype' property. Note: this
18546 // accounts for both named and indexed properties on Arrays.
18547 } else {
18548 return objEquiv(actual, expected, opts);
18549 }
18550};
18551
18552function isUndefinedOrNull(value) {
18553 return value === null || value === undefined;
18554}
18555
18556function isBuffer (x) {
18557 if (!x || typeof x !== 'object' || typeof x.length !== 'number') return false;
18558 if (typeof x.copy !== 'function' || typeof x.slice !== 'function') {
18559 return false;
18560 }
18561 if (x.length > 0 && typeof x[0] !== 'number') return false;
18562 return true;
18563}
18564
18565function objEquiv(a, b, opts) {
18566 var i, key;
18567 if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
18568 return false;
18569 // an identical 'prototype' property.
18570 if (a.prototype !== b.prototype) return false;
18571 //~~~I've managed to break Object.keys through screwy arguments passing.
18572 // Converting to array solves the problem.
18573 if (is_arguments(a)) {
18574 if (!is_arguments(b)) {
18575 return false;
18576 }
18577 a = pSlice.call(a);
18578 b = pSlice.call(b);
18579 return deepEqual(a, b, opts);
18580 }
18581 if (isBuffer(a)) {
18582 if (!isBuffer(b)) {
18583 return false;
18584 }
18585 if (a.length !== b.length) return false;
18586 for (i = 0; i < a.length; i++) {
18587 if (a[i] !== b[i]) return false;
18588 }
18589 return true;
18590 }
18591 try {
18592 var ka = keys(a),
18593 kb = keys(b);
18594 } catch (e) {//happens when one is a string literal and the other isn't
18595 return false;
18596 }
18597 // having the same number of owned properties (keys incorporates
18598 // hasOwnProperty)
18599 if (ka.length != kb.length)
18600 return false;
18601 //the same set of keys (although not necessarily the same order),
18602 ka.sort();
18603 kb.sort();
18604 //~~~cheap key test
18605 for (i = ka.length - 1; i >= 0; i--) {
18606 if (ka[i] != kb[i])
18607 return false;
18608 }
18609 //equivalent values for every corresponding key, and
18610 //~~~possibly expensive deep test
18611 for (i = ka.length - 1; i >= 0; i--) {
18612 key = ka[i];
18613 if (!deepEqual(a[key], b[key], opts)) return false;
18614 }
18615 return typeof a === typeof b;
18616}
18617});
18618
18619//index.js
18620
18621
18622var Equality = function(opt) {
18623 this.precision = opt && opt.precision ? opt.precision : 17;
18624 this.direction = opt && opt.direction ? opt.direction : false;
18625 this.pseudoNode = opt && opt.pseudoNode ? opt.pseudoNode : false;
18626 this.objectComparator = opt && opt.objectComparator ? opt.objectComparator : objectComparator;
18627};
18628
18629Equality.prototype.compare = function(g1,g2) {
18630 if (g1.type !== g2.type || !sameLength(g1,g2)) return false;
18631
18632 switch(g1.type) {
18633 case 'Point':
18634 return this.compareCoord(g1.coordinates, g2.coordinates);
18635 break;
18636 case 'LineString':
18637 return this.compareLine(g1.coordinates, g2.coordinates,0,false);
18638 break;
18639 case 'Polygon':
18640 return this.comparePolygon(g1,g2);
18641 break;
18642 case 'Feature':
18643 return this.compareFeature(g1, g2);
18644 default:
18645 if (g1.type.indexOf('Multi') === 0) {
18646 var context = this;
18647 var g1s = explode$2(g1);
18648 var g2s = explode$2(g2);
18649 return g1s.every(function(g1part) {
18650 return this.some(function(g2part) {
18651 return context.compare(g1part,g2part);
18652 });
18653 },g2s);
18654 }
18655 }
18656 return false;
18657};
18658
18659function explode$2(g) {
18660 return g.coordinates.map(function(part) {
18661 return {
18662 type: g.type.replace('Multi', ''),
18663 coordinates: part}
18664 });
18665}
18666//compare length of coordinates/array
18667function sameLength(g1,g2) {
18668 return g1.hasOwnProperty('coordinates') ?
18669 g1.coordinates.length === g2.coordinates.length
18670 : g1.length === g2.length;
18671}
18672
18673// compare the two coordinates [x,y]
18674Equality.prototype.compareCoord = function(c1,c2) {
18675 if (c1.length !== c2.length) {
18676 return false;
18677 }
18678
18679 for (var i=0; i < c1.length; i++) {
18680 if (c1[i].toFixed(this.precision) !== c2[i].toFixed(this.precision)) {
18681 return false;
18682 }
18683 }
18684 return true;
18685};
18686
18687Equality.prototype.compareLine = function(path1,path2,ind,isPoly) {
18688 if (!sameLength(path1,path2)) return false;
18689 var p1 = this.pseudoNode ? path1 : this.removePseudo(path1);
18690 var p2 = this.pseudoNode ? path2 : this.removePseudo(path2);
18691 if (isPoly && !this.compareCoord(p1[0],p2[0])) {
18692 // fix start index of both to same point
18693 p2 = this.fixStartIndex(p2,p1);
18694 if(!p2) return;
18695 }
18696 // for linestring ind =0 and for polygon ind =1
18697 var sameDirection = this.compareCoord(p1[ind],p2[ind]);
18698 if (this.direction || sameDirection
18699 ) {
18700 return this.comparePath(p1, p2);
18701 } else {
18702 if (this.compareCoord(p1[ind],p2[p2.length - (1+ind)])
18703 ) {
18704 return this.comparePath(p1.slice().reverse(), p2);
18705 }
18706 return false;
18707 }
18708};
18709Equality.prototype.fixStartIndex = function(sourcePath,targetPath) {
18710 //make sourcePath first point same as of targetPath
18711 var correctPath,ind = -1;
18712 for (var i=0; i< sourcePath.length; i++) {
18713 if(this.compareCoord(sourcePath[i],targetPath[0])) {
18714 ind = i;
18715 break;
18716 }
18717 }
18718 if (ind >= 0) {
18719 correctPath = [].concat(
18720 sourcePath.slice(ind,sourcePath.length),
18721 sourcePath.slice(1,ind+1));
18722 }
18723 return correctPath;
18724};
18725Equality.prototype.comparePath = function (p1,p2) {
18726 var cont = this;
18727 return p1.every(function(c,i) {
18728 return cont.compareCoord(c,this[i]);
18729 },p2);
18730};
18731
18732Equality.prototype.comparePolygon = function(g1,g2) {
18733 if (this.compareLine(g1.coordinates[0],g2.coordinates[0],1,true)) {
18734 var holes1 = g1.coordinates.slice(1,g1.coordinates.length);
18735 var holes2 = g2.coordinates.slice(1,g2.coordinates.length);
18736 var cont = this;
18737 return holes1.every(function(h1) {
18738 return this.some(function(h2) {
18739 return cont.compareLine(h1,h2,1,true);
18740 });
18741 },holes2);
18742 } else {
18743 return false;
18744 }
18745};
18746
18747Equality.prototype.compareFeature = function(g1,g2) {
18748 if (
18749 g1.id !== g2.id ||
18750 !this.objectComparator(g1.properties, g2.properties) ||
18751 !this.compareBBox(g1,g2)
18752 ) {
18753 return false;
18754 }
18755 return this.compare(g1.geometry, g2.geometry);
18756};
18757
18758Equality.prototype.compareBBox = function(g1,g2) {
18759 if (
18760 (!g1.bbox && !g2.bbox) ||
18761 (
18762 g1.bbox && g2.bbox &&
18763 this.compareCoord(g1.bbox, g2.bbox)
18764 )
18765 ) {
18766 return true;
18767 }
18768 return false;
18769};
18770Equality.prototype.removePseudo = function(path) {
18771 //TODO to be implement
18772 return path;
18773};
18774
18775function objectComparator(obj1, obj2) {
18776 return deepEqual_1(obj1, obj2, {strict: true});
18777}
18778
18779var geojsonEquality = Equality;
18780
18781/**
18782 * Compares two geometries of the same dimension and returns true if their intersection set results in a geometry
18783 * different from both but of the same dimension. It applies to Polygon/Polygon, LineString/LineString,
18784 * Multipoint/Multipoint, MultiLineString/MultiLineString and MultiPolygon/MultiPolygon.
18785 *
18786 * @name booleanOverlap
18787 * @param {Geometry|Feature<LineString|MultiLineString|Polygon|MultiPolygon>} feature1 input
18788 * @param {Geometry|Feature<LineString|MultiLineString|Polygon|MultiPolygon>} feature2 input
18789 * @returns {boolean} true/false
18790 * @example
18791 * var poly1 = turf.polygon([[[0,0],[0,5],[5,5],[5,0],[0,0]]]);
18792 * var poly2 = turf.polygon([[[1,1],[1,6],[6,6],[6,1],[1,1]]]);
18793 * var poly3 = turf.polygon([[[10,10],[10,15],[15,15],[15,10],[10,10]]]);
18794 *
18795 * turf.booleanOverlap(poly1, poly2)
18796 * //=true
18797 * turf.booleanOverlap(poly2, poly3)
18798 * //=false
18799 */
18800function booleanOverlap(feature1, feature2) {
18801 // validation
18802 if (!feature1) throw new Error('feature1 is required');
18803 if (!feature2) throw new Error('feature2 is required');
18804 var type1 = getType(feature1);
18805 var type2 = getType(feature2);
18806 if (type1 !== type2) throw new Error('features must be of the same type');
18807 if (type1 === 'Point') throw new Error('Point geometry not supported');
18808
18809 // features must be not equal
18810 var equality = new geojsonEquality({precision: 6});
18811 if (equality.compare(feature1, feature2)) return false;
18812
18813 var overlap = 0;
18814
18815 switch (type1) {
18816 case 'MultiPoint':
18817 var coords1 = coordAll(feature1);
18818 var coords2 = coordAll(feature2);
18819 coords1.forEach(function (coord1) {
18820 coords2.forEach(function (coord2) {
18821 if (coord1[0] === coord2[0] && coord1[1] === coord2[1]) overlap++;
18822 });
18823 });
18824 break;
18825
18826 case 'LineString':
18827 case 'MultiLineString':
18828 segmentEach(feature1, function (segment1) {
18829 segmentEach(feature2, function (segment2) {
18830 if (lineOverlap(segment1, segment2).features.length) overlap++;
18831 });
18832 });
18833 break;
18834
18835 case 'Polygon':
18836 case 'MultiPolygon':
18837 segmentEach(feature1, function (segment1) {
18838 segmentEach(feature2, function (segment2) {
18839 if (lineIntersect(segment1, segment2).features.length) overlap++;
18840 });
18841 });
18842 break;
18843 }
18844
18845 return overlap > 0;
18846}
18847
18848/**
18849 * Determine whether two geometries of the same type have identical X,Y coordinate values.
18850 * See http://edndoc.esri.com/arcsde/9.0/general_topics/understand_spatial_relations.htm
18851 *
18852 * @name booleanEqual
18853 * @param {Geometry|Feature} feature1 GeoJSON input
18854 * @param {Geometry|Feature} feature2 GeoJSON input
18855 * @returns {boolean} true if the objects are equal, false otherwise
18856 * @example
18857 * var pt1 = turf.point([0, 0]);
18858 * var pt2 = turf.point([0, 0]);
18859 * var pt3 = turf.point([1, 1]);
18860 *
18861 * turf.booleanEqual(pt1, pt2);
18862 * //= true
18863 * turf.booleanEqual(pt2, pt3);
18864 * //= false
18865 */
18866function booleanEqual(feature1, feature2) {
18867 // validation
18868 if (!feature1) throw new Error('feature1 is required');
18869 if (!feature2) throw new Error('feature2 is required');
18870 var type1 = getType(feature1);
18871 var type2 = getType(feature2);
18872 if (type1 !== type2) return false;
18873
18874 var equality = new geojsonEquality({precision: 6});
18875 return equality.compare(cleanCoords(feature1), cleanCoords(feature2));
18876}
18877
18878var DBSCAN_1 = createCommonjsModule(function (module) {
18879/**
18880 * DBSCAN - Density based clustering
18881 *
18882 * @author Lukasz Krawczyk <contact@lukaszkrawczyk.eu>
18883 * @copyright MIT
18884 */
18885
18886/**
18887 * DBSCAN class construcotr
18888 * @constructor
18889 *
18890 * @param {Array} dataset
18891 * @param {number} epsilon
18892 * @param {number} minPts
18893 * @param {function} distanceFunction
18894 * @returns {DBSCAN}
18895 */
18896function DBSCAN(dataset, epsilon, minPts, distanceFunction) {
18897 /** @type {Array} */
18898 this.dataset = [];
18899 /** @type {number} */
18900 this.epsilon = 1;
18901 /** @type {number} */
18902 this.minPts = 2;
18903 /** @type {function} */
18904 this.distance = this._euclideanDistance;
18905 /** @type {Array} */
18906 this.clusters = [];
18907 /** @type {Array} */
18908 this.noise = [];
18909
18910 // temporary variables used during computation
18911
18912 /** @type {Array} */
18913 this._visited = [];
18914 /** @type {Array} */
18915 this._assigned = [];
18916 /** @type {number} */
18917 this._datasetLength = 0;
18918
18919 this._init(dataset, epsilon, minPts, distanceFunction);
18920}
18921
18922/******************************************************************************/
18923// public functions
18924
18925/**
18926 * Start clustering
18927 *
18928 * @param {Array} dataset
18929 * @param {number} epsilon
18930 * @param {number} minPts
18931 * @param {function} distanceFunction
18932 * @returns {undefined}
18933 * @access public
18934 */
18935DBSCAN.prototype.run = function(dataset, epsilon, minPts, distanceFunction) {
18936 this._init(dataset, epsilon, minPts, distanceFunction);
18937
18938 for (var pointId = 0; pointId < this._datasetLength; pointId++) {
18939 // if point is not visited, check if it forms a cluster
18940 if (this._visited[pointId] !== 1) {
18941 this._visited[pointId] = 1;
18942
18943 // if closest neighborhood is too small to form a cluster, mark as noise
18944 var neighbors = this._regionQuery(pointId);
18945
18946 if (neighbors.length < this.minPts) {
18947 this.noise.push(pointId);
18948 } else {
18949 // create new cluster and add point
18950 var clusterId = this.clusters.length;
18951 this.clusters.push([]);
18952 this._addToCluster(pointId, clusterId);
18953
18954 this._expandCluster(clusterId, neighbors);
18955 }
18956 }
18957 }
18958
18959 return this.clusters;
18960};
18961
18962/******************************************************************************/
18963// protected functions
18964
18965/**
18966 * Set object properties
18967 *
18968 * @param {Array} dataset
18969 * @param {number} epsilon
18970 * @param {number} minPts
18971 * @param {function} distance
18972 * @returns {undefined}
18973 * @access protected
18974 */
18975DBSCAN.prototype._init = function(dataset, epsilon, minPts, distance) {
18976
18977 if (dataset) {
18978
18979 if (!(dataset instanceof Array)) {
18980 throw Error('Dataset must be of type array, ' +
18981 typeof dataset + ' given');
18982 }
18983
18984 this.dataset = dataset;
18985 this.clusters = [];
18986 this.noise = [];
18987
18988 this._datasetLength = dataset.length;
18989 this._visited = new Array(this._datasetLength);
18990 this._assigned = new Array(this._datasetLength);
18991 }
18992
18993 if (epsilon) {
18994 this.epsilon = epsilon;
18995 }
18996
18997 if (minPts) {
18998 this.minPts = minPts;
18999 }
19000
19001 if (distance) {
19002 this.distance = distance;
19003 }
19004};
19005
19006/**
19007 * Expand cluster to closest points of given neighborhood
19008 *
19009 * @param {number} clusterId
19010 * @param {Array} neighbors
19011 * @returns {undefined}
19012 * @access protected
19013 */
19014DBSCAN.prototype._expandCluster = function(clusterId, neighbors) {
19015
19016 /**
19017 * It's very important to calculate length of neighbors array each time,
19018 * as the number of elements changes over time
19019 */
19020 for (var i = 0; i < neighbors.length; i++) {
19021 var pointId2 = neighbors[i];
19022
19023 if (this._visited[pointId2] !== 1) {
19024 this._visited[pointId2] = 1;
19025 var neighbors2 = this._regionQuery(pointId2);
19026
19027 if (neighbors2.length >= this.minPts) {
19028 neighbors = this._mergeArrays(neighbors, neighbors2);
19029 }
19030 }
19031
19032 // add to cluster
19033 if (this._assigned[pointId2] !== 1) {
19034 this._addToCluster(pointId2, clusterId);
19035 }
19036 }
19037};
19038
19039/**
19040 * Add new point to cluster
19041 *
19042 * @param {number} pointId
19043 * @param {number} clusterId
19044 */
19045DBSCAN.prototype._addToCluster = function(pointId, clusterId) {
19046 this.clusters[clusterId].push(pointId);
19047 this._assigned[pointId] = 1;
19048};
19049
19050/**
19051 * Find all neighbors around given point
19052 *
19053 * @param {number} pointId,
19054 * @param {number} epsilon
19055 * @returns {Array}
19056 * @access protected
19057 */
19058DBSCAN.prototype._regionQuery = function(pointId) {
19059 var neighbors = [];
19060
19061 for (var id = 0; id < this._datasetLength; id++) {
19062 var dist = this.distance(this.dataset[pointId], this.dataset[id]);
19063 if (dist < this.epsilon) {
19064 neighbors.push(id);
19065 }
19066 }
19067
19068 return neighbors;
19069};
19070
19071/******************************************************************************/
19072// helpers
19073
19074/**
19075 * @param {Array} a
19076 * @param {Array} b
19077 * @returns {Array}
19078 * @access protected
19079 */
19080DBSCAN.prototype._mergeArrays = function(a, b) {
19081 var len = b.length;
19082
19083 for (var i = 0; i < len; i++) {
19084 var P = b[i];
19085 if (a.indexOf(P) < 0) {
19086 a.push(P);
19087 }
19088 }
19089
19090 return a;
19091};
19092
19093/**
19094 * Calculate euclidean distance in multidimensional space
19095 *
19096 * @param {Array} p
19097 * @param {Array} q
19098 * @returns {number}
19099 * @access protected
19100 */
19101DBSCAN.prototype._euclideanDistance = function(p, q) {
19102 var sum = 0;
19103 var i = Math.min(p.length, q.length);
19104
19105 while (i--) {
19106 sum += (p[i] - q[i]) * (p[i] - q[i]);
19107 }
19108
19109 return Math.sqrt(sum);
19110};
19111
19112if ('object' !== 'undefined' && module.exports) {
19113 module.exports = DBSCAN;
19114}
19115});
19116
19117var KMEANS_1 = createCommonjsModule(function (module) {
19118/**
19119 * KMEANS clustering
19120 *
19121 * @author Lukasz Krawczyk <contact@lukaszkrawczyk.eu>
19122 * @copyright MIT
19123 */
19124
19125/**
19126 * KMEANS class constructor
19127 * @constructor
19128 *
19129 * @param {Array} dataset
19130 * @param {number} k - number of clusters
19131 * @param {function} distance - distance function
19132 * @returns {KMEANS}
19133 */
19134 function KMEANS(dataset, k, distance) {
19135 this.k = 3; // number of clusters
19136 this.dataset = []; // set of feature vectors
19137 this.assignments = []; // set of associated clusters for each feature vector
19138 this.centroids = []; // vectors for our clusters
19139
19140 this.init(dataset, k, distance);
19141}
19142
19143/**
19144 * @returns {undefined}
19145 */
19146KMEANS.prototype.init = function(dataset, k, distance) {
19147 this.assignments = [];
19148 this.centroids = [];
19149
19150 if (typeof dataset !== 'undefined') {
19151 this.dataset = dataset;
19152 }
19153
19154 if (typeof k !== 'undefined') {
19155 this.k = k;
19156 }
19157
19158 if (typeof distance !== 'undefined') {
19159 this.distance = distance;
19160 }
19161};
19162
19163/**
19164 * @returns {undefined}
19165 */
19166KMEANS.prototype.run = function(dataset, k) {
19167 this.init(dataset, k);
19168
19169 var len = this.dataset.length;
19170
19171 // initialize centroids
19172 for (var i = 0; i < this.k; i++) {
19173 this.centroids[i] = this.randomCentroid();
19174 }
19175
19176 var change = true;
19177 while(change) {
19178
19179 // assign feature vectors to clusters
19180 change = this.assign();
19181
19182 // adjust location of centroids
19183 for (var centroidId = 0; centroidId < this.k; centroidId++) {
19184 var mean = new Array(maxDim);
19185 var count = 0;
19186
19187 // init mean vector
19188 for (var dim = 0; dim < maxDim; dim++) {
19189 mean[dim] = 0;
19190 }
19191
19192 for (var j = 0; j < len; j++) {
19193 var maxDim = this.dataset[j].length;
19194
19195 // if current cluster id is assigned to point
19196 if (centroidId === this.assignments[j]) {
19197 for (var dim = 0; dim < maxDim; dim++) {
19198 mean[dim] += this.dataset[j][dim];
19199 }
19200 count++;
19201 }
19202 }
19203
19204 if (count > 0) {
19205 // if cluster contain points, adjust centroid position
19206 for (var dim = 0; dim < maxDim; dim++) {
19207 mean[dim] /= count;
19208 }
19209 this.centroids[centroidId] = mean;
19210 } else {
19211 // if cluster is empty, generate new random centroid
19212 this.centroids[centroidId] = this.randomCentroid();
19213 change = true;
19214 }
19215 }
19216 }
19217
19218 return this.getClusters();
19219};
19220
19221/**
19222 * Generate random centroid
19223 *
19224 * @returns {Array}
19225 */
19226KMEANS.prototype.randomCentroid = function() {
19227 var maxId = this.dataset.length -1;
19228 var centroid;
19229 var id;
19230
19231 do {
19232 id = Math.round(Math.random() * maxId);
19233 centroid = this.dataset[id];
19234 } while (this.centroids.indexOf(centroid) >= 0);
19235
19236 return centroid;
19237};
19238
19239/**
19240 * Assign points to clusters
19241 *
19242 * @returns {boolean}
19243 */
19244KMEANS.prototype.assign = function() {
19245 var change = false;
19246 var len = this.dataset.length;
19247 var closestCentroid;
19248
19249 for (var i = 0; i < len; i++) {
19250 closestCentroid = this.argmin(this.dataset[i], this.centroids, this.distance);
19251
19252 if (closestCentroid != this.assignments[i]) {
19253 this.assignments[i] = closestCentroid;
19254 change = true;
19255 }
19256 }
19257
19258 return change;
19259};
19260
19261/**
19262 * Extract information about clusters
19263 *
19264 * @returns {undefined}
19265 */
19266KMEANS.prototype.getClusters = function() {
19267 var clusters = new Array(this.k);
19268 var centroidId;
19269
19270 for (var pointId = 0; pointId < this.assignments.length; pointId++) {
19271 centroidId = this.assignments[pointId];
19272
19273 // init empty cluster
19274 if (typeof clusters[centroidId] === 'undefined') {
19275 clusters[centroidId] = [];
19276 }
19277
19278 clusters[centroidId].push(pointId);
19279 }
19280
19281 return clusters;
19282};
19283
19284// utils
19285
19286/**
19287 * @params {Array} point
19288 * @params {Array.<Array>} set
19289 * @params {Function} f
19290 * @returns {number}
19291 */
19292KMEANS.prototype.argmin = function(point, set, f) {
19293 var min = Number.MAX_VALUE;
19294 var arg = 0;
19295 var len = set.length;
19296 var d;
19297
19298 for (var i = 0; i < len; i++) {
19299 d = f(point, set[i]);
19300 if (d < min) {
19301 min = d;
19302 arg = i;
19303 }
19304 }
19305
19306 return arg;
19307};
19308
19309/**
19310 * Euclidean distance
19311 *
19312 * @params {number} p
19313 * @params {number} q
19314 * @returns {number}
19315 */
19316KMEANS.prototype.distance = function(p, q) {
19317 var sum = 0;
19318 var i = Math.min(p.length, q.length);
19319
19320 while (i--) {
19321 var diff = p[i] - q[i];
19322 sum += diff * diff;
19323 }
19324
19325 return Math.sqrt(sum);
19326};
19327
19328if ('object' !== 'undefined' && module.exports) {
19329 module.exports = KMEANS;
19330}
19331});
19332
19333var PriorityQueue_1 = createCommonjsModule(function (module) {
19334/**
19335 * PriorityQueue
19336 * Elements in this queue are sorted according to their value
19337 *
19338 * @author Lukasz Krawczyk <contact@lukaszkrawczyk.eu>
19339 * @copyright MIT
19340 */
19341
19342/**
19343 * PriorityQueue class construcotr
19344 * @constructor
19345 *
19346 * @example
19347 * queue: [1,2,3,4]
19348 * priorities: [4,1,2,3]
19349 * > result = [1,4,2,3]
19350 *
19351 * @param {Array} elements
19352 * @param {Array} priorities
19353 * @param {string} sorting - asc / desc
19354 * @returns {PriorityQueue}
19355 */
19356function PriorityQueue(elements, priorities, sorting) {
19357 /** @type {Array} */
19358 this._queue = [];
19359 /** @type {Array} */
19360 this._priorities = [];
19361 /** @type {string} */
19362 this._sorting = 'desc';
19363
19364 this._init(elements, priorities, sorting);
19365}
19366
19367/**
19368 * Insert element
19369 *
19370 * @param {Object} ele
19371 * @param {Object} priority
19372 * @returns {undefined}
19373 * @access public
19374 */
19375PriorityQueue.prototype.insert = function(ele, priority) {
19376 var indexToInsert = this._queue.length;
19377 var index = indexToInsert;
19378
19379 while (index--) {
19380 var priority2 = this._priorities[index];
19381 if (this._sorting === 'desc') {
19382 if (priority > priority2) {
19383 indexToInsert = index;
19384 }
19385 } else {
19386 if (priority < priority2) {
19387 indexToInsert = index;
19388 }
19389 }
19390 }
19391
19392 this._insertAt(ele, priority, indexToInsert);
19393};
19394
19395/**
19396 * Remove element
19397 *
19398 * @param {Object} ele
19399 * @returns {undefined}
19400 * @access public
19401 */
19402PriorityQueue.prototype.remove = function(ele) {
19403 var index = this._queue.length;
19404
19405 while (index--) {
19406 var ele2 = this._queue[index];
19407 if (ele === ele2) {
19408 this._queue.splice(index, 1);
19409 this._priorities.splice(index, 1);
19410 break;
19411 }
19412 }
19413};
19414
19415/**
19416 * For each loop wrapper
19417 *
19418 * @param {function} func
19419 * @returs {undefined}
19420 * @access public
19421 */
19422PriorityQueue.prototype.forEach = function(func) {
19423 this._queue.forEach(func);
19424};
19425
19426/**
19427 * @returns {Array}
19428 * @access public
19429 */
19430PriorityQueue.prototype.getElements = function() {
19431 return this._queue;
19432};
19433
19434/**
19435 * @param {number} index
19436 * @returns {Object}
19437 * @access public
19438 */
19439PriorityQueue.prototype.getElementPriority = function(index) {
19440 return this._priorities[index];
19441};
19442
19443/**
19444 * @returns {Array}
19445 * @access public
19446 */
19447PriorityQueue.prototype.getPriorities = function() {
19448 return this._priorities;
19449};
19450
19451/**
19452 * @returns {Array}
19453 * @access public
19454 */
19455PriorityQueue.prototype.getElementsWithPriorities = function() {
19456 var result = [];
19457
19458 for (var i = 0, l = this._queue.length; i < l; i++) {
19459 result.push([this._queue[i], this._priorities[i]]);
19460 }
19461
19462 return result;
19463};
19464
19465/**
19466 * Set object properties
19467 *
19468 * @param {Array} elements
19469 * @param {Array} priorities
19470 * @returns {undefined}
19471 * @access protected
19472 */
19473PriorityQueue.prototype._init = function(elements, priorities, sorting) {
19474
19475 if (elements && priorities) {
19476 this._queue = [];
19477 this._priorities = [];
19478
19479 if (elements.length !== priorities.length) {
19480 throw new Error('Arrays must have the same length');
19481 }
19482
19483 for (var i = 0; i < elements.length; i++) {
19484 this.insert(elements[i], priorities[i]);
19485 }
19486 }
19487
19488 if (sorting) {
19489 this._sorting = sorting;
19490 }
19491};
19492
19493/**
19494 * Insert element at given position
19495 *
19496 * @param {Object} ele
19497 * @param {number} index
19498 * @returns {undefined}
19499 * @access protected
19500 */
19501PriorityQueue.prototype._insertAt = function(ele, priority, index) {
19502 if (this._queue.length === index) {
19503 this._queue.push(ele);
19504 this._priorities.push(priority);
19505 } else {
19506 this._queue.splice(index, 0, ele);
19507 this._priorities.splice(index, 0, priority);
19508 }
19509};
19510
19511if ('object' !== 'undefined' && module.exports) {
19512 module.exports = PriorityQueue;
19513}
19514});
19515
19516var OPTICS_1 = createCommonjsModule(function (module) {
19517/**
19518 * @requires ./PriorityQueue.js
19519 */
19520
19521if ('object' !== 'undefined' && module.exports) {
19522 var PriorityQueue = PriorityQueue_1;
19523}
19524
19525/**
19526 * OPTICS - Ordering points to identify the clustering structure
19527 *
19528 * @author Lukasz Krawczyk <contact@lukaszkrawczyk.eu>
19529 * @copyright MIT
19530 */
19531
19532/**
19533 * OPTICS class constructor
19534 * @constructor
19535 *
19536 * @param {Array} dataset
19537 * @param {number} epsilon
19538 * @param {number} minPts
19539 * @param {function} distanceFunction
19540 * @returns {OPTICS}
19541 */
19542function OPTICS(dataset, epsilon, minPts, distanceFunction) {
19543 /** @type {number} */
19544 this.epsilon = 1;
19545 /** @type {number} */
19546 this.minPts = 1;
19547 /** @type {function} */
19548 this.distance = this._euclideanDistance;
19549
19550 // temporary variables used during computation
19551
19552 /** @type {Array} */
19553 this._reachability = [];
19554 /** @type {Array} */
19555 this._processed = [];
19556 /** @type {number} */
19557 this._coreDistance = 0;
19558 /** @type {Array} */
19559 this._orderedList = [];
19560
19561 this._init(dataset, epsilon, minPts, distanceFunction);
19562}
19563
19564/******************************************************************************/
19565// pulic functions
19566
19567/**
19568 * Start clustering
19569 *
19570 * @param {Array} dataset
19571 * @returns {undefined}
19572 * @access public
19573 */
19574OPTICS.prototype.run = function(dataset, epsilon, minPts, distanceFunction) {
19575 this._init(dataset, epsilon, minPts, distanceFunction);
19576
19577 for (var pointId = 0, l = this.dataset.length; pointId < l; pointId++) {
19578 if (this._processed[pointId] !== 1) {
19579 this._processed[pointId] = 1;
19580 this.clusters.push([pointId]);
19581 var clusterId = this.clusters.length - 1;
19582
19583 this._orderedList.push(pointId);
19584 var priorityQueue = new PriorityQueue(null, null, 'asc');
19585 var neighbors = this._regionQuery(pointId);
19586
19587 // using priority queue assign elements to new cluster
19588 if (this._distanceToCore(pointId) !== undefined) {
19589 this._updateQueue(pointId, neighbors, priorityQueue);
19590 this._expandCluster(clusterId, priorityQueue);
19591 }
19592 }
19593 }
19594
19595 return this.clusters;
19596};
19597
19598/**
19599 * Generate reachability plot for all points
19600 *
19601 * @returns {array}
19602 * @access public
19603 */
19604OPTICS.prototype.getReachabilityPlot = function() {
19605 var reachabilityPlot = [];
19606
19607 for (var i = 0, l = this._orderedList.length; i < l; i++) {
19608 var pointId = this._orderedList[i];
19609 var distance = this._reachability[pointId];
19610
19611 reachabilityPlot.push([pointId, distance]);
19612 }
19613
19614 return reachabilityPlot;
19615};
19616
19617/******************************************************************************/
19618// protected functions
19619
19620/**
19621 * Set object properties
19622 *
19623 * @param {Array} dataset
19624 * @param {number} epsilon
19625 * @param {number} minPts
19626 * @param {function} distance
19627 * @returns {undefined}
19628 * @access protected
19629 */
19630OPTICS.prototype._init = function(dataset, epsilon, minPts, distance) {
19631
19632 if (dataset) {
19633
19634 if (!(dataset instanceof Array)) {
19635 throw Error('Dataset must be of type array, ' +
19636 typeof dataset + ' given');
19637 }
19638
19639 this.dataset = dataset;
19640 this.clusters = [];
19641 this._reachability = new Array(this.dataset.length);
19642 this._processed = new Array(this.dataset.length);
19643 this._coreDistance = 0;
19644 this._orderedList = [];
19645 }
19646
19647 if (epsilon) {
19648 this.epsilon = epsilon;
19649 }
19650
19651 if (minPts) {
19652 this.minPts = minPts;
19653 }
19654
19655 if (distance) {
19656 this.distance = distance;
19657 }
19658};
19659
19660/**
19661 * Update information in queue
19662 *
19663 * @param {number} pointId
19664 * @param {Array} neighbors
19665 * @param {PriorityQueue} queue
19666 * @returns {undefined}
19667 * @access protected
19668 */
19669OPTICS.prototype._updateQueue = function(pointId, neighbors, queue) {
19670 var self = this;
19671
19672 this._coreDistance = this._distanceToCore(pointId);
19673 neighbors.forEach(function(pointId2) {
19674 if (self._processed[pointId2] === undefined) {
19675 var dist = self.distance(self.dataset[pointId], self.dataset[pointId2]);
19676 var newReachableDistance = Math.max(self._coreDistance, dist);
19677
19678 if (self._reachability[pointId2] === undefined) {
19679 self._reachability[pointId2] = newReachableDistance;
19680 queue.insert(pointId2, newReachableDistance);
19681 } else {
19682 if (newReachableDistance < self._reachability[pointId2]) {
19683 self._reachability[pointId2] = newReachableDistance;
19684 queue.remove(pointId2);
19685 queue.insert(pointId2, newReachableDistance);
19686 }
19687 }
19688 }
19689 });
19690};
19691
19692/**
19693 * Expand cluster
19694 *
19695 * @param {number} clusterId
19696 * @param {PriorityQueue} queue
19697 * @returns {undefined}
19698 * @access protected
19699 */
19700OPTICS.prototype._expandCluster = function(clusterId, queue) {
19701 var queueElements = queue.getElements();
19702
19703 for (var p = 0, l = queueElements.length; p < l; p++) {
19704 var pointId = queueElements[p];
19705 if (this._processed[pointId] === undefined) {
19706 var neighbors = this._regionQuery(pointId);
19707 this._processed[pointId] = 1;
19708
19709 this.clusters[clusterId].push(pointId);
19710 this._orderedList.push(pointId);
19711
19712 if (this._distanceToCore(pointId) !== undefined) {
19713 this._updateQueue(pointId, neighbors, queue);
19714 this._expandCluster(clusterId, queue);
19715 }
19716 }
19717 }
19718};
19719
19720/**
19721 * Calculating distance to cluster core
19722 *
19723 * @param {number} pointId
19724 * @returns {number}
19725 * @access protected
19726 */
19727OPTICS.prototype._distanceToCore = function(pointId) {
19728 var l = this.epsilon;
19729 for (var coreDistCand = 0; coreDistCand < l; coreDistCand++) {
19730 var neighbors = this._regionQuery(pointId, coreDistCand);
19731 if (neighbors.length >= this.minPts) {
19732 return coreDistCand;
19733 }
19734 }
19735
19736 return;
19737};
19738
19739/**
19740 * Find all neighbors around given point
19741 *
19742 * @param {number} pointId
19743 * @param {number} epsilon
19744 * @returns {Array}
19745 * @access protected
19746 */
19747OPTICS.prototype._regionQuery = function(pointId, epsilon) {
19748 epsilon = epsilon || this.epsilon;
19749 var neighbors = [];
19750
19751 for (var id = 0, l = this.dataset.length; id < l; id++) {
19752 if (this.distance(this.dataset[pointId], this.dataset[id]) < epsilon) {
19753 neighbors.push(id);
19754 }
19755 }
19756
19757 return neighbors;
19758};
19759
19760/******************************************************************************/
19761// helpers
19762
19763/**
19764 * Calculate euclidean distance in multidimensional space
19765 *
19766 * @param {Array} p
19767 * @param {Array} q
19768 * @returns {number}
19769 * @access protected
19770 */
19771OPTICS.prototype._euclideanDistance = function(p, q) {
19772 var sum = 0;
19773 var i = Math.min(p.length, q.length);
19774
19775 while (i--) {
19776 sum += (p[i] - q[i]) * (p[i] - q[i]);
19777 }
19778
19779 return Math.sqrt(sum);
19780};
19781
19782if ('object' !== 'undefined' && module.exports) {
19783 module.exports = OPTICS;
19784}
19785});
19786
19787var lib = createCommonjsModule(function (module) {
19788if ('object' !== 'undefined' && module.exports) {
19789 module.exports = {
19790 DBSCAN: DBSCAN_1,
19791 KMEANS: KMEANS_1,
19792 OPTICS: OPTICS_1,
19793 PriorityQueue: PriorityQueue_1
19794 };
19795}
19796});
19797
19798var lib_1 = lib.DBSCAN;
19799var lib_2 = lib.KMEANS;
19800var lib_3 = lib.OPTICS;
19801var lib_4 = lib.PriorityQueue;
19802
19803/**
19804 * Takes a set of {@link Point|points} and partition them into clusters according to {@link DBSCAN's|https://en.wikipedia.org/wiki/DBSCAN} data clustering algorithm.
19805 *
19806 * @name clustersDbscan
19807 * @param {FeatureCollection<Point>} points to be clustered
19808 * @param {number} maxDistance Maximum Distance between any point of the cluster to generate the clusters (kilometers only)
19809 * @param {Object} [options={}] Optional parameters
19810 * @param {string} [options.units=kilometers] in which `maxDistance` is expressed, can be degrees, radians, miles, or kilometers
19811 * @param {number} [options.minPoints=3] Minimum number of points to generate a single cluster,
19812 * points which do not meet this requirement will be classified as an 'edge' or 'noise'.
19813 * @returns {FeatureCollection<Point>} Clustered Points with an additional two properties associated to each Feature:
19814 * - {number} cluster - the associated clusterId
19815 * - {string} dbscan - type of point it has been classified as ('core'|'edge'|'noise')
19816 * @example
19817 * // create random points with random z-values in their properties
19818 * var points = turf.randomPoint(100, {bbox: [0, 30, 20, 50]});
19819 * var maxDistance = 100;
19820 * var clustered = turf.clustersDbscan(points, maxDistance);
19821 *
19822 * //addToMap
19823 * var addToMap = [clustered];
19824 */
19825function clustersDbscan(points$$1, maxDistance, options) {
19826 // Optional parameters
19827 options = options || {};
19828 if (typeof options !== 'object') throw new Error('options is invalid');
19829 var minPoints = options.minPoints;
19830 var units = options.units;
19831
19832 // Input validation
19833 collectionOf(points$$1, 'Point', 'Input must contain Points');
19834 if (maxDistance === null || maxDistance === undefined) throw new Error('maxDistance is required');
19835 if (!(Math.sign(maxDistance) > 0)) throw new Error('Invalid maxDistance');
19836 if (!(minPoints === undefined || minPoints === null || Math.sign(minPoints) > 0)) throw new Error('Invalid minPoints');
19837
19838 // Clone points to prevent any mutations
19839 points$$1 = clone(points$$1, true);
19840
19841 // Defaults
19842 minPoints = minPoints || 3;
19843
19844 // create clustered ids
19845 var dbscan = new lib.DBSCAN();
19846 var clusteredIds = dbscan.run(coordAll(points$$1), convertLength(maxDistance, units), minPoints, distance);
19847
19848 // Tag points to Clusters ID
19849 var clusterId = -1;
19850 clusteredIds.forEach(function (clusterIds) {
19851 clusterId++;
19852 // assign cluster ids to input points
19853 clusterIds.forEach(function (idx) {
19854 var clusterPoint = points$$1.features[idx];
19855 if (!clusterPoint.properties) clusterPoint.properties = {};
19856 clusterPoint.properties.cluster = clusterId;
19857 clusterPoint.properties.dbscan = 'core';
19858 });
19859 });
19860
19861 // handle noise points, if any
19862 // edges points are tagged by DBSCAN as both 'noise' and 'cluster' as they can "reach" less than 'minPoints' number of points
19863 dbscan.noise.forEach(function (noiseId) {
19864 var noisePoint = points$$1.features[noiseId];
19865 if (!noisePoint.properties) noisePoint.properties = {};
19866 if (noisePoint.properties.cluster) noisePoint.properties.dbscan = 'edge';
19867 else noisePoint.properties.dbscan = 'noise';
19868 });
19869
19870 return points$$1;
19871}
19872
19873var distance$2 = {
19874 /**
19875 * Euclidean distance
19876 */
19877 eudist: function eudist(v1, v2, sqrt) {
19878 var len = v1.length;
19879 var sum = 0;
19880
19881 for (var i = 0; i < len; i++) {
19882 var d = (v1[i] || 0) - (v2[i] || 0);
19883 sum += d * d;
19884 }
19885 // Square root not really needed
19886 return sqrt ? Math.sqrt(sum) : sum;
19887 },
19888 mandist: function mandist(v1, v2, sqrt) {
19889 var len = v1.length;
19890 var sum = 0;
19891
19892 for (var i = 0; i < len; i++) {
19893 sum += Math.abs((v1[i] || 0) - (v2[i] || 0));
19894 }
19895
19896 // Square root not really needed
19897 return sqrt ? Math.sqrt(sum) : sum;
19898 },
19899
19900
19901 /**
19902 * Unidimensional distance
19903 */
19904 dist: function dist(v1, v2, sqrt) {
19905 var d = Math.abs(v1 - v2);
19906 return sqrt ? d : d * d;
19907 }
19908};
19909
19910var eudist$1 = distance$2.eudist;
19911var dist$1 = distance$2.dist;
19912
19913var kinit = {
19914 kmrand: function kmrand(data, k) {
19915 var map = {},
19916 ks = [],
19917 t = k << 2;
19918 var len = data.length;
19919 var multi = data[0].length > 0;
19920
19921 while (ks.length < k && t-- > 0) {
19922 var d = data[Math.floor(Math.random() * len)];
19923 var key = multi ? d.join("_") : "" + d;
19924 if (!map[key]) {
19925 map[key] = true;
19926 ks.push(d);
19927 }
19928 }
19929
19930 if (ks.length < k) throw new Error("Error initializating clusters");else return ks;
19931 },
19932
19933
19934 /**
19935 * K-means++ initial centroid selection
19936 */
19937 kmpp: function kmpp(data, k) {
19938 var distance = data[0].length ? eudist$1 : dist$1;
19939 var ks = [],
19940 len = data.length;
19941 var multi = data[0].length > 0;
19942 var c = data[Math.floor(Math.random() * len)];
19943 var key = multi ? c.join("_") : "" + c;
19944 ks.push(c);
19945 while (ks.length < k) {
19946 // Min Distances between current centroids and data points
19947 var dists = [],
19948 lk = ks.length;
19949 var dsum = 0,
19950 prs = [];
19951
19952 for (var i = 0; i < len; i++) {
19953 var min = Infinity;
19954 for (var j = 0; j < lk; j++) {
19955 var _dist = distance(data[i], ks[j]);
19956 if (_dist <= min) min = _dist;
19957 }
19958 dists[i] = min;
19959 }
19960
19961 // Sum all min distances
19962 for (var _i = 0; _i < len; _i++) {
19963 dsum += dists[_i];
19964 }
19965
19966 // Probabilities and cummulative prob (cumsum)
19967 for (var _i2 = 0; _i2 < len; _i2++) {
19968 prs[_i2] = { i: _i2, v: data[_i2], pr: dists[_i2] / dsum, cs: 0 };
19969 }
19970
19971 // Sort Probabilities
19972 prs.sort(function (a, b) {
19973 return a.pr - b.pr;
19974 });
19975
19976 // Cummulative Probabilities
19977 prs[0].cs = prs[0].pr;
19978 for (var _i3 = 1; _i3 < len; _i3++) {
19979 prs[_i3].cs = prs[_i3 - 1].cs + prs[_i3].pr;
19980 }
19981
19982 // Randomize
19983 var rnd = Math.random();
19984
19985 // Gets only the items whose cumsum >= rnd
19986 var idx = 0;
19987 while (idx < len - 1 && prs[idx++].cs < rnd) {}
19988 ks.push(prs[idx - 1].v);
19989 /*
19990 let done = false;
19991 while(!done) {
19992 // this is our new centroid
19993 c = prs[idx-1].v
19994 key = multi? c.join("_") : `${c}`;
19995 if(!map[key]) {
19996 map[key] = true;
19997 ks.push(c);
19998 done = true;
19999 }
20000 else {
20001 idx++;
20002 }
20003 }
20004 */
20005 }
20006
20007 return ks;
20008 }
20009};
20010
20011/*jshint esversion: 6 */
20012
20013var eudist = distance$2.eudist;
20014var kmrand = kinit.kmrand;
20015var kmpp = kinit.kmpp;
20016
20017var MAX = 10000;
20018
20019/**
20020 * Inits an array with values
20021 */
20022function init(len, val, v) {
20023 v = v || [];
20024 for (var i = 0; i < len; i++) {
20025 v[i] = val;
20026 }return v;
20027}
20028
20029function skmeans(data, k, initial, maxit) {
20030 var ks = [],
20031 old = [],
20032 idxs = [],
20033 dist = [];
20034 var conv = false,
20035 it = maxit || MAX;
20036 var len = data.length,
20037 vlen = data[0].length,
20038 multi = vlen > 0;
20039 var count = [];
20040
20041 if (!initial) {
20042 var _idxs = {};
20043 while (ks.length < k) {
20044 var idx = Math.floor(Math.random() * len);
20045 if (!_idxs[idx]) {
20046 _idxs[idx] = true;
20047 ks.push(data[idx]);
20048 }
20049 }
20050 } else if (initial == "kmrand") {
20051 ks = kmrand(data, k);
20052 } else if (initial == "kmpp") {
20053 ks = kmpp(data, k);
20054 } else {
20055 ks = initial;
20056 }
20057
20058 do {
20059 // Reset k count
20060 init(k, 0, count);
20061
20062 // For each value in data, find the nearest centroid
20063 for (var i = 0; i < len; i++) {
20064 var min = Infinity,
20065 _idx = 0;
20066 for (var j = 0; j < k; j++) {
20067 // Multidimensional or unidimensional
20068 var dist = multi ? eudist(data[i], ks[j]) : Math.abs(data[i] - ks[j]);
20069 if (dist <= min) {
20070 min = dist;
20071 _idx = j;
20072 }
20073 }
20074 idxs[i] = _idx; // Index of the selected centroid for that value
20075 count[_idx]++; // Number of values for this centroid
20076 }
20077
20078 // Recalculate centroids
20079 var sum = [],
20080 old = [];
20081 for (var _j = 0; _j < k; _j++) {
20082 // Multidimensional or unidimensional
20083 sum[_j] = multi ? init(vlen, 0, sum[_j]) : 0;
20084 old[_j] = ks[_j];
20085 }
20086
20087 // If multidimensional
20088 if (multi) {
20089 for (var _j2 = 0; _j2 < k; _j2++) {
20090 ks[_j2] = [];
20091 } // Sum values and count for each centroid
20092 for (var _i = 0; _i < len; _i++) {
20093 var _idx2 = idxs[_i],
20094 // Centroid for that item
20095 vsum = sum[_idx2],
20096 // Sum values for this centroid
20097 vect = data[_i]; // Current vector
20098
20099 // Accumulate value on the centroid for current vector
20100 for (var h = 0; h < vlen; h++) {
20101 vsum[h] += vect[h];
20102 }
20103 }
20104 // Calculate the average for each centroid
20105 conv = true;
20106 for (var _j3 = 0; _j3 < k; _j3++) {
20107 var ksj = ks[_j3],
20108 // Current centroid
20109 sumj = sum[_j3],
20110 // Accumulated centroid values
20111 oldj = old[_j3],
20112 // Old centroid value
20113 cj = count[_j3]; // Number of elements for this centroid
20114
20115 // New average
20116 for (var _h = 0; _h < vlen; _h++) {
20117 ksj[_h] = sumj[_h] / cj || 0; // New centroid
20118 }
20119
20120 // Find if centroids have moved
20121 if (conv) {
20122 for (var _h2 = 0; _h2 < vlen; _h2++) {
20123 if (oldj[_h2] != ksj[_h2]) {
20124 conv = false;
20125 break;
20126 }
20127 }
20128 }
20129 }
20130 }
20131 // If unidimensional
20132 else {
20133 // Sum values and count for each centroid
20134 for (var _i2 = 0; _i2 < len; _i2++) {
20135 var _idx3 = idxs[_i2];
20136 sum[_idx3] += data[_i2];
20137 }
20138 // Calculate the average for each centroid
20139 for (var _j4 = 0; _j4 < k; _j4++) {
20140 ks[_j4] = sum[_j4] / count[_j4] || 0; // New centroid
20141 }
20142 // Find if centroids have moved
20143 conv = true;
20144 for (var _j5 = 0; _j5 < k; _j5++) {
20145 if (old[_j5] != ks[_j5]) {
20146 conv = false;
20147 break;
20148 }
20149 }
20150 }
20151
20152 conv = conv || --it <= 0;
20153 } while (!conv);
20154
20155 return {
20156 it: MAX - it,
20157 k: k,
20158 idxs: idxs,
20159 centroids: ks
20160 };
20161}
20162
20163var main = skmeans;
20164
20165/**
20166 * Takes a set of {@link Point|points} and partition them into clusters using the k-mean .
20167 * It uses the [k-means algorithm](https://en.wikipedia.org/wiki/K-means_clustering)
20168 *
20169 * @name clustersKmeans
20170 * @param {FeatureCollection<Point>} points to be clustered
20171 * @param {Object} [options={}] Optional parameters
20172 * @param {number} [options.numberOfClusters=Math.sqrt(numberOfPoints/2)] numberOfClusters that will be generated
20173 * @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated (significant performance increase if true)
20174 * @returns {FeatureCollection<Point>} Clustered Points with an additional two properties associated to each Feature:
20175 * - {number} cluster - the associated clusterId
20176 * - {[number, number]} centroid - Centroid of the cluster [Longitude, Latitude]
20177 * @example
20178 * // create random points with random z-values in their properties
20179 * var points = turf.randomPoint(100, {bbox: [0, 30, 20, 50]});
20180 * var options = {numberOfClusters: 7};
20181 * var clustered = turf.clustersKmeans(points, options);
20182 *
20183 * //addToMap
20184 * var addToMap = [clustered];
20185 */
20186function clustersKmeans(points, options) {
20187 // Optional parameters
20188 options = options || {};
20189 if (typeof options !== 'object') throw new Error('options is invalid');
20190 var numberOfClusters = options.numberOfClusters;
20191 var mutate = options.mutate;
20192
20193 // Input validation
20194 collectionOf(points, 'Point', 'Input must contain Points');
20195
20196 // Default Params
20197 var count = points.features.length;
20198 numberOfClusters = numberOfClusters || Math.round(Math.sqrt(count / 2));
20199
20200 // numberOfClusters can't be greater than the number of points
20201 // fallbacks to count
20202 if (numberOfClusters > count) numberOfClusters = count;
20203
20204 // Clone points to prevent any mutations (enabled by default)
20205 if (mutate === false || mutate === undefined) points = clone(points, true);
20206
20207 // collect points coordinates
20208 var data = coordAll(points);
20209
20210 // create seed to avoid skmeans to drift
20211 var initialCentroids = data.slice(0, numberOfClusters);
20212
20213 // create skmeans clusters
20214 var skmeansResult = main(data, numberOfClusters, initialCentroids);
20215
20216 // store centroids {clusterId: [number, number]}
20217 var centroids = {};
20218 skmeansResult.centroids.forEach(function (coord, idx) {
20219 centroids[idx] = coord;
20220 });
20221
20222 // add associated cluster number
20223 featureEach(points, function (point, index) {
20224 var clusterId = skmeansResult.idxs[index];
20225 point.properties.cluster = clusterId;
20226 point.properties.centroid = centroids[clusterId];
20227 });
20228
20229 return points;
20230}
20231
20232/**
20233 * Boolean-Parallel returns True if each segment of `line1` is parallel to the correspondent segment of `line2`
20234 *
20235 * @name booleanParallel
20236 * @param {Geometry|Feature<LineString>} line1 GeoJSON Feature or Geometry
20237 * @param {Geometry|Feature<LineString>} line2 GeoJSON Feature or Geometry
20238 * @returns {boolean} true/false if the lines are parallel
20239 * @example
20240 * var line1 = turf.lineString([[0, 0], [0, 1]]);
20241 * var line2 = turf.lineString([[1, 0], [1, 1]]);
20242 *
20243 * turf.booleanParallel(line1, line2);
20244 * //=true
20245 */
20246function booleanParallel(line1, line2) {
20247 // validation
20248 if (!line1) throw new Error('line1 is required');
20249 if (!line2) throw new Error('line2 is required');
20250 var type1 = getType$1(line1, 'line1');
20251 if (type1 !== 'LineString') throw new Error('line1 must be a LineString');
20252 var type2 = getType$1(line2, 'line2');
20253 if (type2 !== 'LineString') throw new Error('line2 must be a LineString');
20254
20255 var segments1 = lineSegment(cleanCoords(line1)).features;
20256 var segments2 = lineSegment(cleanCoords(line2)).features;
20257
20258 for (var i = 0; i < segments1.length; i++) {
20259 var segment1 = segments1[i].geometry.coordinates;
20260 if (!segments2[i]) break;
20261 var segment2 = segments2[i].geometry.coordinates;
20262 if (!isParallel$1(segment1, segment2)) return false;
20263 }
20264 return true;
20265}
20266
20267
20268/**
20269 * Compares slopes and return result
20270 *
20271 * @private
20272 * @param {Geometry|Feature<LineString>} segment1 Geometry or Feature
20273 * @param {Geometry|Feature<LineString>} segment2 Geometry or Feature
20274 * @returns {boolean} if slopes are equal
20275 */
20276function isParallel$1(segment1, segment2) {
20277 var slope1 = bearingToAzimuth(rhumbBearing(segment1[0], segment1[1]));
20278 var slope2 = bearingToAzimuth(rhumbBearing(segment2[0], segment2[1]));
20279 return slope1 === slope2;
20280}
20281
20282
20283/**
20284 * Returns Feature's type
20285 *
20286 * @private
20287 * @param {Geometry|Feature<any>} geojson Geometry or Feature
20288 * @param {string} name of the variable
20289 * @returns {string} Feature's type
20290 */
20291function getType$1(geojson, name) {
20292 if (geojson.geometry && geojson.geometry.type) return geojson.geometry.type;
20293 if (geojson.type) return geojson.type; // if GeoJSON geometry
20294 throw new Error('Invalid GeoJSON object for ' + name);
20295}
20296
20297// javascript-astar 0.4.1
20298// http://github.com/bgrins/javascript-astar
20299// Freely distributable under the MIT License.
20300// Implements the astar search algorithm in javascript using a Binary Heap.
20301// Includes Binary Heap (with modifications) from Marijn Haverbeke.
20302// http://eloquentjavascript.net/appendix2.html
20303
20304function pathTo(node) {
20305 var curr = node,
20306 path = [];
20307 while (curr.parent) {
20308 path.unshift(curr);
20309 curr = curr.parent;
20310 }
20311 return path;
20312}
20313
20314function getHeap() {
20315 return new BinaryHeap(function (node) {
20316 return node.f;
20317 });
20318}
20319
20320/**
20321 * Astar
20322 * @private
20323 */
20324var astar = {
20325 /**
20326 * Perform an A* Search on a graph given a start and end node.
20327 *
20328 * @private
20329 * @memberof astar
20330 * @param {Graph} graph Graph
20331 * @param {GridNode} start Start
20332 * @param {GridNode} end End
20333 * @param {Object} [options] Options
20334 * @param {bool} [options.closest] Specifies whether to return the path to the closest node if the target is unreachable.
20335 * @param {Function} [options.heuristic] Heuristic function (see astar.heuristics).
20336 * @returns {Object} Search
20337 */
20338 search: function (graph, start, end, options) {
20339 graph.cleanDirty();
20340 options = options || {};
20341 var heuristic = options.heuristic || astar.heuristics.manhattan,
20342 closest = options.closest || false;
20343
20344 var openHeap = getHeap(),
20345 closestNode = start; // set the start node to be the closest if required
20346
20347 start.h = heuristic(start, end);
20348
20349 openHeap.push(start);
20350
20351 while (openHeap.size() > 0) {
20352
20353 // Grab the lowest f(x) to process next. Heap keeps this sorted for us.
20354 var currentNode = openHeap.pop();
20355
20356 // End case -- result has been found, return the traced path.
20357 if (currentNode === end) {
20358 return pathTo(currentNode);
20359 }
20360
20361 // Normal case -- move currentNode from open to closed, process each of its neighbors.
20362 currentNode.closed = true;
20363
20364 // Find all neighbors for the current node.
20365 var neighbors = graph.neighbors(currentNode);
20366
20367 for (var i = 0, il = neighbors.length; i < il; ++i) {
20368 var neighbor = neighbors[i];
20369
20370 if (neighbor.closed || neighbor.isWall()) {
20371 // Not a valid node to process, skip to next neighbor.
20372 continue;
20373 }
20374
20375 // The g score is the shortest distance from start to current node.
20376 // We need to check if the path we have arrived at this neighbor is the shortest one we have seen yet.
20377 var gScore = currentNode.g + neighbor.getCost(currentNode),
20378 beenVisited = neighbor.visited;
20379
20380 if (!beenVisited || gScore < neighbor.g) {
20381
20382 // Found an optimal (so far) path to this node. Take score for node to see how good it is.
20383 neighbor.visited = true;
20384 neighbor.parent = currentNode;
20385 neighbor.h = neighbor.h || heuristic(neighbor, end);
20386 neighbor.g = gScore;
20387 neighbor.f = neighbor.g + neighbor.h;
20388 graph.markDirty(neighbor);
20389 if (closest) {
20390 // If the neighbour is closer than the current closestNode or if it's equally close but has
20391 // a cheaper path than the current closest node then it becomes the closest node
20392 if (neighbor.h < closestNode.h || (neighbor.h === closestNode.h && neighbor.g < closestNode.g)) {
20393 closestNode = neighbor;
20394 }
20395 }
20396
20397 if (!beenVisited) {
20398 // Pushing to heap will put it in proper place based on the 'f' value.
20399 openHeap.push(neighbor);
20400 } else {
20401 // Already seen the node, but since it has been rescored we need to reorder it in the heap
20402 openHeap.rescoreElement(neighbor);
20403 }
20404 }
20405 }
20406 }
20407
20408 if (closest) {
20409 return pathTo(closestNode);
20410 }
20411
20412 // No result was found - empty array signifies failure to find path.
20413 return [];
20414 },
20415 // See list of heuristics: http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html
20416 heuristics: {
20417 manhattan: function (pos0, pos1) {
20418 var d1 = Math.abs(pos1.x - pos0.x);
20419 var d2 = Math.abs(pos1.y - pos0.y);
20420 return d1 + d2;
20421 },
20422 diagonal: function (pos0, pos1) {
20423 var D = 1;
20424 var D2 = Math.sqrt(2);
20425 var d1 = Math.abs(pos1.x - pos0.x);
20426 var d2 = Math.abs(pos1.y - pos0.y);
20427 return (D * (d1 + d2)) + ((D2 - (2 * D)) * Math.min(d1, d2));
20428 }
20429 },
20430 cleanNode: function (node) {
20431 node.f = 0;
20432 node.g = 0;
20433 node.h = 0;
20434 node.visited = false;
20435 node.closed = false;
20436 node.parent = null;
20437 }
20438};
20439
20440/**
20441 * A graph memory structure
20442 *
20443 * @private
20444 * @param {Array} gridIn 2D array of input weights
20445 * @param {Object} [options] Options
20446 * @param {boolean} [options.diagonal] Specifies whether diagonal moves are allowed
20447 * @returns {void} Graph
20448 */
20449function Graph$1(gridIn, options) {
20450 options = options || {};
20451 this.nodes = [];
20452 this.diagonal = !!options.diagonal;
20453 this.grid = [];
20454 for (var x = 0; x < gridIn.length; x++) {
20455 this.grid[x] = [];
20456
20457 for (var y = 0, row = gridIn[x]; y < row.length; y++) {
20458 var node = new GridNode(x, y, row[y]);
20459 this.grid[x][y] = node;
20460 this.nodes.push(node);
20461 }
20462 }
20463 this.init();
20464}
20465
20466Graph$1.prototype.init = function () {
20467 this.dirtyNodes = [];
20468 for (var i = 0; i < this.nodes.length; i++) {
20469 astar.cleanNode(this.nodes[i]);
20470 }
20471};
20472
20473Graph$1.prototype.cleanDirty = function () {
20474 for (var i = 0; i < this.dirtyNodes.length; i++) {
20475 astar.cleanNode(this.dirtyNodes[i]);
20476 }
20477 this.dirtyNodes = [];
20478};
20479
20480Graph$1.prototype.markDirty = function (node) {
20481 this.dirtyNodes.push(node);
20482};
20483
20484Graph$1.prototype.neighbors = function (node) {
20485 var ret = [],
20486 x = node.x,
20487 y = node.y,
20488 grid = this.grid;
20489
20490 // West
20491 if (grid[x - 1] && grid[x - 1][y]) {
20492 ret.push(grid[x - 1][y]);
20493 }
20494
20495 // East
20496 if (grid[x + 1] && grid[x + 1][y]) {
20497 ret.push(grid[x + 1][y]);
20498 }
20499
20500 // South
20501 if (grid[x] && grid[x][y - 1]) {
20502 ret.push(grid[x][y - 1]);
20503 }
20504
20505 // North
20506 if (grid[x] && grid[x][y + 1]) {
20507 ret.push(grid[x][y + 1]);
20508 }
20509
20510 if (this.diagonal) {
20511 // Southwest
20512 if (grid[x - 1] && grid[x - 1][y - 1]) {
20513 ret.push(grid[x - 1][y - 1]);
20514 }
20515
20516 // Southeast
20517 if (grid[x + 1] && grid[x + 1][y - 1]) {
20518 ret.push(grid[x + 1][y - 1]);
20519 }
20520
20521 // Northwest
20522 if (grid[x - 1] && grid[x - 1][y + 1]) {
20523 ret.push(grid[x - 1][y + 1]);
20524 }
20525
20526 // Northeast
20527 if (grid[x + 1] && grid[x + 1][y + 1]) {
20528 ret.push(grid[x + 1][y + 1]);
20529 }
20530 }
20531
20532 return ret;
20533};
20534
20535Graph$1.prototype.toString = function () {
20536 var graphString = [],
20537 nodes = this.grid, // when using grid
20538 rowDebug, row, y, l;
20539 for (var x = 0, len = nodes.length; x < len; x++) {
20540 rowDebug = [];
20541 row = nodes[x];
20542 for (y = 0, l = row.length; y < l; y++) {
20543 rowDebug.push(row[y].weight);
20544 }
20545 graphString.push(rowDebug.join(' '));
20546 }
20547 return graphString.join('\n');
20548};
20549
20550function GridNode(x, y, weight) {
20551 this.x = x;
20552 this.y = y;
20553 this.weight = weight;
20554}
20555
20556GridNode.prototype.toString = function () {
20557 return '[' + this.x + ' ' + this.y + ']';
20558};
20559
20560GridNode.prototype.getCost = function (fromNeighbor) {
20561 // Take diagonal weight into consideration.
20562 if (fromNeighbor && fromNeighbor.x !== this.x && fromNeighbor.y !== this.y) {
20563 return this.weight * 1.41421;
20564 }
20565 return this.weight;
20566};
20567
20568GridNode.prototype.isWall = function () {
20569 return this.weight === 0;
20570};
20571
20572function BinaryHeap(scoreFunction) {
20573 this.content = [];
20574 this.scoreFunction = scoreFunction;
20575}
20576
20577BinaryHeap.prototype = {
20578 push: function (element) {
20579 // Add the new element to the end of the array.
20580 this.content.push(element);
20581
20582 // Allow it to sink down.
20583 this.sinkDown(this.content.length - 1);
20584 },
20585 pop: function () {
20586 // Store the first element so we can return it later.
20587 var result = this.content[0];
20588 // Get the element at the end of the array.
20589 var end = this.content.pop();
20590 // If there are any elements left, put the end element at the
20591 // start, and let it bubble up.
20592 if (this.content.length > 0) {
20593 this.content[0] = end;
20594 this.bubbleUp(0);
20595 }
20596 return result;
20597 },
20598 remove: function (node) {
20599 var i = this.content.indexOf(node);
20600
20601 // When it is found, the process seen in 'pop' is repeated
20602 // to fill up the hole.
20603 var end = this.content.pop();
20604
20605 if (i !== this.content.length - 1) {
20606 this.content[i] = end;
20607
20608 if (this.scoreFunction(end) < this.scoreFunction(node)) {
20609 this.sinkDown(i);
20610 } else {
20611 this.bubbleUp(i);
20612 }
20613 }
20614 },
20615 size: function () {
20616 return this.content.length;
20617 },
20618 rescoreElement: function (node) {
20619 this.sinkDown(this.content.indexOf(node));
20620 },
20621 sinkDown: function (n) {
20622 // Fetch the element that has to be sunk.
20623 var element = this.content[n];
20624
20625 // When at 0, an element can not sink any further.
20626 while (n > 0) {
20627
20628 // Compute the parent element's index, and fetch it.
20629 var parentN = ((n + 1) >> 1) - 1,
20630 parent = this.content[parentN];
20631 // Swap the elements if the parent is greater.
20632 if (this.scoreFunction(element) < this.scoreFunction(parent)) {
20633 this.content[parentN] = element;
20634 this.content[n] = parent;
20635 // Update 'n' to continue at the new position.
20636 n = parentN;
20637 // Found a parent that is less, no need to sink any further.
20638 } else {
20639 break;
20640 }
20641 }
20642 },
20643 bubbleUp: function (n) {
20644 // Look up the target element and its score.
20645 var length = this.content.length,
20646 element = this.content[n],
20647 elemScore = this.scoreFunction(element);
20648
20649 while (true) {
20650 // Compute the indices of the child elements.
20651 var child2N = (n + 1) << 1,
20652 child1N = child2N - 1;
20653 // This is used to store the new position of the element, if any.
20654 var swap = null,
20655 child1Score;
20656 // If the first child exists (is inside the array)...
20657 if (child1N < length) {
20658 // Look it up and compute its score.
20659 var child1 = this.content[child1N];
20660 child1Score = this.scoreFunction(child1);
20661
20662 // If the score is less than our element's, we need to swap.
20663 if (child1Score < elemScore) {
20664 swap = child1N;
20665 }
20666 }
20667
20668 // Do the same checks for the other child.
20669 if (child2N < length) {
20670 var child2 = this.content[child2N],
20671 child2Score = this.scoreFunction(child2);
20672 if (child2Score < (swap === null ? elemScore : child1Score)) {
20673 swap = child2N;
20674 }
20675 }
20676
20677 // If the element needs to be moved, swap it, and continue.
20678 if (swap !== null) {
20679 this.content[n] = this.content[swap];
20680 this.content[swap] = element;
20681 n = swap;
20682 // Otherwise, we are done.
20683 } else {
20684 break;
20685 }
20686 }
20687 }
20688};
20689
20690/**
20691 * Returns the shortest {@link LineString|path} from {@link Point|start} to {@link Point|end} without colliding with
20692 * any {@link Feature} in {@link FeatureCollection<Polygon>| obstacles}
20693 *
20694 * @name shortestPath
20695 * @param {Coord} start point
20696 * @param {Coord} end point
20697 * @param {Object} [options={}] optional parameters
20698 * @param {Geometry|Feature|FeatureCollection<Polygon>} [options.obstacles] areas which path cannot travel
20699 * @param {number} [options.minDistance] minimum distance between shortest path and obstacles
20700 * @param {string} [options.units='kilometers'] unit in which resolution & minimum distance will be expressed in; it can be degrees, radians, miles, kilometers, ...
20701 * @param {number} [options.resolution=100] distance between matrix points on which the path will be calculated
20702 * @returns {Feature<LineString>} shortest path between start and end
20703 * @example
20704 * var start = [-5, -6];
20705 * var end = [9, -6];
20706 * var options = {
20707 * obstacles: turf.polygon([[[0, -7], [5, -7], [5, -3], [0, -3], [0, -7]]])
20708 * };
20709 *
20710 * var path = turf.shortestPath(start, end, options);
20711 *
20712 * //addToMap
20713 * var addToMap = [start, end, options.obstacles, path];
20714 */
20715function shortestPath(start, end, options) {
20716 // Optional parameters
20717 options = options || {};
20718 if (!isObject(options)) throw new Error('options is invalid');
20719 var resolution = options.resolution;
20720 var minDistance = options.minDistance;
20721 var obstacles = options.obstacles || featureCollection([]);
20722
20723 // validation
20724 if (!start) throw new Error('start is required');
20725 if (!end) throw new Error('end is required');
20726 if (resolution && !isNumber(resolution) || resolution <= 0) throw new Error('options.resolution must be a number, greater than 0');
20727 if (minDistance) throw new Error('options.minDistance is not yet implemented');
20728
20729 // Normalize Inputs
20730 var startCoord = getCoord(start);
20731 var endCoord = getCoord(end);
20732 start = point(startCoord);
20733 end = point(endCoord);
20734
20735 // Handle obstacles
20736 switch (getType(obstacles)) {
20737 case 'FeatureCollection':
20738 if (obstacles.features.length === 0) return lineString([startCoord, endCoord]);
20739 break;
20740 case 'Polygon':
20741 obstacles = featureCollection([feature(getGeom(obstacles))]);
20742 break;
20743 default:
20744 throw new Error('invalid obstacles');
20745 }
20746
20747 // define path grid area
20748 var collection = obstacles;
20749 collection.features.push(start);
20750 collection.features.push(end);
20751 var box = bbox(transformScale(bboxPolygon(bbox(collection)), 1.15)); // extend 15%
20752 if (!resolution) {
20753 var width = distance([box[0], box[1]], [box[2], box[1]], options);
20754 resolution = width / 100;
20755 }
20756 collection.features.pop();
20757 collection.features.pop();
20758
20759 var west = box[0];
20760 var south = box[1];
20761 var east = box[2];
20762 var north = box[3];
20763
20764 var xFraction = resolution / (distance([west, south], [east, south], options));
20765 var cellWidth = xFraction * (east - west);
20766 var yFraction = resolution / (distance([west, south], [west, north], options));
20767 var cellHeight = yFraction * (north - south);
20768
20769 var bboxHorizontalSide = (east - west);
20770 var bboxVerticalSide = (north - south);
20771 var columns = Math.floor(bboxHorizontalSide / cellWidth);
20772 var rows = Math.floor(bboxVerticalSide / cellHeight);
20773 // adjust origin of the grid
20774 var deltaX = (bboxHorizontalSide - columns * cellWidth) / 2;
20775 var deltaY = (bboxVerticalSide - rows * cellHeight) / 2;
20776
20777 // loop through points only once to speed up process
20778 // define matrix grid for A-star algorithm
20779 var pointMatrix = [];
20780 var matrix = [];
20781
20782 var closestToStart = [];
20783 var closestToEnd = [];
20784 var minDistStart = Infinity;
20785 var minDistEnd = Infinity;
20786 var currentY = north - deltaY;
20787 var r = 0;
20788 while (currentY >= south) {
20789 // var currentY = south + deltaY;
20790 var matrixRow = [];
20791 var pointMatrixRow = [];
20792 var currentX = west + deltaX;
20793 var c = 0;
20794 while (currentX <= east) {
20795 var pt = point([currentX, currentY]);
20796 var isInsideObstacle = isInside$1(pt, obstacles);
20797 // feed obstacles matrix
20798 matrixRow.push(isInsideObstacle ? 0 : 1); // with javascript-astar
20799 // matrixRow.push(isInsideObstacle ? 1 : 0); // with astar-andrea
20800 // map point's coords
20801 pointMatrixRow.push(currentX + '|' + currentY);
20802 // set closest points
20803 var distStart = distance(pt, start);
20804 // if (distStart < minDistStart) {
20805 if (!isInsideObstacle && distStart < minDistStart) {
20806 minDistStart = distStart;
20807 closestToStart = {x: c, y: r};
20808 }
20809 var distEnd = distance(pt, end);
20810 // if (distEnd < minDistEnd) {
20811 if (!isInsideObstacle && distEnd < minDistEnd) {
20812 minDistEnd = distEnd;
20813 closestToEnd = {x: c, y: r};
20814 }
20815 currentX += cellWidth;
20816 c++;
20817 }
20818 matrix.push(matrixRow);
20819 pointMatrix.push(pointMatrixRow);
20820 currentY -= cellHeight;
20821 r++;
20822 }
20823
20824 // find path on matrix grid
20825
20826 // javascript-astar ----------------------
20827 var graph = new Graph$1(matrix, {diagonal: true});
20828 var startOnMatrix = graph.grid[closestToStart.y][closestToStart.x];
20829 var endOnMatrix = graph.grid[closestToEnd.y][closestToEnd.x];
20830 var result = astar.search(graph, startOnMatrix, endOnMatrix);
20831
20832 var path = [startCoord];
20833 result.forEach(function (coord) {
20834 var coords = pointMatrix[coord.x][coord.y].split('|');
20835 path.push([+coords[0], +coords[1]]); // make sure coords are numbers
20836 });
20837 path.push(endCoord);
20838 // ---------------------------------------
20839
20840
20841 // astar-andrea ------------------------
20842 // var result = aStar(matrix, [closestToStart.x, closestToStart.y], [closestToEnd.x, closestToEnd.y], 'DiagonalFree');
20843 // var path = [start.geometry.coordinates];
20844 // result.forEach(function (coord) {
20845 // var coords = pointMatrix[coord[1]][coord[0]].split('|');
20846 // path.push([+coords[0], +coords[1]]); // make sure coords are numbers
20847 // });
20848 // path.push(end.geometry.coordinates);
20849 // ---------------------------------------
20850
20851
20852 return cleanCoords(lineString(path));
20853}
20854
20855/**
20856 * Checks if Point is inside any of the Polygons
20857 *
20858 * @private
20859 * @param {Feature<Point>} pt to check
20860 * @param {FeatureCollection<Polygon>} polygons features
20861 * @returns {boolean} if inside or not
20862 */
20863function isInside$1(pt, polygons$$1) {
20864 for (var i = 0; i < polygons$$1.features.length; i++) {
20865 if (booleanPointInPolygon(pt, polygons$$1.features[i])) {
20866 return true;
20867 }
20868 }
20869 return false;
20870}
20871
20872var constant = function(x) {
20873 return function() {
20874 return x;
20875 };
20876};
20877
20878function x(d) {
20879 return d[0];
20880}
20881
20882function y(d) {
20883 return d[1];
20884}
20885
20886function RedBlackTree() {
20887 this._ = null; // root node
20888}
20889
20890function RedBlackNode(node) {
20891 node.U = // parent node
20892 node.C = // color - true for red, false for black
20893 node.L = // left node
20894 node.R = // right node
20895 node.P = // previous node
20896 node.N = null; // next node
20897}
20898
20899RedBlackTree.prototype = {
20900 constructor: RedBlackTree,
20901
20902 insert: function(after, node) {
20903 var parent, grandpa, uncle;
20904
20905 if (after) {
20906 node.P = after;
20907 node.N = after.N;
20908 if (after.N) after.N.P = node;
20909 after.N = node;
20910 if (after.R) {
20911 after = after.R;
20912 while (after.L) after = after.L;
20913 after.L = node;
20914 } else {
20915 after.R = node;
20916 }
20917 parent = after;
20918 } else if (this._) {
20919 after = RedBlackFirst(this._);
20920 node.P = null;
20921 node.N = after;
20922 after.P = after.L = node;
20923 parent = after;
20924 } else {
20925 node.P = node.N = null;
20926 this._ = node;
20927 parent = null;
20928 }
20929 node.L = node.R = null;
20930 node.U = parent;
20931 node.C = true;
20932
20933 after = node;
20934 while (parent && parent.C) {
20935 grandpa = parent.U;
20936 if (parent === grandpa.L) {
20937 uncle = grandpa.R;
20938 if (uncle && uncle.C) {
20939 parent.C = uncle.C = false;
20940 grandpa.C = true;
20941 after = grandpa;
20942 } else {
20943 if (after === parent.R) {
20944 RedBlackRotateLeft(this, parent);
20945 after = parent;
20946 parent = after.U;
20947 }
20948 parent.C = false;
20949 grandpa.C = true;
20950 RedBlackRotateRight(this, grandpa);
20951 }
20952 } else {
20953 uncle = grandpa.L;
20954 if (uncle && uncle.C) {
20955 parent.C = uncle.C = false;
20956 grandpa.C = true;
20957 after = grandpa;
20958 } else {
20959 if (after === parent.L) {
20960 RedBlackRotateRight(this, parent);
20961 after = parent;
20962 parent = after.U;
20963 }
20964 parent.C = false;
20965 grandpa.C = true;
20966 RedBlackRotateLeft(this, grandpa);
20967 }
20968 }
20969 parent = after.U;
20970 }
20971 this._.C = false;
20972 },
20973
20974 remove: function(node) {
20975 if (node.N) node.N.P = node.P;
20976 if (node.P) node.P.N = node.N;
20977 node.N = node.P = null;
20978
20979 var parent = node.U,
20980 sibling,
20981 left = node.L,
20982 right = node.R,
20983 next,
20984 red;
20985
20986 if (!left) next = right;
20987 else if (!right) next = left;
20988 else next = RedBlackFirst(right);
20989
20990 if (parent) {
20991 if (parent.L === node) parent.L = next;
20992 else parent.R = next;
20993 } else {
20994 this._ = next;
20995 }
20996
20997 if (left && right) {
20998 red = next.C;
20999 next.C = node.C;
21000 next.L = left;
21001 left.U = next;
21002 if (next !== right) {
21003 parent = next.U;
21004 next.U = node.U;
21005 node = next.R;
21006 parent.L = node;
21007 next.R = right;
21008 right.U = next;
21009 } else {
21010 next.U = parent;
21011 parent = next;
21012 node = next.R;
21013 }
21014 } else {
21015 red = node.C;
21016 node = next;
21017 }
21018
21019 if (node) node.U = parent;
21020 if (red) return;
21021 if (node && node.C) { node.C = false; return; }
21022
21023 do {
21024 if (node === this._) break;
21025 if (node === parent.L) {
21026 sibling = parent.R;
21027 if (sibling.C) {
21028 sibling.C = false;
21029 parent.C = true;
21030 RedBlackRotateLeft(this, parent);
21031 sibling = parent.R;
21032 }
21033 if ((sibling.L && sibling.L.C)
21034 || (sibling.R && sibling.R.C)) {
21035 if (!sibling.R || !sibling.R.C) {
21036 sibling.L.C = false;
21037 sibling.C = true;
21038 RedBlackRotateRight(this, sibling);
21039 sibling = parent.R;
21040 }
21041 sibling.C = parent.C;
21042 parent.C = sibling.R.C = false;
21043 RedBlackRotateLeft(this, parent);
21044 node = this._;
21045 break;
21046 }
21047 } else {
21048 sibling = parent.L;
21049 if (sibling.C) {
21050 sibling.C = false;
21051 parent.C = true;
21052 RedBlackRotateRight(this, parent);
21053 sibling = parent.L;
21054 }
21055 if ((sibling.L && sibling.L.C)
21056 || (sibling.R && sibling.R.C)) {
21057 if (!sibling.L || !sibling.L.C) {
21058 sibling.R.C = false;
21059 sibling.C = true;
21060 RedBlackRotateLeft(this, sibling);
21061 sibling = parent.L;
21062 }
21063 sibling.C = parent.C;
21064 parent.C = sibling.L.C = false;
21065 RedBlackRotateRight(this, parent);
21066 node = this._;
21067 break;
21068 }
21069 }
21070 sibling.C = true;
21071 node = parent;
21072 parent = parent.U;
21073 } while (!node.C);
21074
21075 if (node) node.C = false;
21076 }
21077};
21078
21079function RedBlackRotateLeft(tree, node) {
21080 var p = node,
21081 q = node.R,
21082 parent = p.U;
21083
21084 if (parent) {
21085 if (parent.L === p) parent.L = q;
21086 else parent.R = q;
21087 } else {
21088 tree._ = q;
21089 }
21090
21091 q.U = parent;
21092 p.U = q;
21093 p.R = q.L;
21094 if (p.R) p.R.U = p;
21095 q.L = p;
21096}
21097
21098function RedBlackRotateRight(tree, node) {
21099 var p = node,
21100 q = node.L,
21101 parent = p.U;
21102
21103 if (parent) {
21104 if (parent.L === p) parent.L = q;
21105 else parent.R = q;
21106 } else {
21107 tree._ = q;
21108 }
21109
21110 q.U = parent;
21111 p.U = q;
21112 p.L = q.R;
21113 if (p.L) p.L.U = p;
21114 q.R = p;
21115}
21116
21117function RedBlackFirst(node) {
21118 while (node.L) node = node.L;
21119 return node;
21120}
21121
21122function createEdge(left, right, v0, v1) {
21123 var edge = [null, null],
21124 index = edges.push(edge) - 1;
21125 edge.left = left;
21126 edge.right = right;
21127 if (v0) setEdgeEnd(edge, left, right, v0);
21128 if (v1) setEdgeEnd(edge, right, left, v1);
21129 cells[left.index].halfedges.push(index);
21130 cells[right.index].halfedges.push(index);
21131 return edge;
21132}
21133
21134function createBorderEdge(left, v0, v1) {
21135 var edge = [v0, v1];
21136 edge.left = left;
21137 return edge;
21138}
21139
21140function setEdgeEnd(edge, left, right, vertex) {
21141 if (!edge[0] && !edge[1]) {
21142 edge[0] = vertex;
21143 edge.left = left;
21144 edge.right = right;
21145 } else if (edge.left === right) {
21146 edge[1] = vertex;
21147 } else {
21148 edge[0] = vertex;
21149 }
21150}
21151
21152// Liang–Barsky line clipping.
21153function clipEdge(edge, x0, y0, x1, y1) {
21154 var a = edge[0],
21155 b = edge[1],
21156 ax = a[0],
21157 ay = a[1],
21158 bx = b[0],
21159 by = b[1],
21160 t0 = 0,
21161 t1 = 1,
21162 dx = bx - ax,
21163 dy = by - ay,
21164 r;
21165
21166 r = x0 - ax;
21167 if (!dx && r > 0) return;
21168 r /= dx;
21169 if (dx < 0) {
21170 if (r < t0) return;
21171 if (r < t1) t1 = r;
21172 } else if (dx > 0) {
21173 if (r > t1) return;
21174 if (r > t0) t0 = r;
21175 }
21176
21177 r = x1 - ax;
21178 if (!dx && r < 0) return;
21179 r /= dx;
21180 if (dx < 0) {
21181 if (r > t1) return;
21182 if (r > t0) t0 = r;
21183 } else if (dx > 0) {
21184 if (r < t0) return;
21185 if (r < t1) t1 = r;
21186 }
21187
21188 r = y0 - ay;
21189 if (!dy && r > 0) return;
21190 r /= dy;
21191 if (dy < 0) {
21192 if (r < t0) return;
21193 if (r < t1) t1 = r;
21194 } else if (dy > 0) {
21195 if (r > t1) return;
21196 if (r > t0) t0 = r;
21197 }
21198
21199 r = y1 - ay;
21200 if (!dy && r < 0) return;
21201 r /= dy;
21202 if (dy < 0) {
21203 if (r > t1) return;
21204 if (r > t0) t0 = r;
21205 } else if (dy > 0) {
21206 if (r < t0) return;
21207 if (r < t1) t1 = r;
21208 }
21209
21210 if (!(t0 > 0) && !(t1 < 1)) return true; // TODO Better check?
21211
21212 if (t0 > 0) edge[0] = [ax + t0 * dx, ay + t0 * dy];
21213 if (t1 < 1) edge[1] = [ax + t1 * dx, ay + t1 * dy];
21214 return true;
21215}
21216
21217function connectEdge(edge, x0, y0, x1, y1) {
21218 var v1 = edge[1];
21219 if (v1) return true;
21220
21221 var v0 = edge[0],
21222 left = edge.left,
21223 right = edge.right,
21224 lx = left[0],
21225 ly = left[1],
21226 rx = right[0],
21227 ry = right[1],
21228 fx = (lx + rx) / 2,
21229 fy = (ly + ry) / 2,
21230 fm,
21231 fb;
21232
21233 if (ry === ly) {
21234 if (fx < x0 || fx >= x1) return;
21235 if (lx > rx) {
21236 if (!v0) v0 = [fx, y0];
21237 else if (v0[1] >= y1) return;
21238 v1 = [fx, y1];
21239 } else {
21240 if (!v0) v0 = [fx, y1];
21241 else if (v0[1] < y0) return;
21242 v1 = [fx, y0];
21243 }
21244 } else {
21245 fm = (lx - rx) / (ry - ly);
21246 fb = fy - fm * fx;
21247 if (fm < -1 || fm > 1) {
21248 if (lx > rx) {
21249 if (!v0) v0 = [(y0 - fb) / fm, y0];
21250 else if (v0[1] >= y1) return;
21251 v1 = [(y1 - fb) / fm, y1];
21252 } else {
21253 if (!v0) v0 = [(y1 - fb) / fm, y1];
21254 else if (v0[1] < y0) return;
21255 v1 = [(y0 - fb) / fm, y0];
21256 }
21257 } else {
21258 if (ly < ry) {
21259 if (!v0) v0 = [x0, fm * x0 + fb];
21260 else if (v0[0] >= x1) return;
21261 v1 = [x1, fm * x1 + fb];
21262 } else {
21263 if (!v0) v0 = [x1, fm * x1 + fb];
21264 else if (v0[0] < x0) return;
21265 v1 = [x0, fm * x0 + fb];
21266 }
21267 }
21268 }
21269
21270 edge[0] = v0;
21271 edge[1] = v1;
21272 return true;
21273}
21274
21275function clipEdges(x0, y0, x1, y1) {
21276 var i = edges.length,
21277 edge;
21278
21279 while (i--) {
21280 if (!connectEdge(edge = edges[i], x0, y0, x1, y1)
21281 || !clipEdge(edge, x0, y0, x1, y1)
21282 || !(Math.abs(edge[0][0] - edge[1][0]) > epsilon
21283 || Math.abs(edge[0][1] - edge[1][1]) > epsilon)) {
21284 delete edges[i];
21285 }
21286 }
21287}
21288
21289function createCell(site) {
21290 return cells[site.index] = {
21291 site: site,
21292 halfedges: []
21293 };
21294}
21295
21296function cellHalfedgeAngle(cell, edge) {
21297 var site = cell.site,
21298 va = edge.left,
21299 vb = edge.right;
21300 if (site === vb) vb = va, va = site;
21301 if (vb) return Math.atan2(vb[1] - va[1], vb[0] - va[0]);
21302 if (site === va) va = edge[1], vb = edge[0];
21303 else va = edge[0], vb = edge[1];
21304 return Math.atan2(va[0] - vb[0], vb[1] - va[1]);
21305}
21306
21307function cellHalfedgeStart(cell, edge) {
21308 return edge[+(edge.left !== cell.site)];
21309}
21310
21311function cellHalfedgeEnd(cell, edge) {
21312 return edge[+(edge.left === cell.site)];
21313}
21314
21315function sortCellHalfedges() {
21316 for (var i = 0, n = cells.length, cell, halfedges, j, m; i < n; ++i) {
21317 if ((cell = cells[i]) && (m = (halfedges = cell.halfedges).length)) {
21318 var index = new Array(m),
21319 array = new Array(m);
21320 for (j = 0; j < m; ++j) index[j] = j, array[j] = cellHalfedgeAngle(cell, edges[halfedges[j]]);
21321 index.sort(function(i, j) { return array[j] - array[i]; });
21322 for (j = 0; j < m; ++j) array[j] = halfedges[index[j]];
21323 for (j = 0; j < m; ++j) halfedges[j] = array[j];
21324 }
21325 }
21326}
21327
21328function clipCells(x0, y0, x1, y1) {
21329 var nCells = cells.length,
21330 iCell,
21331 cell,
21332 site,
21333 iHalfedge,
21334 halfedges,
21335 nHalfedges,
21336 start,
21337 startX,
21338 startY,
21339 end,
21340 endX,
21341 endY,
21342 cover = true;
21343
21344 for (iCell = 0; iCell < nCells; ++iCell) {
21345 if (cell = cells[iCell]) {
21346 site = cell.site;
21347 halfedges = cell.halfedges;
21348 iHalfedge = halfedges.length;
21349
21350 // Remove any dangling clipped edges.
21351 while (iHalfedge--) {
21352 if (!edges[halfedges[iHalfedge]]) {
21353 halfedges.splice(iHalfedge, 1);
21354 }
21355 }
21356
21357 // Insert any border edges as necessary.
21358 iHalfedge = 0, nHalfedges = halfedges.length;
21359 while (iHalfedge < nHalfedges) {
21360 end = cellHalfedgeEnd(cell, edges[halfedges[iHalfedge]]), endX = end[0], endY = end[1];
21361 start = cellHalfedgeStart(cell, edges[halfedges[++iHalfedge % nHalfedges]]), startX = start[0], startY = start[1];
21362 if (Math.abs(endX - startX) > epsilon || Math.abs(endY - startY) > epsilon) {
21363 halfedges.splice(iHalfedge, 0, edges.push(createBorderEdge(site, end,
21364 Math.abs(endX - x0) < epsilon && y1 - endY > epsilon ? [x0, Math.abs(startX - x0) < epsilon ? startY : y1]
21365 : Math.abs(endY - y1) < epsilon && x1 - endX > epsilon ? [Math.abs(startY - y1) < epsilon ? startX : x1, y1]
21366 : Math.abs(endX - x1) < epsilon && endY - y0 > epsilon ? [x1, Math.abs(startX - x1) < epsilon ? startY : y0]
21367 : Math.abs(endY - y0) < epsilon && endX - x0 > epsilon ? [Math.abs(startY - y0) < epsilon ? startX : x0, y0]
21368 : null)) - 1);
21369 ++nHalfedges;
21370 }
21371 }
21372
21373 if (nHalfedges) cover = false;
21374 }
21375 }
21376
21377 // If there weren’t any edges, have the closest site cover the extent.
21378 // It doesn’t matter which corner of the extent we measure!
21379 if (cover) {
21380 var dx, dy, d2, dc = Infinity;
21381
21382 for (iCell = 0, cover = null; iCell < nCells; ++iCell) {
21383 if (cell = cells[iCell]) {
21384 site = cell.site;
21385 dx = site[0] - x0;
21386 dy = site[1] - y0;
21387 d2 = dx * dx + dy * dy;
21388 if (d2 < dc) dc = d2, cover = cell;
21389 }
21390 }
21391
21392 if (cover) {
21393 var v00 = [x0, y0], v01 = [x0, y1], v11 = [x1, y1], v10 = [x1, y0];
21394 cover.halfedges.push(
21395 edges.push(createBorderEdge(site = cover.site, v00, v01)) - 1,
21396 edges.push(createBorderEdge(site, v01, v11)) - 1,
21397 edges.push(createBorderEdge(site, v11, v10)) - 1,
21398 edges.push(createBorderEdge(site, v10, v00)) - 1
21399 );
21400 }
21401 }
21402
21403 // Lastly delete any cells with no edges; these were entirely clipped.
21404 for (iCell = 0; iCell < nCells; ++iCell) {
21405 if (cell = cells[iCell]) {
21406 if (!cell.halfedges.length) {
21407 delete cells[iCell];
21408 }
21409 }
21410 }
21411}
21412
21413var circlePool = [];
21414
21415var firstCircle;
21416
21417function Circle() {
21418 RedBlackNode(this);
21419 this.x =
21420 this.y =
21421 this.arc =
21422 this.site =
21423 this.cy = null;
21424}
21425
21426function attachCircle(arc) {
21427 var lArc = arc.P,
21428 rArc = arc.N;
21429
21430 if (!lArc || !rArc) return;
21431
21432 var lSite = lArc.site,
21433 cSite = arc.site,
21434 rSite = rArc.site;
21435
21436 if (lSite === rSite) return;
21437
21438 var bx = cSite[0],
21439 by = cSite[1],
21440 ax = lSite[0] - bx,
21441 ay = lSite[1] - by,
21442 cx = rSite[0] - bx,
21443 cy = rSite[1] - by;
21444
21445 var d = 2 * (ax * cy - ay * cx);
21446 if (d >= -epsilon2) return;
21447
21448 var ha = ax * ax + ay * ay,
21449 hc = cx * cx + cy * cy,
21450 x = (cy * ha - ay * hc) / d,
21451 y = (ax * hc - cx * ha) / d;
21452
21453 var circle = circlePool.pop() || new Circle;
21454 circle.arc = arc;
21455 circle.site = cSite;
21456 circle.x = x + bx;
21457 circle.y = (circle.cy = y + by) + Math.sqrt(x * x + y * y); // y bottom
21458
21459 arc.circle = circle;
21460
21461 var before = null,
21462 node = circles._;
21463
21464 while (node) {
21465 if (circle.y < node.y || (circle.y === node.y && circle.x <= node.x)) {
21466 if (node.L) node = node.L;
21467 else { before = node.P; break; }
21468 } else {
21469 if (node.R) node = node.R;
21470 else { before = node; break; }
21471 }
21472 }
21473
21474 circles.insert(before, circle);
21475 if (!before) firstCircle = circle;
21476}
21477
21478function detachCircle(arc) {
21479 var circle = arc.circle;
21480 if (circle) {
21481 if (!circle.P) firstCircle = circle.N;
21482 circles.remove(circle);
21483 circlePool.push(circle);
21484 RedBlackNode(circle);
21485 arc.circle = null;
21486 }
21487}
21488
21489var beachPool = [];
21490
21491function Beach() {
21492 RedBlackNode(this);
21493 this.edge =
21494 this.site =
21495 this.circle = null;
21496}
21497
21498function createBeach(site) {
21499 var beach = beachPool.pop() || new Beach;
21500 beach.site = site;
21501 return beach;
21502}
21503
21504function detachBeach(beach) {
21505 detachCircle(beach);
21506 beaches.remove(beach);
21507 beachPool.push(beach);
21508 RedBlackNode(beach);
21509}
21510
21511function removeBeach(beach) {
21512 var circle = beach.circle,
21513 x = circle.x,
21514 y = circle.cy,
21515 vertex = [x, y],
21516 previous = beach.P,
21517 next = beach.N,
21518 disappearing = [beach];
21519
21520 detachBeach(beach);
21521
21522 var lArc = previous;
21523 while (lArc.circle
21524 && Math.abs(x - lArc.circle.x) < epsilon
21525 && Math.abs(y - lArc.circle.cy) < epsilon) {
21526 previous = lArc.P;
21527 disappearing.unshift(lArc);
21528 detachBeach(lArc);
21529 lArc = previous;
21530 }
21531
21532 disappearing.unshift(lArc);
21533 detachCircle(lArc);
21534
21535 var rArc = next;
21536 while (rArc.circle
21537 && Math.abs(x - rArc.circle.x) < epsilon
21538 && Math.abs(y - rArc.circle.cy) < epsilon) {
21539 next = rArc.N;
21540 disappearing.push(rArc);
21541 detachBeach(rArc);
21542 rArc = next;
21543 }
21544
21545 disappearing.push(rArc);
21546 detachCircle(rArc);
21547
21548 var nArcs = disappearing.length,
21549 iArc;
21550 for (iArc = 1; iArc < nArcs; ++iArc) {
21551 rArc = disappearing[iArc];
21552 lArc = disappearing[iArc - 1];
21553 setEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex);
21554 }
21555
21556 lArc = disappearing[0];
21557 rArc = disappearing[nArcs - 1];
21558 rArc.edge = createEdge(lArc.site, rArc.site, null, vertex);
21559
21560 attachCircle(lArc);
21561 attachCircle(rArc);
21562}
21563
21564function addBeach(site) {
21565 var x = site[0],
21566 directrix = site[1],
21567 lArc,
21568 rArc,
21569 dxl,
21570 dxr,
21571 node = beaches._;
21572
21573 while (node) {
21574 dxl = leftBreakPoint(node, directrix) - x;
21575 if (dxl > epsilon) node = node.L; else {
21576 dxr = x - rightBreakPoint(node, directrix);
21577 if (dxr > epsilon) {
21578 if (!node.R) {
21579 lArc = node;
21580 break;
21581 }
21582 node = node.R;
21583 } else {
21584 if (dxl > -epsilon) {
21585 lArc = node.P;
21586 rArc = node;
21587 } else if (dxr > -epsilon) {
21588 lArc = node;
21589 rArc = node.N;
21590 } else {
21591 lArc = rArc = node;
21592 }
21593 break;
21594 }
21595 }
21596 }
21597
21598 createCell(site);
21599 var newArc = createBeach(site);
21600 beaches.insert(lArc, newArc);
21601
21602 if (!lArc && !rArc) return;
21603
21604 if (lArc === rArc) {
21605 detachCircle(lArc);
21606 rArc = createBeach(lArc.site);
21607 beaches.insert(newArc, rArc);
21608 newArc.edge = rArc.edge = createEdge(lArc.site, newArc.site);
21609 attachCircle(lArc);
21610 attachCircle(rArc);
21611 return;
21612 }
21613
21614 if (!rArc) { // && lArc
21615 newArc.edge = createEdge(lArc.site, newArc.site);
21616 return;
21617 }
21618
21619 // else lArc !== rArc
21620 detachCircle(lArc);
21621 detachCircle(rArc);
21622
21623 var lSite = lArc.site,
21624 ax = lSite[0],
21625 ay = lSite[1],
21626 bx = site[0] - ax,
21627 by = site[1] - ay,
21628 rSite = rArc.site,
21629 cx = rSite[0] - ax,
21630 cy = rSite[1] - ay,
21631 d = 2 * (bx * cy - by * cx),
21632 hb = bx * bx + by * by,
21633 hc = cx * cx + cy * cy,
21634 vertex = [(cy * hb - by * hc) / d + ax, (bx * hc - cx * hb) / d + ay];
21635
21636 setEdgeEnd(rArc.edge, lSite, rSite, vertex);
21637 newArc.edge = createEdge(lSite, site, null, vertex);
21638 rArc.edge = createEdge(site, rSite, null, vertex);
21639 attachCircle(lArc);
21640 attachCircle(rArc);
21641}
21642
21643function leftBreakPoint(arc, directrix) {
21644 var site = arc.site,
21645 rfocx = site[0],
21646 rfocy = site[1],
21647 pby2 = rfocy - directrix;
21648
21649 if (!pby2) return rfocx;
21650
21651 var lArc = arc.P;
21652 if (!lArc) return -Infinity;
21653
21654 site = lArc.site;
21655 var lfocx = site[0],
21656 lfocy = site[1],
21657 plby2 = lfocy - directrix;
21658
21659 if (!plby2) return lfocx;
21660
21661 var hl = lfocx - rfocx,
21662 aby2 = 1 / pby2 - 1 / plby2,
21663 b = hl / plby2;
21664
21665 if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx;
21666
21667 return (rfocx + lfocx) / 2;
21668}
21669
21670function rightBreakPoint(arc, directrix) {
21671 var rArc = arc.N;
21672 if (rArc) return leftBreakPoint(rArc, directrix);
21673 var site = arc.site;
21674 return site[1] === directrix ? site[0] : Infinity;
21675}
21676
21677var epsilon = 1e-6;
21678var epsilon2 = 1e-12;
21679var beaches;
21680var cells;
21681var circles;
21682var edges;
21683
21684function triangleArea(a, b, c) {
21685 return (a[0] - c[0]) * (b[1] - a[1]) - (a[0] - b[0]) * (c[1] - a[1]);
21686}
21687
21688function lexicographic(a, b) {
21689 return b[1] - a[1]
21690 || b[0] - a[0];
21691}
21692
21693function Diagram(sites, extent) {
21694 var site = sites.sort(lexicographic).pop(),
21695 x,
21696 y,
21697 circle;
21698
21699 edges = [];
21700 cells = new Array(sites.length);
21701 beaches = new RedBlackTree;
21702 circles = new RedBlackTree;
21703
21704 while (true) {
21705 circle = firstCircle;
21706 if (site && (!circle || site[1] < circle.y || (site[1] === circle.y && site[0] < circle.x))) {
21707 if (site[0] !== x || site[1] !== y) {
21708 addBeach(site);
21709 x = site[0], y = site[1];
21710 }
21711 site = sites.pop();
21712 } else if (circle) {
21713 removeBeach(circle.arc);
21714 } else {
21715 break;
21716 }
21717 }
21718
21719 sortCellHalfedges();
21720
21721 if (extent) {
21722 var x0 = +extent[0][0],
21723 y0 = +extent[0][1],
21724 x1 = +extent[1][0],
21725 y1 = +extent[1][1];
21726 clipEdges(x0, y0, x1, y1);
21727 clipCells(x0, y0, x1, y1);
21728 }
21729
21730 this.edges = edges;
21731 this.cells = cells;
21732
21733 beaches =
21734 circles =
21735 edges =
21736 cells = null;
21737}
21738
21739Diagram.prototype = {
21740 constructor: Diagram,
21741
21742 polygons: function() {
21743 var edges = this.edges;
21744
21745 return this.cells.map(function(cell) {
21746 var polygon = cell.halfedges.map(function(i) { return cellHalfedgeStart(cell, edges[i]); });
21747 polygon.data = cell.site.data;
21748 return polygon;
21749 });
21750 },
21751
21752 triangles: function() {
21753 var triangles = [],
21754 edges = this.edges;
21755
21756 this.cells.forEach(function(cell, i) {
21757 if (!(m = (halfedges = cell.halfedges).length)) return;
21758 var site = cell.site,
21759 halfedges,
21760 j = -1,
21761 m,
21762 s0,
21763 e1 = edges[halfedges[m - 1]],
21764 s1 = e1.left === site ? e1.right : e1.left;
21765
21766 while (++j < m) {
21767 s0 = s1;
21768 e1 = edges[halfedges[j]];
21769 s1 = e1.left === site ? e1.right : e1.left;
21770 if (s0 && s1 && i < s0.index && i < s1.index && triangleArea(site, s0, s1) < 0) {
21771 triangles.push([site.data, s0.data, s1.data]);
21772 }
21773 }
21774 });
21775
21776 return triangles;
21777 },
21778
21779 links: function() {
21780 return this.edges.filter(function(edge) {
21781 return edge.right;
21782 }).map(function(edge) {
21783 return {
21784 source: edge.left.data,
21785 target: edge.right.data
21786 };
21787 });
21788 },
21789
21790 find: function(x, y, radius) {
21791 var that = this, i0, i1 = that._found || 0, n = that.cells.length, cell;
21792
21793 // Use the previously-found cell, or start with an arbitrary one.
21794 while (!(cell = that.cells[i1])) if (++i1 >= n) return null;
21795 var dx = x - cell.site[0], dy = y - cell.site[1], d2 = dx * dx + dy * dy;
21796
21797 // Traverse the half-edges to find a closer cell, if any.
21798 do {
21799 cell = that.cells[i0 = i1], i1 = null;
21800 cell.halfedges.forEach(function(e) {
21801 var edge = that.edges[e], v = edge.left;
21802 if ((v === cell.site || !v) && !(v = edge.right)) return;
21803 var vx = x - v[0], vy = y - v[1], v2 = vx * vx + vy * vy;
21804 if (v2 < d2) d2 = v2, i1 = v.index;
21805 });
21806 } while (i1 !== null);
21807
21808 that._found = i0;
21809
21810 return radius == null || d2 <= radius * radius ? cell.site : null;
21811 }
21812};
21813
21814var voronoi = function() {
21815 var x$$1 = x,
21816 y$$1 = y,
21817 extent = null;
21818
21819 function voronoi(data) {
21820 return new Diagram(data.map(function(d, i) {
21821 var s = [Math.round(x$$1(d, i, data) / epsilon) * epsilon, Math.round(y$$1(d, i, data) / epsilon) * epsilon];
21822 s.index = i;
21823 s.data = d;
21824 return s;
21825 }), extent);
21826 }
21827
21828 voronoi.polygons = function(data) {
21829 return voronoi(data).polygons();
21830 };
21831
21832 voronoi.links = function(data) {
21833 return voronoi(data).links();
21834 };
21835
21836 voronoi.triangles = function(data) {
21837 return voronoi(data).triangles();
21838 };
21839
21840 voronoi.x = function(_) {
21841 return arguments.length ? (x$$1 = typeof _ === "function" ? _ : constant(+_), voronoi) : x$$1;
21842 };
21843
21844 voronoi.y = function(_) {
21845 return arguments.length ? (y$$1 = typeof _ === "function" ? _ : constant(+_), voronoi) : y$$1;
21846 };
21847
21848 voronoi.extent = function(_) {
21849 return arguments.length ? (extent = _ == null ? null : [[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]], voronoi) : extent && [[extent[0][0], extent[0][1]], [extent[1][0], extent[1][1]]];
21850 };
21851
21852 voronoi.size = function(_) {
21853 return arguments.length ? (extent = _ == null ? null : [[0, 0], [+_[0], +_[1]]], voronoi) : extent && [extent[1][0] - extent[0][0], extent[1][1] - extent[0][1]];
21854 };
21855
21856 return voronoi;
21857};
21858
21859/**
21860 * @private
21861 * @param {Array<Array<number>>} coords representing a polygon
21862 * @returns {Feature<Polygon>} polygon
21863 */
21864function coordsToPolygon(coords) {
21865 coords = coords.slice();
21866 coords.push(coords[0]);
21867 return polygon([coords]);
21868}
21869
21870/**
21871 * Takes a FeatureCollection of points, and a bounding box, and returns a FeatureCollection
21872 * of Voronoi polygons.
21873 *
21874 * The Voronoi algorithim used comes from the d3-voronoi package.
21875 *
21876 * @name voronoi
21877 * @param {FeatureCollection<Point>} points to find the Voronoi polygons around.
21878 * @param {Object} [options={}] Optional parameters
21879 * @param {number[]} [options.bbox=[-180, -85, 180, -85]] clipping rectangle, in [minX, minY, maxX, MaxY] order.
21880 * @returns {FeatureCollection<Polygon>} a set of polygons, one per input point.
21881 * @example
21882 * var options = {
21883 * bbox: [-70, 40, -60, 60]
21884 * };
21885 * var points = turf.randomPoint(100, options);
21886 * var voronoiPolygons = turf.voronoi(points, options);
21887 *
21888 * //addToMap
21889 * var addToMap = [voronoiPolygons, points];
21890 */
21891function voronoi$1(points$$1, options) {
21892 // Optional params
21893 options = options || {};
21894 if (!isObject(options)) throw new Error('options is invalid');
21895 var bbox = options.bbox || [-180, -85, 180, 85];
21896
21897 // Input Validation
21898 if (!points$$1) throw new Error('points is required');
21899 if (!Array.isArray(bbox)) throw new Error('bbox is invalid');
21900 collectionOf(points$$1, 'Point', 'points');
21901
21902 // Main
21903 return featureCollection(
21904 voronoi()
21905 .x(function (feature$$1) { return feature$$1.geometry.coordinates[0]; })
21906 .y(function (feature$$1) { return feature$$1.geometry.coordinates[1]; })
21907 .extent([[bbox[0], bbox[1]], [bbox[2], bbox[3]]])
21908 .polygons(points$$1.features)
21909 .map(coordsToPolygon)
21910 );
21911}
21912
21913/**
21914 * Takes a {@link Point} and calculates the ellipse polygon given two semi-axes expressed in variable units and steps for precision.
21915 *
21916 * @param {Coord} center center point
21917 * @param {number} xSemiAxis semi (major) axis of the ellipse along the x-axis
21918 * @param {number} ySemiAxis semi (minor) axis of the ellipse along the y-axis
21919 * @param {Object} [options={}] Optional parameters
21920 * @param {number} [options.angle=0] angle of rotation (along the vertical axis), from North in decimal degrees, negative clockwise
21921 * @param {Coord} [options.pivot='origin'] point around which the rotation will be performed
21922 * @param {number} [options.steps=64] number of steps
21923 * @param {string} [options.units='kilometers'] unit of measurement for axes
21924 * @param {Object} [options.properties={}] properties
21925 * @returns {Feature<Polygon>} ellipse polygon
21926 * @example
21927 * var center = [-75, 40];
21928 * var xSemiAxis = 5;
21929 * var ySemiAxis = 2;
21930 * var ellipse = turf.ellipse(center, xSemiAxis, ySemiAxis);
21931 *
21932 * //addToMap
21933 * var addToMap = [turf.point(center), ellipse]
21934 */
21935function ellipse(center, xSemiAxis, ySemiAxis, options) {
21936 // Optional params
21937 options = options || {};
21938 var steps = options.steps || 64;
21939 var units = options.units || 'kilometers';
21940 var angle = options.angle || 0;
21941 var pivot = options.pivot || center;
21942 var properties = options.properties || center.properties || {};
21943
21944 // validation
21945 if (!center) throw new Error('center is required');
21946 if (!xSemiAxis) throw new Error('xSemiAxis is required');
21947 if (!ySemiAxis) throw new Error('ySemiAxis is required');
21948 if (!isObject(options)) throw new Error('options must be an object');
21949 if (!isNumber(steps)) throw new Error('steps must be a number');
21950 if (!isNumber(angle)) throw new Error('angle must be a number');
21951
21952 var centerCoords = getCoord(center);
21953 if (units === 'degrees') {
21954 var angleRad = degreesToRadians(angle);
21955 } else {
21956 xSemiAxis = rhumbDestination(center, xSemiAxis, 90, {units: units});
21957 ySemiAxis = rhumbDestination(center, ySemiAxis, 0, {units: units});
21958 xSemiAxis = getCoord(xSemiAxis)[0] - centerCoords[0];
21959 ySemiAxis = getCoord(ySemiAxis)[1] - centerCoords[1];
21960 }
21961
21962 var coordinates = [];
21963 for (var i = 0; i < steps; i += 1) {
21964 var stepAngle = i * -360 / steps;
21965 var x = ((xSemiAxis * ySemiAxis) / Math.sqrt(Math.pow(ySemiAxis, 2) + (Math.pow(xSemiAxis, 2) * Math.pow(getTanDeg(stepAngle), 2))));
21966 var y = ((xSemiAxis * ySemiAxis) / Math.sqrt(Math.pow(xSemiAxis, 2) + (Math.pow(ySemiAxis, 2) / Math.pow(getTanDeg(stepAngle), 2))));
21967
21968 if (stepAngle < -90 && stepAngle >= -270) x = -x;
21969 if (stepAngle < -180 && stepAngle >= -360) y = -y;
21970 if (units === 'degrees') {
21971 var newx = x * Math.cos(angleRad) + y * Math.sin(angleRad);
21972 var newy = y * Math.cos(angleRad) - x * Math.sin(angleRad);
21973 x = newx;
21974 y = newy;
21975 }
21976
21977 coordinates.push([x + centerCoords[0], y + centerCoords[1]]);
21978 }
21979 coordinates.push(coordinates[0]);
21980 if (units === 'degrees') {
21981 return polygon([coordinates], properties);
21982 } else {
21983 return transformRotate(polygon([coordinates], properties), angle, { pivot: pivot });
21984 }
21985}
21986
21987/**
21988 * Get Tan Degrees
21989 *
21990 * @private
21991 * @param {number} deg Degrees
21992 * @returns {number} Tan Degrees
21993 */
21994function getTanDeg(deg) {
21995 var rad = deg * Math.PI / 180;
21996 return Math.tan(rad);
21997}
21998
21999/**
22000 * Takes a {@link Feature} or {@link FeatureCollection} and returns the mean center. Can be weighted.
22001 *
22002 * @name centerMean
22003 * @param {GeoJSON} geojson GeoJSON to be centered
22004 * @param {Object} [options={}] Optional parameters
22005 * @param {Object} [options.properties={}] an Object that is used as the {@link Feature}'s properties
22006 * @param {number} [options.weight] the property name used to weight the center
22007 * @returns {Feature<Point>} a Point feature at the mean center point of all input features
22008 * @example
22009 * var features = turf.featureCollection([
22010 * turf.point([-97.522259, 35.4691], {weight: 10}),
22011 * turf.point([-97.502754, 35.463455], {weight: 3}),
22012 * turf.point([-97.508269, 35.463245], {weight: 5})
22013 * ]);
22014 *
22015 * var options = {weight: "weight"}
22016 * var mean = turf.centerMean(features, options);
22017 *
22018 * //addToMap
22019 * var addToMap = [features, mean]
22020 * mean.properties['marker-size'] = 'large';
22021 * mean.properties['marker-color'] = '#000';
22022 */
22023function centerMean(geojson, options) {
22024 // Optional parameters
22025 options = options || {};
22026 if (!isObject(options)) throw new Error('options is invalid');
22027 var properties = options.properties;
22028 var weightTerm = options.weight;
22029
22030 // Input validation
22031 if (!geojson) throw new Error('geojson is required');
22032
22033 var sumXs = 0;
22034 var sumYs = 0;
22035 var sumNs = 0;
22036 geomEach(geojson, function (geom, featureIndex, properties) {
22037 var weight = properties[weightTerm];
22038 weight = (weight === undefined || weight === null) ? 1 : weight;
22039 if (!isNumber(weight)) throw new Error('weight value must be a number for feature index ' + featureIndex);
22040 weight = Number(weight);
22041 if (weight > 0) {
22042 coordEach(geom, function (coord) {
22043 sumXs += coord[0] * weight;
22044 sumYs += coord[1] * weight;
22045 sumNs += weight;
22046 });
22047 }
22048 });
22049 return point([sumXs / sumNs, sumYs / sumNs], properties);
22050}
22051
22052/**
22053 * Takes a {@link FeatureCollection} of points and calculates the median center,
22054 * algorithimically. The median center is understood as the point that is
22055 * requires the least total travel from all other points.
22056 *
22057 * Turfjs has four different functions for calculating the center of a set of
22058 * data. Each is useful depending on circumstance.
22059 *
22060 * `@turf/center` finds the simple center of a dataset, by finding the
22061 * midpoint between the extents of the data. That is, it divides in half the
22062 * farthest east and farthest west point as well as the farthest north and
22063 * farthest south.
22064 *
22065 * `@turf/center-of-mass` imagines that the dataset is a sheet of paper.
22066 * The center of mass is where the sheet would balance on a fingertip.
22067 *
22068 * `@turf/center-mean` takes the averages of all the coordinates and
22069 * produces a value that respects that. Unlike `@turf/center`, it is
22070 * sensitive to clusters and outliers. It lands in the statistical middle of a
22071 * dataset, not the geographical. It can also be weighted, meaning certain
22072 * points are more important than others.
22073 *
22074 * `@turf/center-median` takes the mean center and tries to find, iteratively,
22075 * a new point that requires the least amount of travel from all the points in
22076 * the dataset. It is not as sensitive to outliers as `@turf/center`, but it is
22077 * attracted to clustered data. It, too, can be weighted.
22078 *
22079 * **Bibliography**
22080 *
22081 * Harold W. Kuhn and Robert E. Kuenne, “An Efficient Algorithm for the
22082 * Numerical Solution of the Generalized Weber Problem in Spatial
22083 * Economics,” _Journal of Regional Science_ 4, no. 2 (1962): 21–33,
22084 * doi:{@link https://doi.org/10.1111/j.1467-9787.1962.tb00902.x}.
22085 *
22086 * James E. Burt, Gerald M. Barber, and David L. Rigby, _Elementary
22087 * Statistics for Geographers_, 3rd ed., New York: The Guilford
22088 * Press, 2009, 150–151.
22089 *
22090 * @name centerMedian
22091 * @param {FeatureCollection<any>} features Any GeoJSON Feature Collection
22092 * @param {Object} [options={}] Optional parameters
22093 * @param {string} [options.weight] the property name used to weight the center
22094 * @param {number} [options.tolerance=0.001] the difference in distance between candidate medians at which point the algorighim stops iterating.
22095 * @param {number} [options.counter=10] how many attempts to find the median, should the tolerance be insufficient.
22096 * @returns {Feature<Point>} The median center of the collection
22097 * @example
22098 * var points = turf.points([[0, 0], [1, 0], [0, 1], [5, 8]]);
22099 * var medianCenter = turf.centerMedian(points);
22100 *
22101 * //addToMap
22102 * var addToMap = [points, medianCenter]
22103 */
22104function centerMedian(features, options) {
22105 // Optional params
22106 options = options || {};
22107 if (!isObject(options)) throw new Error('options is invalid');
22108 var counter = options.counter || 10;
22109 if (!isNumber(counter)) throw new Error('counter must be a number');
22110 var weightTerm = options.weight;
22111
22112 // Calculate mean center:
22113 var meanCenter = centerMean(features, {weight: options.weight});
22114
22115 // Calculate center of every feature:
22116 var centroids = featureCollection([]);
22117 featureEach(features, function (feature$$1) {
22118 centroids.features.push(centroid(feature$$1, {weight: feature$$1.properties[weightTerm]}));
22119 });
22120
22121 centroids.properties = {
22122 tolerance: options.tolerance,
22123 medianCandidates: []
22124 };
22125 return findMedian(meanCenter.geometry.coordinates, [0, 0], centroids, counter);
22126}
22127
22128/**
22129 * Recursive function to find new candidate medians.
22130 *
22131 * @private
22132 * @param {Position} candidateMedian current candidate median
22133 * @param {Position} previousCandidate the previous candidate median
22134 * @param {FeatureCollection<Point>} centroids the collection of centroids whose median we are determining
22135 * @param {number} counter how many attempts to try before quitting.
22136 * @returns {Feature<Point>} the median center of the dataset.
22137 */
22138function findMedian(candidateMedian, previousCandidate, centroids, counter) {
22139 var tolerance = centroids.properties.tolerance || 0.001;
22140 var candidateXsum = 0;
22141 var candidateYsum = 0;
22142 var kSum = 0;
22143 var centroidCount = 0;
22144 featureEach(centroids, function (theCentroid) {
22145 var weightValue = theCentroid.properties.weight;
22146 var weight = (weightValue === undefined || weightValue === null) ? 1 : weightValue;
22147 weight = Number(weight);
22148 if (!isNumber(weight)) throw new Error('weight value must be a number');
22149 if (weight > 0) {
22150 centroidCount += 1;
22151 var distanceFromCandidate = weight * distance(theCentroid, candidateMedian);
22152 if (distanceFromCandidate === 0) distanceFromCandidate = 1;
22153 var k = weight / distanceFromCandidate;
22154 candidateXsum += theCentroid.geometry.coordinates[0] * k;
22155 candidateYsum += theCentroid.geometry.coordinates[1] * k;
22156 kSum += k;
22157 }
22158 });
22159 if (centroidCount < 1) throw new Error('no features to measure');
22160 var candidateX = candidateXsum / kSum;
22161 var candidateY = candidateYsum / kSum;
22162 if (centroidCount === 1 || counter === 0 || (Math.abs(candidateX - previousCandidate[0]) < tolerance && Math.abs(candidateY - previousCandidate[1]) < tolerance)) {
22163 return point([candidateX, candidateY], {medianCandidates: centroids.properties.medianCandidates});
22164 } else {
22165 centroids.properties.medianCandidates.push([candidateX, candidateY]);
22166 return findMedian([candidateX, candidateY], candidateMedian, centroids, counter - 1);
22167 }
22168}
22169
22170/**
22171 * Takes a {@link FeatureCollection} and returns a standard deviational ellipse,
22172 * also known as a “directional distribution.” The standard deviational ellipse
22173 * aims to show the direction and the distribution of a dataset by drawing
22174 * an ellipse that contains about one standard deviation’s worth (~ 70%) of the
22175 * data.
22176 *
22177 * This module mirrors the functionality of [Directional Distribution](http://desktop.arcgis.com/en/arcmap/10.3/tools/spatial-statistics-toolbox/directional-distribution.htm)
22178 * in ArcGIS and the [QGIS Standard Deviational Ellipse Plugin](http://arken.nmbu.no/~havatv/gis/qgisplugins/SDEllipse/)
22179 *
22180 * **Bibliography**
22181 *
22182 * • Robert S. Yuill, “The Standard Deviational Ellipse; An Updated Tool for
22183 * Spatial Description,” _Geografiska Annaler_ 53, no. 1 (1971): 28–39,
22184 * doi:{@link https://doi.org/10.2307/490885|10.2307/490885}.
22185 *
22186 * • Paul Hanly Furfey, “A Note on Lefever’s “Standard Deviational Ellipse,”
22187 * _American Journal of Sociology_ 33, no. 1 (1927): 94—98,
22188 * doi:{@link https://doi.org/10.1086/214336|10.1086/214336}.
22189 *
22190 *
22191 * @name standardDeviationalEllipse
22192 * @param {FeatureCollection<Point>} points GeoJSON points
22193 * @param {Object} [options={}] Optional parameters
22194 * @param {string} [options.weight] the property name used to weight the center
22195 * @param {number} [options.steps=64] number of steps for the polygon
22196 * @param {Object} [options.properties={}] properties to pass to the resulting ellipse
22197 * @returns {Feature<Polygon>} an elliptical Polygon that includes approximately 1 SD of the dataset within it.
22198 * @example
22199 *
22200 * var bbox = [-74, 40.72, -73.98, 40.74];
22201 * var points = turf.randomPoint(400, {bbox: bbox});
22202 * var sdEllipse = turf.standardDeviationalEllipse(points);
22203 *
22204 * //addToMap
22205 * var addToMap = [points, sdEllipse];
22206 *
22207 */
22208function standardDeviationalEllipse(points$$1, options) {
22209 // Optional params
22210 options = options || {};
22211 if (!isObject(options)) throw new Error('options is invalid');
22212 var steps = options.steps || 64;
22213 var weightTerm = options.weight;
22214 var properties = options.properties || {};
22215
22216 // Validation:
22217 if (!isNumber(steps)) throw new Error('steps must be a number');
22218 if (!isObject(properties)) throw new Error('properties must be a number');
22219
22220 // Calculate mean center & number of features:
22221 var numberOfFeatures = coordAll(points$$1).length;
22222 var meanCenter = centerMean(points$$1, {weight: weightTerm});
22223
22224 // Calculate angle of rotation:
22225 // [X, Y] = mean center of all [x, y].
22226 // theta = arctan( (A + B) / C )
22227 // A = sum((x - X)^2) - sum((y - Y)^2)
22228 // B = sqrt(A^2 + 4(sum((x - X)(y - Y))^2))
22229 // C = 2(sum((x - X)(y - Y)))
22230
22231 var xDeviationSquaredSum = 0;
22232 var yDeviationSquaredSum = 0;
22233 var xyDeviationSum = 0;
22234
22235 featureEach(points$$1, function (point$$1) {
22236 var weight = point$$1.properties[weightTerm] || 1;
22237 var deviation = getDeviations(getCoords(point$$1), getCoords(meanCenter));
22238 xDeviationSquaredSum += Math.pow(deviation.x, 2) * weight;
22239 yDeviationSquaredSum += Math.pow(deviation.y, 2) * weight;
22240 xyDeviationSum += deviation.x * deviation.y * weight;
22241 });
22242
22243 var bigA = xDeviationSquaredSum - yDeviationSquaredSum;
22244 var bigB = Math.sqrt(Math.pow(bigA, 2) + 4 * Math.pow(xyDeviationSum, 2));
22245 var bigC = 2 * xyDeviationSum;
22246 var theta = Math.atan((bigA + bigB) / bigC);
22247 var thetaDeg = theta * 180 / Math.PI;
22248
22249 // Calculate axes:
22250 // sigmaX = sqrt((1 / n - 2) * sum((((x - X) * cos(theta)) - ((y - Y) * sin(theta)))^2))
22251 // sigmaY = sqrt((1 / n - 2) * sum((((x - X) * sin(theta)) - ((y - Y) * cos(theta)))^2))
22252 var sigmaXsum = 0;
22253 var sigmaYsum = 0;
22254 var weightsum = 0;
22255 featureEach(points$$1, function (point$$1) {
22256 var weight = point$$1.properties[weightTerm] || 1;
22257 var deviation = getDeviations(getCoords(point$$1), getCoords(meanCenter));
22258 sigmaXsum += Math.pow((deviation.x * Math.cos(theta)) - (deviation.y * Math.sin(theta)), 2) * weight;
22259 sigmaYsum += Math.pow((deviation.x * Math.sin(theta)) + (deviation.y * Math.cos(theta)), 2) * weight;
22260 weightsum += weight;
22261 });
22262
22263 var sigmaX = Math.sqrt(2 * sigmaXsum / weightsum);
22264 var sigmaY = Math.sqrt(2 * sigmaYsum / weightsum);
22265
22266 var theEllipse = ellipse(meanCenter, sigmaX, sigmaY, {units: 'degrees', angle: thetaDeg, steps: steps, properties: properties});
22267 var pointsWithinEllipse = pointsWithinPolygon(points$$1, featureCollection([theEllipse]));
22268 var standardDeviationalEllipseProperties = {
22269 meanCenterCoordinates: getCoords(meanCenter),
22270 semiMajorAxis: sigmaX,
22271 semiMinorAxis: sigmaY,
22272 numberOfFeatures: numberOfFeatures,
22273 angle: thetaDeg,
22274 percentageWithinEllipse: 100 * coordAll(pointsWithinEllipse).length / numberOfFeatures
22275 };
22276 theEllipse.properties.standardDeviationalEllipse = standardDeviationalEllipseProperties;
22277
22278 return theEllipse;
22279}
22280
22281/**
22282 * Get x_i - X and y_i - Y
22283 *
22284 * @private
22285 * @param {Array} coordinates Array of [x_i, y_i]
22286 * @param {Array} center Array of [X, Y]
22287 * @returns {Object} { x: n, y: m }
22288 */
22289function getDeviations(coordinates, center) {
22290 return {
22291 x: coordinates[0] - center[0],
22292 y: coordinates[1] - center[1]
22293 };
22294}
22295
22296/**
22297 * Returns a random position within a {@link bounding box}.
22298 *
22299 * @name randomPosition
22300 * @param {Array<number>} [bbox=[-180, -90, 180, 90]] a bounding box inside of which positions are placed.
22301 * @returns {Array<number>} Position [longitude, latitude]
22302 * @example
22303 * var position = turf.randomPosition([-180, -90, 180, 90])
22304 * //=position
22305 */
22306function randomPosition(bbox) {
22307 if (isObject(bbox)) bbox = bbox.bbox;
22308 if (bbox && !Array.isArray(bbox)) throw new Error('bbox is invalid');
22309 if (bbox) return coordInBBox(bbox);
22310 else return [lon(), lat()];
22311}
22312
22313/**
22314 * Returns a random {@link point}.
22315 *
22316 * @name randomPoint
22317 * @param {number} [count=1] how many geometries will be generated
22318 * @param {Object} [options={}] Optional parameters
22319 * @param {Array<number>} [options.bbox=[-180, -90, 180, 90]] a bounding box inside of which geometries are placed.
22320 * @returns {FeatureCollection<Point>} GeoJSON FeatureCollection of points
22321 * @example
22322 * var points = turf.randomPoint(25, {bbox: [-180, -90, 180, 90]})
22323 * //=points
22324 */
22325function randomPoint(count, options) {
22326 // Optional parameters
22327 options = options || {};
22328 if (!isObject(options)) throw new Error('options is invalid');
22329 var bbox = options.bbox;
22330 if (count === undefined || count === null) count = 1;
22331
22332 var features = [];
22333 for (var i = 0; i < count; i++) {
22334 features.push(point(randomPosition(bbox)));
22335 }
22336 return featureCollection(features);
22337}
22338
22339/**
22340 * Returns a random {@link polygon}.
22341 *
22342 * @name randomPolygon
22343 * @param {number} [count=1] how many geometries will be generated
22344 * @param {Object} [options={}] Optional parameters
22345 * @param {Array<number>} [options.bbox=[-180, -90, 180, 90]] a bounding box inside of which geometries are placed.
22346 * @param {number} [options.num_vertices=10] is how many coordinates each LineString will contain.
22347 * @param {number} [options.max_radial_length=10] is the maximum number of decimal degrees latitude or longitude that a vertex can reach out of the center of the Polygon.
22348 * @returns {FeatureCollection<Point>} GeoJSON FeatureCollection of points
22349 * @example
22350 * var polygons = turf.randomPolygon(25, {bbox: [-180, -90, 180, 90]})
22351 * //=polygons
22352 */
22353function randomPolygon(count, options) {
22354 // Optional parameters
22355 options = options || {};
22356 if (!isObject(options)) throw new Error('options is invalid');
22357 var bbox = options.bbox;
22358 var num_vertices = options.num_vertices;
22359 var max_radial_length = options.max_radial_length;
22360 if (count === undefined || count === null) count = 1;
22361
22362 // Validation
22363 if (!isNumber(num_vertices)) num_vertices = 10;
22364 if (!isNumber(max_radial_length)) max_radial_length = 10;
22365
22366 var features = [];
22367 for (var i = 0; i < count; i++) {
22368 var vertices = [],
22369 circle_offsets = Array.apply(null,
22370 new Array(num_vertices + 1)).map(Math.random);
22371
22372 circle_offsets.forEach(sumOffsets);
22373 circle_offsets.forEach(scaleOffsets);
22374 vertices[vertices.length - 1] = vertices[0]; // close the ring
22375
22376 // center the polygon around something
22377 vertices = vertices.map(vertexToCoordinate(randomPosition(bbox)));
22378 features.push(polygon([vertices]));
22379 }
22380
22381 function sumOffsets(cur, index, arr) {
22382 arr[index] = (index > 0) ? cur + arr[index - 1] : cur;
22383 }
22384
22385 function scaleOffsets(cur) {
22386 cur = cur * 2 * Math.PI / circle_offsets[circle_offsets.length - 1];
22387 var radial_scaler = Math.random();
22388 vertices.push([
22389 radial_scaler * max_radial_length * Math.sin(cur),
22390 radial_scaler * max_radial_length * Math.cos(cur)
22391 ]);
22392 }
22393
22394 return featureCollection(features);
22395}
22396
22397/**
22398 * Returns a random {@link linestring}.
22399 *
22400 * @name randomLineString
22401 * @param {number} [count=1] how many geometries will be generated
22402 * @param {Object} [options={}] Optional parameters
22403 * @param {Array<number>} [options.bbox=[-180, -90, 180, 90]] a bounding box inside of which geometries are placed.
22404 * @param {number} [options.num_vertices=10] is how many coordinates each LineString will contain.
22405 * @param {number} [options.max_length=0.0001] is the maximum number of decimal degrees that a vertex can be from its predecessor
22406 * @param {number} [options.max_rotation=Math.PI / 8] is the maximum number of radians that a line segment can turn from the previous segment.
22407 * @returns {FeatureCollection<Point>} GeoJSON FeatureCollection of points
22408 * @example
22409 * var lineStrings = turf.randomLineString(25, {bbox: [-180, -90, 180, 90]})
22410 * //=lineStrings
22411 */
22412function randomLineString(count, options) {
22413 // Optional parameters
22414 options = options || {};
22415 if (!isObject(options)) throw new Error('options is invalid');
22416 var bbox = options.bbox;
22417 var num_vertices = options.num_vertices;
22418 var max_length = options.max_length;
22419 var max_rotation = options.max_rotation;
22420 if (count === undefined || count === null) count = 1;
22421
22422 // Default parameters
22423 if (!isNumber(num_vertices) || num_vertices < 2) num_vertices = 10;
22424 if (!isNumber(max_length)) max_length = 0.0001;
22425 if (!isNumber(max_rotation)) max_rotation = Math.PI / 8;
22426
22427 var features = [];
22428 for (var i = 0; i < count; i++) {
22429 var startingPoint = randomPosition(bbox);
22430 var vertices = [startingPoint];
22431 for (var j = 0; j < num_vertices - 1; j++) {
22432 var priorAngle = (j === 0) ?
22433 Math.random() * 2 * Math.PI :
22434 Math.tan(
22435 (vertices[j][1] - vertices[j - 1][1]) /
22436 (vertices[j][0] - vertices[j - 1][0])
22437 );
22438 var angle = priorAngle + (Math.random() - 0.5) * max_rotation * 2;
22439 var distance = Math.random() * max_length;
22440 vertices.push([
22441 vertices[j][0] + distance * Math.cos(angle),
22442 vertices[j][1] + distance * Math.sin(angle)
22443 ]);
22444 }
22445 features.push(lineString(vertices));
22446 }
22447
22448 return featureCollection(features);
22449}
22450
22451function vertexToCoordinate(hub) {
22452 return function (cur) { return [cur[0] + hub[0], cur[1] + hub[1]]; };
22453}
22454
22455function rnd() { return Math.random() - 0.5; }
22456function lon() { return rnd() * 360; }
22457function lat() { return rnd() * 180; }
22458
22459function coordInBBox(bbox) {
22460 return [
22461 (Math.random() * (bbox[2] - bbox[0])) + bbox[0],
22462 (Math.random() * (bbox[3] - bbox[1])) + bbox[1]];
22463}
22464
22465
22466
22467
22468var main_es$4 = Object.freeze({
22469 randomPosition: randomPosition,
22470 randomPoint: randomPoint,
22471 randomPolygon: randomPolygon,
22472 randomLineString: randomLineString
22473});
22474
22475/**
22476 * Get Cluster
22477 *
22478 * @name getCluster
22479 * @param {FeatureCollection} geojson GeoJSON Features
22480 * @param {*} filter Filter used on GeoJSON properties to get Cluster
22481 * @returns {FeatureCollection} Single Cluster filtered by GeoJSON Properties
22482 * @example
22483 * var geojson = turf.featureCollection([
22484 * turf.point([0, 0], {'marker-symbol': 'circle'}),
22485 * turf.point([2, 4], {'marker-symbol': 'star'}),
22486 * turf.point([3, 6], {'marker-symbol': 'star'}),
22487 * turf.point([5, 1], {'marker-symbol': 'square'}),
22488 * turf.point([4, 2], {'marker-symbol': 'circle'})
22489 * ]);
22490 *
22491 * // Create a cluster using K-Means (adds `cluster` to GeoJSON properties)
22492 * var clustered = turf.clustersKmeans(geojson);
22493 *
22494 * // Retrieve first cluster (0)
22495 * var cluster = turf.getCluster(clustered, {cluster: 0});
22496 * //= cluster
22497 *
22498 * // Retrieve cluster based on custom properties
22499 * turf.getCluster(clustered, {'marker-symbol': 'circle'}).length;
22500 * //= 2
22501 * turf.getCluster(clustered, {'marker-symbol': 'square'}).length;
22502 * //= 1
22503 */
22504function getCluster(geojson, filter) {
22505 // Validation
22506 if (!geojson) throw new Error('geojson is required');
22507 if (geojson.type !== 'FeatureCollection') throw new Error('geojson must be a FeatureCollection');
22508 if (filter === undefined || filter === null) throw new Error('filter is required');
22509
22510 // Filter Features
22511 var features = [];
22512 featureEach(geojson, function (feature$$1) {
22513 if (applyFilter(feature$$1.properties, filter)) features.push(feature$$1);
22514 });
22515 return featureCollection(features);
22516}
22517
22518/**
22519 * Callback for clusterEach
22520 *
22521 * @callback clusterEachCallback
22522 * @param {FeatureCollection} [cluster] The current cluster being processed.
22523 * @param {*} [clusterValue] Value used to create cluster being processed.
22524 * @param {number} [currentIndex] The index of the current element being processed in the array.Starts at index 0
22525 * @returns {void}
22526 */
22527
22528/**
22529 * clusterEach
22530 *
22531 * @name clusterEach
22532 * @param {FeatureCollection} geojson GeoJSON Features
22533 * @param {string|number} property GeoJSON property key/value used to create clusters
22534 * @param {Function} callback a method that takes (cluster, clusterValue, currentIndex)
22535 * @returns {void}
22536 * @example
22537 * var geojson = turf.featureCollection([
22538 * turf.point([0, 0]),
22539 * turf.point([2, 4]),
22540 * turf.point([3, 6]),
22541 * turf.point([5, 1]),
22542 * turf.point([4, 2])
22543 * ]);
22544 *
22545 * // Create a cluster using K-Means (adds `cluster` to GeoJSON properties)
22546 * var clustered = turf.clustersKmeans(geojson);
22547 *
22548 * // Iterate over each cluster
22549 * turf.clusterEach(clustered, 'cluster', function (cluster, clusterValue, currentIndex) {
22550 * //= cluster
22551 * //= clusterValue
22552 * //= currentIndex
22553 * })
22554 *
22555 * // Calculate the total number of clusters
22556 * var total = 0
22557 * turf.clusterEach(clustered, 'cluster', function () {
22558 * total++;
22559 * });
22560 *
22561 * // Create an Array of all the values retrieved from the 'cluster' property
22562 * var values = []
22563 * turf.clusterEach(clustered, 'cluster', function (cluster, clusterValue) {
22564 * values.push(clusterValue);
22565 * });
22566 */
22567function clusterEach(geojson, property, callback) {
22568 // Validation
22569 if (!geojson) throw new Error('geojson is required');
22570 if (geojson.type !== 'FeatureCollection') throw new Error('geojson must be a FeatureCollection');
22571 if (property === undefined || property === null) throw new Error('property is required');
22572
22573 // Create clusters based on property values
22574 var bins = createBins(geojson, property);
22575 var values = Object.keys(bins);
22576 for (var index = 0; index < values.length; index++) {
22577 var value = values[index];
22578 var bin = bins[value];
22579 var features = [];
22580 for (var i = 0; i < bin.length; i++) {
22581 features.push(geojson.features[bin[i]]);
22582 }
22583 callback(featureCollection(features), value, index);
22584 }
22585}
22586
22587/**
22588 * Callback for clusterReduce
22589 *
22590 * The first time the callback function is called, the values provided as arguments depend
22591 * on whether the reduce method has an initialValue argument.
22592 *
22593 * If an initialValue is provided to the reduce method:
22594 * - The previousValue argument is initialValue.
22595 * - The currentValue argument is the value of the first element present in the array.
22596 *
22597 * If an initialValue is not provided:
22598 * - The previousValue argument is the value of the first element present in the array.
22599 * - The currentValue argument is the value of the second element present in the array.
22600 *
22601 * @callback clusterReduceCallback
22602 * @param {*} [previousValue] The accumulated value previously returned in the last invocation
22603 * of the callback, or initialValue, if supplied.
22604 * @param {FeatureCollection} [cluster] The current cluster being processed.
22605 * @param {*} [clusterValue] Value used to create cluster being processed.
22606 * @param {number} [currentIndex] The index of the current element being processed in the
22607 * array. Starts at index 0, if an initialValue is provided, and at index 1 otherwise.
22608 */
22609
22610/**
22611 * Reduce clusters in GeoJSON Features, similar to Array.reduce()
22612 *
22613 * @name clusterReduce
22614 * @param {FeatureCollection} geojson GeoJSON Features
22615 * @param {string|number} property GeoJSON property key/value used to create clusters
22616 * @param {Function} callback a method that takes (previousValue, cluster, clusterValue, currentIndex)
22617 * @param {*} [initialValue] Value to use as the first argument to the first call of the callback.
22618 * @returns {*} The value that results from the reduction.
22619 * @example
22620 * var geojson = turf.featureCollection([
22621 * turf.point([0, 0]),
22622 * turf.point([2, 4]),
22623 * turf.point([3, 6]),
22624 * turf.point([5, 1]),
22625 * turf.point([4, 2])
22626 * ]);
22627 *
22628 * // Create a cluster using K-Means (adds `cluster` to GeoJSON properties)
22629 * var clustered = turf.clustersKmeans(geojson);
22630 *
22631 * // Iterate over each cluster and perform a calculation
22632 * var initialValue = 0
22633 * turf.clusterReduce(clustered, 'cluster', function (previousValue, cluster, clusterValue, currentIndex) {
22634 * //=previousValue
22635 * //=cluster
22636 * //=clusterValue
22637 * //=currentIndex
22638 * return previousValue++;
22639 * }, initialValue);
22640 *
22641 * // Calculate the total number of clusters
22642 * var total = turf.clusterReduce(clustered, 'cluster', function (previousValue) {
22643 * return previousValue++;
22644 * }, 0);
22645 *
22646 * // Create an Array of all the values retrieved from the 'cluster' property
22647 * var values = turf.clusterReduce(clustered, 'cluster', function (previousValue, cluster, clusterValue) {
22648 * return previousValue.concat(clusterValue);
22649 * }, []);
22650 */
22651function clusterReduce(geojson, property, callback, initialValue) {
22652 var previousValue = initialValue;
22653 clusterEach(geojson, property, function (cluster, clusterValue, currentIndex) {
22654 if (currentIndex === 0 && initialValue === undefined) previousValue = cluster;
22655 else previousValue = callback(previousValue, cluster, clusterValue, currentIndex);
22656 });
22657 return previousValue;
22658}
22659
22660/**
22661 * Create Bins
22662 *
22663 * @private
22664 * @param {FeatureCollection} geojson GeoJSON Features
22665 * @param {string|number} property Property values are used to create bins
22666 * @returns {Object} bins with Feature IDs
22667 * @example
22668 * var geojson = turf.featureCollection([
22669 * turf.point([0, 0], {cluster: 0, foo: 'null'}),
22670 * turf.point([2, 4], {cluster: 1, foo: 'bar'}),
22671 * turf.point([5, 1], {0: 'foo'}),
22672 * turf.point([3, 6], {cluster: 1}),
22673 * ]);
22674 * createBins(geojson, 'cluster');
22675 * //= { '0': [ 0 ], '1': [ 1, 3 ] }
22676 */
22677function createBins(geojson, property) {
22678 var bins = {};
22679
22680 featureEach(geojson, function (feature$$1, i) {
22681 var properties = feature$$1.properties || {};
22682 if (properties.hasOwnProperty(property)) {
22683 var value = properties[property];
22684 if (bins.hasOwnProperty(value)) bins[value].push(i);
22685 else bins[value] = [i];
22686 }
22687 });
22688 return bins;
22689}
22690
22691/**
22692 * Apply Filter
22693 *
22694 * @private
22695 * @param {*} properties Properties
22696 * @param {*} filter Filter
22697 * @returns {boolean} applied Filter to properties
22698 */
22699function applyFilter(properties, filter) {
22700 if (properties === undefined) return false;
22701 var filterType = typeof filter;
22702
22703 // String & Number
22704 if (filterType === 'number' || filterType === 'string') return properties.hasOwnProperty(filter);
22705 // Array
22706 else if (Array.isArray(filter)) {
22707 for (var i = 0; i < filter.length; i++) {
22708 if (!applyFilter(properties, filter[i])) return false;
22709 }
22710 return true;
22711 // Object
22712 } else {
22713 return propertiesContainsFilter(properties, filter);
22714 }
22715}
22716
22717/**
22718 * Properties contains filter (does not apply deepEqual operations)
22719 *
22720 * @private
22721 * @param {*} properties Properties
22722 * @param {Object} filter Filter
22723 * @returns {boolean} does filter equal Properties
22724 * @example
22725 * propertiesContainsFilter({foo: 'bar', cluster: 0}, {cluster: 0})
22726 * //= true
22727 * propertiesContainsFilter({foo: 'bar', cluster: 0}, {cluster: 1})
22728 * //= false
22729 */
22730function propertiesContainsFilter(properties, filter) {
22731 var keys = Object.keys(filter);
22732 for (var i = 0; i < keys.length; i++) {
22733 var key = keys[i];
22734 if (properties[key] !== filter[key]) return false;
22735 }
22736 return true;
22737}
22738
22739/**
22740 * Filter Properties
22741 *
22742 * @private
22743 * @param {*} properties Properties
22744 * @param {Array<string>} keys Used to filter Properties
22745 * @returns {*} filtered Properties
22746 * @example
22747 * filterProperties({foo: 'bar', cluster: 0}, ['cluster'])
22748 * //= {cluster: 0}
22749 */
22750function filterProperties(properties, keys) {
22751 if (!keys) return {};
22752 if (!keys.length) return {};
22753
22754 var newProperties = {};
22755 for (var i = 0; i < keys.length; i++) {
22756 var key = keys[i];
22757 if (properties.hasOwnProperty(key)) newProperties[key] = properties[key];
22758 }
22759 return newProperties;
22760}
22761
22762
22763
22764
22765var main_es$5 = Object.freeze({
22766 getCluster: getCluster,
22767 clusterEach: clusterEach,
22768 clusterReduce: clusterReduce,
22769 createBins: createBins,
22770 applyFilter: applyFilter,
22771 propertiesContainsFilter: propertiesContainsFilter,
22772 filterProperties: filterProperties
22773});
22774
22775/* Polyfill service v3.13.0
22776 * For detailed credits and licence information see http://github.com/financial-times/polyfill-service
22777 *
22778 * - Array.prototype.fill, License: CC0 */
22779
22780if (!('fill' in Array.prototype)) {
22781 Object.defineProperty(Array.prototype, 'fill', {
22782 configurable: true,
22783 value: function fill (value) {
22784 if (this === undefined || this === null) {
22785 throw new TypeError(this + ' is not an object')
22786 }
22787
22788 var arrayLike = Object(this);
22789
22790 var length = Math.max(Math.min(arrayLike.length, 9007199254740991), 0) || 0;
22791
22792 var relativeStart = 1 in arguments ? parseInt(Number(arguments[1]), 10) || 0 : 0;
22793
22794 relativeStart = relativeStart < 0 ? Math.max(length + relativeStart, 0) : Math.min(relativeStart, length);
22795
22796 var relativeEnd = 2 in arguments && arguments[2] !== undefined ? parseInt(Number(arguments[2]), 10) || 0 : length;
22797
22798 relativeEnd = relativeEnd < 0 ? Math.max(length + arguments[2], 0) : Math.min(relativeEnd, length);
22799
22800 while (relativeStart < relativeEnd) {
22801 arrayLike[relativeStart] = value;
22802
22803 ++relativeStart;
22804 }
22805
22806 return arrayLike
22807 },
22808 writable: true
22809 });
22810}
22811
22812/**
22813 * Polyfill for IE support
22814 */
22815Number.isFinite = Number.isFinite || function (value) {
22816 return typeof value === 'number' && isFinite(value)
22817};
22818
22819Number.isInteger = Number.isInteger || function (val) {
22820 return typeof val === 'number' &&
22821 isFinite(val) &&
22822 Math.floor(val) === val
22823};
22824
22825Number.parseFloat = Number.parseFloat || parseFloat;
22826
22827Number.isNaN = Number.isNaN || function (value) {
22828 return value !== value // eslint-disable-line
22829};
22830
22831/**
22832 * Polyfill for IE support
22833 */
22834Math.trunc = Math.trunc || function (x) {
22835 return x < 0 ? Math.ceil(x) : Math.floor(x)
22836};
22837
22838var NumberUtil = function NumberUtil () {};
22839
22840NumberUtil.prototype.interfaces_ = function interfaces_ () {
22841 return []
22842};
22843NumberUtil.prototype.getClass = function getClass () {
22844 return NumberUtil
22845};
22846NumberUtil.prototype.equalsWithTolerance = function equalsWithTolerance (x1, x2, tolerance) {
22847 return Math.abs(x1 - x2) <= tolerance
22848};
22849
22850var IllegalArgumentException = function IllegalArgumentException () {};
22851
22852var Double = function Double () {};
22853
22854var staticAccessors$1 = { MAX_VALUE: { configurable: true } };
22855
22856Double.isNaN = function isNaN (n) { return Number.isNaN(n) };
22857Double.doubleToLongBits = function doubleToLongBits (n) { return n };
22858Double.longBitsToDouble = function longBitsToDouble (n) { return n };
22859Double.isInfinite = function isInfinite (n) { return !Number.isFinite(n) };
22860staticAccessors$1.MAX_VALUE.get = function () { return Number.MAX_VALUE };
22861
22862Object.defineProperties( Double, staticAccessors$1 );
22863
22864var Comparable = function Comparable () {};
22865
22866var Clonable = function Clonable () {};
22867
22868var Comparator = function Comparator () {};
22869
22870function Serializable () {}
22871
22872// import Assert from '../util/Assert'
22873
22874var Coordinate = function Coordinate () {
22875 this.x = null;
22876 this.y = null;
22877 this.z = null;
22878 if (arguments.length === 0) {
22879 this.x = 0.0;
22880 this.y = 0.0;
22881 this.z = Coordinate.NULL_ORDINATE;
22882 } else if (arguments.length === 1) {
22883 var c = arguments[0];
22884 this.x = c.x;
22885 this.y = c.y;
22886 this.z = c.z;
22887 } else if (arguments.length === 2) {
22888 this.x = arguments[0];
22889 this.y = arguments[1];
22890 this.z = Coordinate.NULL_ORDINATE;
22891 } else if (arguments.length === 3) {
22892 this.x = arguments[0];
22893 this.y = arguments[1];
22894 this.z = arguments[2];
22895 }
22896};
22897
22898var staticAccessors = { DimensionalComparator: { configurable: true },serialVersionUID: { configurable: true },NULL_ORDINATE: { configurable: true },X: { configurable: true },Y: { configurable: true },Z: { configurable: true } };
22899Coordinate.prototype.setOrdinate = function setOrdinate (ordinateIndex, value) {
22900 switch (ordinateIndex) {
22901 case Coordinate.X:
22902 this.x = value;
22903 break
22904 case Coordinate.Y:
22905 this.y = value;
22906 break
22907 case Coordinate.Z:
22908 this.z = value;
22909 break
22910 default:
22911 throw new IllegalArgumentException('Invalid ordinate index: ' + ordinateIndex)
22912 }
22913};
22914Coordinate.prototype.equals2D = function equals2D () {
22915 if (arguments.length === 1) {
22916 var other = arguments[0];
22917 if (this.x !== other.x) {
22918 return false
22919 }
22920 if (this.y !== other.y) {
22921 return false
22922 }
22923 return true
22924 } else if (arguments.length === 2) {
22925 var c = arguments[0];
22926 var tolerance = arguments[1];
22927 if (!NumberUtil.equalsWithTolerance(this.x, c.x, tolerance)) {
22928 return false
22929 }
22930 if (!NumberUtil.equalsWithTolerance(this.y, c.y, tolerance)) {
22931 return false
22932 }
22933 return true
22934 }
22935};
22936Coordinate.prototype.getOrdinate = function getOrdinate (ordinateIndex) {
22937 switch (ordinateIndex) {
22938 case Coordinate.X:
22939 return this.x
22940 case Coordinate.Y:
22941 return this.y
22942 case Coordinate.Z:
22943 return this.z
22944 default:
22945 }
22946 throw new IllegalArgumentException('Invalid ordinate index: ' + ordinateIndex)
22947};
22948Coordinate.prototype.equals3D = function equals3D (other) {
22949 return this.x === other.x &&
22950 this.y === other.y &&
22951 ((this.z === other.z || Double.isNaN(this.z)) &&
22952 Double.isNaN(other.z))
22953};
22954Coordinate.prototype.equals = function equals (other) {
22955 if (!(other instanceof Coordinate)) {
22956 return false
22957 }
22958 return this.equals2D(other)
22959};
22960Coordinate.prototype.equalInZ = function equalInZ (c, tolerance) {
22961 return NumberUtil.equalsWithTolerance(this.z, c.z, tolerance)
22962};
22963Coordinate.prototype.compareTo = function compareTo (o) {
22964 var other = o;
22965 if (this.x < other.x) { return -1 }
22966 if (this.x > other.x) { return 1 }
22967 if (this.y < other.y) { return -1 }
22968 if (this.y > other.y) { return 1 }
22969 return 0
22970};
22971Coordinate.prototype.clone = function clone () {
22972 // try {
22973 // var coord = null
22974 // return coord
22975 // } catch (e) {
22976 // if (e instanceof CloneNotSupportedException) {
22977 // Assert.shouldNeverReachHere("this shouldn't happen because this class is Cloneable")
22978 // return null
22979 // } else throw e
22980 // } finally {}
22981};
22982Coordinate.prototype.copy = function copy () {
22983 return new Coordinate(this)
22984};
22985Coordinate.prototype.toString = function toString () {
22986 return '(' + this.x + ', ' + this.y + ', ' + this.z + ')'
22987};
22988Coordinate.prototype.distance3D = function distance3D (c) {
22989 var dx = this.x - c.x;
22990 var dy = this.y - c.y;
22991 var dz = this.z - c.z;
22992 return Math.sqrt(dx * dx + dy * dy + dz * dz)
22993};
22994Coordinate.prototype.distance = function distance (c) {
22995 var dx = this.x - c.x;
22996 var dy = this.y - c.y;
22997 return Math.sqrt(dx * dx + dy * dy)
22998};
22999Coordinate.prototype.hashCode = function hashCode () {
23000 var result = 17;
23001 result = 37 * result + Coordinate.hashCode(this.x);
23002 result = 37 * result + Coordinate.hashCode(this.y);
23003 return result
23004};
23005Coordinate.prototype.setCoordinate = function setCoordinate (other) {
23006 this.x = other.x;
23007 this.y = other.y;
23008 this.z = other.z;
23009};
23010Coordinate.prototype.interfaces_ = function interfaces_ () {
23011 return [Comparable, Clonable, Serializable]
23012};
23013Coordinate.prototype.getClass = function getClass () {
23014 return Coordinate
23015};
23016Coordinate.hashCode = function hashCode () {
23017 if (arguments.length === 1) {
23018 var x = arguments[0];
23019 var f = Double.doubleToLongBits(x);
23020 return Math.trunc((f ^ f) >>> 32)
23021 }
23022};
23023staticAccessors.DimensionalComparator.get = function () { return DimensionalComparator };
23024staticAccessors.serialVersionUID.get = function () { return 6683108902428366910 };
23025staticAccessors.NULL_ORDINATE.get = function () { return Double.NaN };
23026staticAccessors.X.get = function () { return 0 };
23027staticAccessors.Y.get = function () { return 1 };
23028staticAccessors.Z.get = function () { return 2 };
23029
23030Object.defineProperties( Coordinate, staticAccessors );
23031
23032var DimensionalComparator = function DimensionalComparator (dimensionsToTest) {
23033 this._dimensionsToTest = 2;
23034 if (arguments.length === 0) {} else if (arguments.length === 1) {
23035 var dimensionsToTest$1 = arguments[0];
23036 if (dimensionsToTest$1 !== 2 && dimensionsToTest$1 !== 3) { throw new IllegalArgumentException('only 2 or 3 dimensions may be specified') }
23037 this._dimensionsToTest = dimensionsToTest$1;
23038 }
23039};
23040DimensionalComparator.prototype.compare = function compare (o1, o2) {
23041 var c1 = o1;
23042 var c2 = o2;
23043 var compX = DimensionalComparator.compare(c1.x, c2.x);
23044 if (compX !== 0) { return compX }
23045 var compY = DimensionalComparator.compare(c1.y, c2.y);
23046 if (compY !== 0) { return compY }
23047 if (this._dimensionsToTest <= 2) { return 0 }
23048 var compZ = DimensionalComparator.compare(c1.z, c2.z);
23049 return compZ
23050};
23051DimensionalComparator.prototype.interfaces_ = function interfaces_ () {
23052 return [Comparator]
23053};
23054DimensionalComparator.prototype.getClass = function getClass () {
23055 return DimensionalComparator
23056};
23057DimensionalComparator.compare = function compare (a, b) {
23058 if (a < b) { return -1 }
23059 if (a > b) { return 1 }
23060 if (Double.isNaN(a)) {
23061 if (Double.isNaN(b)) { return 0 }
23062 return -1
23063 }
23064 if (Double.isNaN(b)) { return 1 }
23065 return 0
23066};
23067
23068// import hasInterface from '../../../../hasInterface'
23069// import CoordinateSequence from './CoordinateSequence'
23070
23071var CoordinateSequenceFactory = function CoordinateSequenceFactory () {};
23072
23073CoordinateSequenceFactory.prototype.create = function create () {
23074 // if (arguments.length === 1) {
23075 // if (arguments[0] instanceof Array) {
23076 // let coordinates = arguments[0]
23077 // } else if (hasInterface(arguments[0], CoordinateSequence)) {
23078 // let coordSeq = arguments[0]
23079 // }
23080 // } else if (arguments.length === 2) {
23081 // let size = arguments[0]
23082 // let dimension = arguments[1]
23083 // }
23084};
23085CoordinateSequenceFactory.prototype.interfaces_ = function interfaces_ () {
23086 return []
23087};
23088CoordinateSequenceFactory.prototype.getClass = function getClass () {
23089 return CoordinateSequenceFactory
23090};
23091
23092var Location = function Location () {};
23093
23094var staticAccessors$4 = { INTERIOR: { configurable: true },BOUNDARY: { configurable: true },EXTERIOR: { configurable: true },NONE: { configurable: true } };
23095
23096Location.prototype.interfaces_ = function interfaces_ () {
23097 return []
23098};
23099Location.prototype.getClass = function getClass () {
23100 return Location
23101};
23102Location.toLocationSymbol = function toLocationSymbol (locationValue) {
23103 switch (locationValue) {
23104 case Location.EXTERIOR:
23105 return 'e'
23106 case Location.BOUNDARY:
23107 return 'b'
23108 case Location.INTERIOR:
23109 return 'i'
23110 case Location.NONE:
23111 return '-'
23112 default:
23113 }
23114 throw new IllegalArgumentException('Unknown location value: ' + locationValue)
23115};
23116staticAccessors$4.INTERIOR.get = function () { return 0 };
23117staticAccessors$4.BOUNDARY.get = function () { return 1 };
23118staticAccessors$4.EXTERIOR.get = function () { return 2 };
23119staticAccessors$4.NONE.get = function () { return -1 };
23120
23121Object.defineProperties( Location, staticAccessors$4 );
23122
23123var hasInterface = function (o, i) {
23124 return o.interfaces_ && o.interfaces_().indexOf(i) > -1
23125};
23126
23127var MathUtil = function MathUtil () {};
23128
23129var staticAccessors$5 = { LOG_10: { configurable: true } };
23130
23131MathUtil.prototype.interfaces_ = function interfaces_ () {
23132 return []
23133};
23134MathUtil.prototype.getClass = function getClass () {
23135 return MathUtil
23136};
23137MathUtil.log10 = function log10 (x) {
23138 var ln = Math.log(x);
23139 if (Double.isInfinite(ln)) { return ln }
23140 if (Double.isNaN(ln)) { return ln }
23141 return ln / MathUtil.LOG_10
23142};
23143MathUtil.min = function min (v1, v2, v3, v4) {
23144 var min = v1;
23145 if (v2 < min) { min = v2; }
23146 if (v3 < min) { min = v3; }
23147 if (v4 < min) { min = v4; }
23148 return min
23149};
23150MathUtil.clamp = function clamp () {
23151 if (typeof arguments[2] === 'number' && (typeof arguments[0] === 'number' && typeof arguments[1] === 'number')) {
23152 var x = arguments[0];
23153 var min = arguments[1];
23154 var max = arguments[2];
23155 if (x < min) { return min }
23156 if (x > max) { return max }
23157 return x
23158 } else if (Number.isInteger(arguments[2]) && (Number.isInteger(arguments[0]) && Number.isInteger(arguments[1]))) {
23159 var x$1 = arguments[0];
23160 var min$1 = arguments[1];
23161 var max$1 = arguments[2];
23162 if (x$1 < min$1) { return min$1 }
23163 if (x$1 > max$1) { return max$1 }
23164 return x$1
23165 }
23166};
23167MathUtil.wrap = function wrap (index, max) {
23168 if (index < 0) {
23169 return max - -index % max
23170 }
23171 return index % max
23172};
23173MathUtil.max = function max () {
23174 if (arguments.length === 3) {
23175 var v1 = arguments[0];
23176 var v2 = arguments[1];
23177 var v3 = arguments[2];
23178 var max = v1;
23179 if (v2 > max) { max = v2; }
23180 if (v3 > max) { max = v3; }
23181 return max
23182 } else if (arguments.length === 4) {
23183 var v1$1 = arguments[0];
23184 var v2$1 = arguments[1];
23185 var v3$1 = arguments[2];
23186 var v4 = arguments[3];
23187 var max$1 = v1$1;
23188 if (v2$1 > max$1) { max$1 = v2$1; }
23189 if (v3$1 > max$1) { max$1 = v3$1; }
23190 if (v4 > max$1) { max$1 = v4; }
23191 return max$1
23192 }
23193};
23194MathUtil.average = function average (x1, x2) {
23195 return (x1 + x2) / 2.0
23196};
23197staticAccessors$5.LOG_10.get = function () { return Math.log(10) };
23198
23199Object.defineProperties( MathUtil, staticAccessors$5 );
23200
23201var StringBuffer = function StringBuffer (str) {
23202 this.str = str;
23203};
23204StringBuffer.prototype.append = function append (e) {
23205 this.str += e;
23206};
23207
23208StringBuffer.prototype.setCharAt = function setCharAt (i, c) {
23209 this.str = this.str.substr(0, i) + c + this.str.substr(i + 1);
23210};
23211
23212StringBuffer.prototype.toString = function toString (e) {
23213 return this.str
23214};
23215
23216var Integer = function Integer (value) {
23217 this.value = value;
23218};
23219Integer.prototype.intValue = function intValue () {
23220 return this.value
23221};
23222Integer.prototype.compareTo = function compareTo (o) {
23223 if (this.value < o) { return -1 }
23224 if (this.value > o) { return 1 }
23225 return 0
23226};
23227Integer.isNaN = function isNaN (n) { return Number.isNaN(n) };
23228
23229var Character = function Character () {};
23230
23231Character.isWhitespace = function isWhitespace (c) { return ((c <= 32 && c >= 0) || c === 127) };
23232Character.toUpperCase = function toUpperCase (c) { return c.toUpperCase() };
23233
23234var DD = function DD () {
23235 this._hi = 0.0;
23236 this._lo = 0.0;
23237 if (arguments.length === 0) {
23238 this.init(0.0);
23239 } else if (arguments.length === 1) {
23240 if (typeof arguments[0] === 'number') {
23241 var x = arguments[0];
23242 this.init(x);
23243 } else if (arguments[0] instanceof DD) {
23244 var dd = arguments[0];
23245 this.init(dd);
23246 } else if (typeof arguments[0] === 'string') {
23247 var str = arguments[0];
23248 DD.call(this, DD.parse(str));
23249 }
23250 } else if (arguments.length === 2) {
23251 var hi = arguments[0];
23252 var lo = arguments[1];
23253 this.init(hi, lo);
23254 }
23255};
23256
23257var staticAccessors$7 = { PI: { configurable: true },TWO_PI: { configurable: true },PI_2: { configurable: true },E: { configurable: true },NaN: { configurable: true },EPS: { configurable: true },SPLIT: { configurable: true },MAX_PRINT_DIGITS: { configurable: true },TEN: { configurable: true },ONE: { configurable: true },SCI_NOT_EXPONENT_CHAR: { configurable: true },SCI_NOT_ZERO: { configurable: true } };
23258DD.prototype.le = function le (y) {
23259 return (this._hi < y._hi || this._hi === y._hi) && this._lo <= y._lo
23260};
23261DD.prototype.extractSignificantDigits = function extractSignificantDigits (insertDecimalPoint, magnitude) {
23262 var y = this.abs();
23263 var mag = DD.magnitude(y._hi);
23264 var scale = DD.TEN.pow(mag);
23265 y = y.divide(scale);
23266 if (y.gt(DD.TEN)) {
23267 y = y.divide(DD.TEN);
23268 mag += 1;
23269 } else if (y.lt(DD.ONE)) {
23270 y = y.multiply(DD.TEN);
23271 mag -= 1;
23272 }
23273 var decimalPointPos = mag + 1;
23274 var buf = new StringBuffer();
23275 var numDigits = DD.MAX_PRINT_DIGITS - 1;
23276 for (var i = 0; i <= numDigits; i++) {
23277 if (insertDecimalPoint && i === decimalPointPos) {
23278 buf.append('.');
23279 }
23280 var digit = Math.trunc(y._hi);
23281 if (digit < 0) {
23282 break
23283 }
23284 var rebiasBy10 = false;
23285 var digitChar = 0;
23286 if (digit > 9) {
23287 rebiasBy10 = true;
23288 digitChar = '9';
23289 } else {
23290 digitChar = '0' + digit;
23291 }
23292 buf.append(digitChar);
23293 y = y.subtract(DD.valueOf(digit)).multiply(DD.TEN);
23294 if (rebiasBy10) { y.selfAdd(DD.TEN); }
23295 var continueExtractingDigits = true;
23296 var remMag = DD.magnitude(y._hi);
23297 if (remMag < 0 && Math.abs(remMag) >= numDigits - i) { continueExtractingDigits = false; }
23298 if (!continueExtractingDigits) { break }
23299 }
23300 magnitude[0] = mag;
23301 return buf.toString()
23302};
23303DD.prototype.sqr = function sqr () {
23304 return this.multiply(this)
23305};
23306DD.prototype.doubleValue = function doubleValue () {
23307 return this._hi + this._lo
23308};
23309DD.prototype.subtract = function subtract () {
23310 if (arguments[0] instanceof DD) {
23311 var y = arguments[0];
23312 return this.add(y.negate())
23313 } else if (typeof arguments[0] === 'number') {
23314 var y$1 = arguments[0];
23315 return this.add(-y$1)
23316 }
23317};
23318DD.prototype.equals = function equals () {
23319 if (arguments.length === 1) {
23320 var y = arguments[0];
23321 return this._hi === y._hi && this._lo === y._lo
23322 }
23323};
23324DD.prototype.isZero = function isZero () {
23325 return this._hi === 0.0 && this._lo === 0.0
23326};
23327DD.prototype.selfSubtract = function selfSubtract () {
23328 if (arguments[0] instanceof DD) {
23329 var y = arguments[0];
23330 if (this.isNaN()) { return this }
23331 return this.selfAdd(-y._hi, -y._lo)
23332 } else if (typeof arguments[0] === 'number') {
23333 var y$1 = arguments[0];
23334 if (this.isNaN()) { return this }
23335 return this.selfAdd(-y$1, 0.0)
23336 }
23337};
23338DD.prototype.getSpecialNumberString = function getSpecialNumberString () {
23339 if (this.isZero()) { return '0.0' }
23340 if (this.isNaN()) { return 'NaN ' }
23341 return null
23342};
23343DD.prototype.min = function min (x) {
23344 if (this.le(x)) {
23345 return this
23346 } else {
23347 return x
23348 }
23349};
23350DD.prototype.selfDivide = function selfDivide () {
23351 if (arguments.length === 1) {
23352 if (arguments[0] instanceof DD) {
23353 var y = arguments[0];
23354 return this.selfDivide(y._hi, y._lo)
23355 } else if (typeof arguments[0] === 'number') {
23356 var y$1 = arguments[0];
23357 return this.selfDivide(y$1, 0.0)
23358 }
23359 } else if (arguments.length === 2) {
23360 var yhi = arguments[0];
23361 var ylo = arguments[1];
23362 var hc = null;
23363 var tc = null;
23364 var hy = null;
23365 var ty = null;
23366 var C = null;
23367 var c = null;
23368 var U = null;
23369 var u = null;
23370 C = this._hi / yhi;
23371 c = DD.SPLIT * C;
23372 hc = c - C;
23373 u = DD.SPLIT * yhi;
23374 hc = c - hc;
23375 tc = C - hc;
23376 hy = u - yhi;
23377 U = C * yhi;
23378 hy = u - hy;
23379 ty = yhi - hy;
23380 u = hc * hy - U + hc * ty + tc * hy + tc * ty;
23381 c = (this._hi - U - u + this._lo - C * ylo) / yhi;
23382 u = C + c;
23383 this._hi = u;
23384 this._lo = C - u + c;
23385 return this
23386 }
23387};
23388DD.prototype.dump = function dump () {
23389 return 'DD<' + this._hi + ', ' + this._lo + '>'
23390};
23391DD.prototype.divide = function divide () {
23392 if (arguments[0] instanceof DD) {
23393 var y = arguments[0];
23394 var hc = null;
23395 var tc = null;
23396 var hy = null;
23397 var ty = null;
23398 var C = null;
23399 var c = null;
23400 var U = null;
23401 var u = null;
23402 C = this._hi / y._hi;
23403 c = DD.SPLIT * C;
23404 hc = c - C;
23405 u = DD.SPLIT * y._hi;
23406 hc = c - hc;
23407 tc = C - hc;
23408 hy = u - y._hi;
23409 U = C * y._hi;
23410 hy = u - hy;
23411 ty = y._hi - hy;
23412 u = hc * hy - U + hc * ty + tc * hy + tc * ty;
23413 c = (this._hi - U - u + this._lo - C * y._lo) / y._hi;
23414 u = C + c;
23415 var zhi = u;
23416 var zlo = C - u + c;
23417 return new DD(zhi, zlo)
23418 } else if (typeof arguments[0] === 'number') {
23419 var y$1 = arguments[0];
23420 if (Double.isNaN(y$1)) { return DD.createNaN() }
23421 return DD.copy(this).selfDivide(y$1, 0.0)
23422 }
23423};
23424DD.prototype.ge = function ge (y) {
23425 return (this._hi > y._hi || this._hi === y._hi) && this._lo >= y._lo
23426};
23427DD.prototype.pow = function pow (exp) {
23428 if (exp === 0.0) { return DD.valueOf(1.0) }
23429 var r = new DD(this);
23430 var s = DD.valueOf(1.0);
23431 var n = Math.abs(exp);
23432 if (n > 1) {
23433 while (n > 0) {
23434 if (n % 2 === 1) {
23435 s.selfMultiply(r);
23436 }
23437 n /= 2;
23438 if (n > 0) { r = r.sqr(); }
23439 }
23440 } else {
23441 s = r;
23442 }
23443 if (exp < 0) { return s.reciprocal() }
23444 return s
23445};
23446DD.prototype.ceil = function ceil () {
23447 if (this.isNaN()) { return DD.NaN }
23448 var fhi = Math.ceil(this._hi);
23449 var flo = 0.0;
23450 if (fhi === this._hi) {
23451 flo = Math.ceil(this._lo);
23452 }
23453 return new DD(fhi, flo)
23454};
23455DD.prototype.compareTo = function compareTo (o) {
23456 var other = o;
23457 if (this._hi < other._hi) { return -1 }
23458 if (this._hi > other._hi) { return 1 }
23459 if (this._lo < other._lo) { return -1 }
23460 if (this._lo > other._lo) { return 1 }
23461 return 0
23462};
23463DD.prototype.rint = function rint () {
23464 if (this.isNaN()) { return this }
23465 var plus5 = this.add(0.5);
23466 return plus5.floor()
23467};
23468DD.prototype.setValue = function setValue () {
23469 if (arguments[0] instanceof DD) {
23470 var value = arguments[0];
23471 this.init(value);
23472 return this
23473 } else if (typeof arguments[0] === 'number') {
23474 var value$1 = arguments[0];
23475 this.init(value$1);
23476 return this
23477 }
23478};
23479DD.prototype.max = function max (x) {
23480 if (this.ge(x)) {
23481 return this
23482 } else {
23483 return x
23484 }
23485};
23486DD.prototype.sqrt = function sqrt () {
23487 if (this.isZero()) { return DD.valueOf(0.0) }
23488 if (this.isNegative()) {
23489 return DD.NaN
23490 }
23491 var x = 1.0 / Math.sqrt(this._hi);
23492 var ax = this._hi * x;
23493 var axdd = DD.valueOf(ax);
23494 var diffSq = this.subtract(axdd.sqr());
23495 var d2 = diffSq._hi * (x * 0.5);
23496 return axdd.add(d2)
23497};
23498DD.prototype.selfAdd = function selfAdd () {
23499 if (arguments.length === 1) {
23500 if (arguments[0] instanceof DD) {
23501 var y = arguments[0];
23502 return this.selfAdd(y._hi, y._lo)
23503 } else if (typeof arguments[0] === 'number') {
23504 var y$1 = arguments[0];
23505 var H = null;
23506 var h = null;
23507 var S = null;
23508 var s = null;
23509 var e = null;
23510 var f = null;
23511 S = this._hi + y$1;
23512 e = S - this._hi;
23513 s = S - e;
23514 s = y$1 - e + (this._hi - s);
23515 f = s + this._lo;
23516 H = S + f;
23517 h = f + (S - H);
23518 this._hi = H + h;
23519 this._lo = h + (H - this._hi);
23520 return this
23521 }
23522 } else if (arguments.length === 2) {
23523 var yhi = arguments[0];
23524 var ylo = arguments[1];
23525 var H$1 = null;
23526 var h$1 = null;
23527 var T = null;
23528 var t = null;
23529 var S$1 = null;
23530 var s$1 = null;
23531 var e$1 = null;
23532 var f$1 = null;
23533 S$1 = this._hi + yhi;
23534 T = this._lo + ylo;
23535 e$1 = S$1 - this._hi;
23536 f$1 = T - this._lo;
23537 s$1 = S$1 - e$1;
23538 t = T - f$1;
23539 s$1 = yhi - e$1 + (this._hi - s$1);
23540 t = ylo - f$1 + (this._lo - t);
23541 e$1 = s$1 + T;
23542 H$1 = S$1 + e$1;
23543 h$1 = e$1 + (S$1 - H$1);
23544 e$1 = t + h$1;
23545 var zhi = H$1 + e$1;
23546 var zlo = e$1 + (H$1 - zhi);
23547 this._hi = zhi;
23548 this._lo = zlo;
23549 return this
23550 }
23551};
23552DD.prototype.selfMultiply = function selfMultiply () {
23553 if (arguments.length === 1) {
23554 if (arguments[0] instanceof DD) {
23555 var y = arguments[0];
23556 return this.selfMultiply(y._hi, y._lo)
23557 } else if (typeof arguments[0] === 'number') {
23558 var y$1 = arguments[0];
23559 return this.selfMultiply(y$1, 0.0)
23560 }
23561 } else if (arguments.length === 2) {
23562 var yhi = arguments[0];
23563 var ylo = arguments[1];
23564 var hx = null;
23565 var tx = null;
23566 var hy = null;
23567 var ty = null;
23568 var C = null;
23569 var c = null;
23570 C = DD.SPLIT * this._hi;
23571 hx = C - this._hi;
23572 c = DD.SPLIT * yhi;
23573 hx = C - hx;
23574 tx = this._hi - hx;
23575 hy = c - yhi;
23576 C = this._hi * yhi;
23577 hy = c - hy;
23578 ty = yhi - hy;
23579 c = hx * hy - C + hx * ty + tx * hy + tx * ty + (this._hi * ylo + this._lo * yhi);
23580 var zhi = C + c;
23581 hx = C - zhi;
23582 var zlo = c + hx;
23583 this._hi = zhi;
23584 this._lo = zlo;
23585 return this
23586 }
23587};
23588DD.prototype.selfSqr = function selfSqr () {
23589 return this.selfMultiply(this)
23590};
23591DD.prototype.floor = function floor () {
23592 if (this.isNaN()) { return DD.NaN }
23593 var fhi = Math.floor(this._hi);
23594 var flo = 0.0;
23595 if (fhi === this._hi) {
23596 flo = Math.floor(this._lo);
23597 }
23598 return new DD(fhi, flo)
23599};
23600DD.prototype.negate = function negate () {
23601 if (this.isNaN()) { return this }
23602 return new DD(-this._hi, -this._lo)
23603};
23604DD.prototype.clone = function clone () {
23605 // try {
23606 // return null
23607 // } catch (ex) {
23608 // if (ex instanceof CloneNotSupportedException) {
23609 // return null
23610 // } else throw ex
23611 // } finally {}
23612};
23613DD.prototype.multiply = function multiply () {
23614 if (arguments[0] instanceof DD) {
23615 var y = arguments[0];
23616 if (y.isNaN()) { return DD.createNaN() }
23617 return DD.copy(this).selfMultiply(y)
23618 } else if (typeof arguments[0] === 'number') {
23619 var y$1 = arguments[0];
23620 if (Double.isNaN(y$1)) { return DD.createNaN() }
23621 return DD.copy(this).selfMultiply(y$1, 0.0)
23622 }
23623};
23624DD.prototype.isNaN = function isNaN () {
23625 return Double.isNaN(this._hi)
23626};
23627DD.prototype.intValue = function intValue () {
23628 return Math.trunc(this._hi)
23629};
23630DD.prototype.toString = function toString () {
23631 var mag = DD.magnitude(this._hi);
23632 if (mag >= -3 && mag <= 20) { return this.toStandardNotation() }
23633 return this.toSciNotation()
23634};
23635DD.prototype.toStandardNotation = function toStandardNotation () {
23636 var specialStr = this.getSpecialNumberString();
23637 if (specialStr !== null) { return specialStr }
23638 var magnitude = new Array(1).fill(null);
23639 var sigDigits = this.extractSignificantDigits(true, magnitude);
23640 var decimalPointPos = magnitude[0] + 1;
23641 var num = sigDigits;
23642 if (sigDigits.charAt(0) === '.') {
23643 num = '0' + sigDigits;
23644 } else if (decimalPointPos < 0) {
23645 num = '0.' + DD.stringOfChar('0', -decimalPointPos) + sigDigits;
23646 } else if (sigDigits.indexOf('.') === -1) {
23647 var numZeroes = decimalPointPos - sigDigits.length;
23648 var zeroes = DD.stringOfChar('0', numZeroes);
23649 num = sigDigits + zeroes + '.0';
23650 }
23651 if (this.isNegative()) { return '-' + num }
23652 return num
23653};
23654DD.prototype.reciprocal = function reciprocal () {
23655 var hc = null;
23656 var tc = null;
23657 var hy = null;
23658 var ty = null;
23659 var C = null;
23660 var c = null;
23661 var U = null;
23662 var u = null;
23663 C = 1.0 / this._hi;
23664 c = DD.SPLIT * C;
23665 hc = c - C;
23666 u = DD.SPLIT * this._hi;
23667 hc = c - hc;
23668 tc = C - hc;
23669 hy = u - this._hi;
23670 U = C * this._hi;
23671 hy = u - hy;
23672 ty = this._hi - hy;
23673 u = hc * hy - U + hc * ty + tc * hy + tc * ty;
23674 c = (1.0 - U - u - C * this._lo) / this._hi;
23675 var zhi = C + c;
23676 var zlo = C - zhi + c;
23677 return new DD(zhi, zlo)
23678};
23679DD.prototype.toSciNotation = function toSciNotation () {
23680 if (this.isZero()) { return DD.SCI_NOT_ZERO }
23681 var specialStr = this.getSpecialNumberString();
23682 if (specialStr !== null) { return specialStr }
23683 var magnitude = new Array(1).fill(null);
23684 var digits = this.extractSignificantDigits(false, magnitude);
23685 var expStr = DD.SCI_NOT_EXPONENT_CHAR + magnitude[0];
23686 if (digits.charAt(0) === '0') {
23687 throw new Error('Found leading zero: ' + digits)
23688 }
23689 var trailingDigits = '';
23690 if (digits.length > 1) { trailingDigits = digits.substring(1); }
23691 var digitsWithDecimal = digits.charAt(0) + '.' + trailingDigits;
23692 if (this.isNegative()) { return '-' + digitsWithDecimal + expStr }
23693 return digitsWithDecimal + expStr
23694};
23695DD.prototype.abs = function abs () {
23696 if (this.isNaN()) { return DD.NaN }
23697 if (this.isNegative()) { return this.negate() }
23698 return new DD(this)
23699};
23700DD.prototype.isPositive = function isPositive () {
23701 return (this._hi > 0.0 || this._hi === 0.0) && this._lo > 0.0
23702};
23703DD.prototype.lt = function lt (y) {
23704 return (this._hi < y._hi || this._hi === y._hi) && this._lo < y._lo
23705};
23706DD.prototype.add = function add () {
23707 if (arguments[0] instanceof DD) {
23708 var y = arguments[0];
23709 return DD.copy(this).selfAdd(y)
23710 } else if (typeof arguments[0] === 'number') {
23711 var y$1 = arguments[0];
23712 return DD.copy(this).selfAdd(y$1)
23713 }
23714};
23715DD.prototype.init = function init () {
23716 if (arguments.length === 1) {
23717 if (typeof arguments[0] === 'number') {
23718 var x = arguments[0];
23719 this._hi = x;
23720 this._lo = 0.0;
23721 } else if (arguments[0] instanceof DD) {
23722 var dd = arguments[0];
23723 this._hi = dd._hi;
23724 this._lo = dd._lo;
23725 }
23726 } else if (arguments.length === 2) {
23727 var hi = arguments[0];
23728 var lo = arguments[1];
23729 this._hi = hi;
23730 this._lo = lo;
23731 }
23732};
23733DD.prototype.gt = function gt (y) {
23734 return (this._hi > y._hi || this._hi === y._hi) && this._lo > y._lo
23735};
23736DD.prototype.isNegative = function isNegative () {
23737 return (this._hi < 0.0 || this._hi === 0.0) && this._lo < 0.0
23738};
23739DD.prototype.trunc = function trunc () {
23740 if (this.isNaN()) { return DD.NaN }
23741 if (this.isPositive()) { return this.floor(); } else { return this.ceil() }
23742};
23743DD.prototype.signum = function signum () {
23744 if (this._hi > 0) { return 1 }
23745 if (this._hi < 0) { return -1 }
23746 if (this._lo > 0) { return 1 }
23747 if (this._lo < 0) { return -1 }
23748 return 0
23749};
23750DD.prototype.interfaces_ = function interfaces_ () {
23751 return [Serializable, Comparable, Clonable]
23752};
23753DD.prototype.getClass = function getClass () {
23754 return DD
23755};
23756DD.sqr = function sqr (x) {
23757 return DD.valueOf(x).selfMultiply(x)
23758};
23759DD.valueOf = function valueOf () {
23760 if (typeof arguments[0] === 'string') {
23761 var str = arguments[0];
23762 return DD.parse(str)
23763 } else if (typeof arguments[0] === 'number') {
23764 var x = arguments[0];
23765 return new DD(x)
23766 }
23767};
23768DD.sqrt = function sqrt (x) {
23769 return DD.valueOf(x).sqrt()
23770};
23771DD.parse = function parse (str) {
23772 var i = 0;
23773 var strlen = str.length;
23774 while (Character.isWhitespace(str.charAt(i))) { i++; }
23775 var isNegative = false;
23776 if (i < strlen) {
23777 var signCh = str.charAt(i);
23778 if (signCh === '-' || signCh === '+') {
23779 i++;
23780 if (signCh === '-') { isNegative = true; }
23781 }
23782 }
23783 var val = new DD();
23784 var numDigits = 0;
23785 var numBeforeDec = 0;
23786 var exp = 0;
23787 while (true) {
23788 if (i >= strlen) { break }
23789 var ch = str.charAt(i);
23790 i++;
23791 if (Character.isDigit(ch)) {
23792 var d = ch - '0';
23793 val.selfMultiply(DD.TEN);
23794 val.selfAdd(d);
23795 numDigits++;
23796 continue
23797 }
23798 if (ch === '.') {
23799 numBeforeDec = numDigits;
23800 continue
23801 }
23802 if (ch === 'e' || ch === 'E') {
23803 var expStr = str.substring(i);
23804 try {
23805 exp = Integer.parseInt(expStr);
23806 } catch (ex) {
23807 if (ex instanceof Error) {
23808 throw new Error('Invalid exponent ' + expStr + ' in string ' + str)
23809 } else { throw ex }
23810 } finally {}
23811 break
23812 }
23813 throw new Error("Unexpected character '" + ch + "' at position " + i + ' in string ' + str)
23814 }
23815 var val2 = val;
23816 var numDecPlaces = numDigits - numBeforeDec - exp;
23817 if (numDecPlaces === 0) {
23818 val2 = val;
23819 } else if (numDecPlaces > 0) {
23820 var scale = DD.TEN.pow(numDecPlaces);
23821 val2 = val.divide(scale);
23822 } else if (numDecPlaces < 0) {
23823 var scale$1 = DD.TEN.pow(-numDecPlaces);
23824 val2 = val.multiply(scale$1);
23825 }
23826 if (isNegative) {
23827 return val2.negate()
23828 }
23829 return val2
23830};
23831DD.createNaN = function createNaN () {
23832 return new DD(Double.NaN, Double.NaN)
23833};
23834DD.copy = function copy (dd) {
23835 return new DD(dd)
23836};
23837DD.magnitude = function magnitude (x) {
23838 var xAbs = Math.abs(x);
23839 var xLog10 = Math.log(xAbs) / Math.log(10);
23840 var xMag = Math.trunc(Math.floor(xLog10));
23841 var xApprox = Math.pow(10, xMag);
23842 if (xApprox * 10 <= xAbs) { xMag += 1; }
23843 return xMag
23844};
23845DD.stringOfChar = function stringOfChar (ch, len) {
23846 var buf = new StringBuffer();
23847 for (var i = 0; i < len; i++) {
23848 buf.append(ch);
23849 }
23850 return buf.toString()
23851};
23852staticAccessors$7.PI.get = function () { return new DD(3.141592653589793116e+00, 1.224646799147353207e-16) };
23853staticAccessors$7.TWO_PI.get = function () { return new DD(6.283185307179586232e+00, 2.449293598294706414e-16) };
23854staticAccessors$7.PI_2.get = function () { return new DD(1.570796326794896558e+00, 6.123233995736766036e-17) };
23855staticAccessors$7.E.get = function () { return new DD(2.718281828459045091e+00, 1.445646891729250158e-16) };
23856staticAccessors$7.NaN.get = function () { return new DD(Double.NaN, Double.NaN) };
23857staticAccessors$7.EPS.get = function () { return 1.23259516440783e-32 };
23858staticAccessors$7.SPLIT.get = function () { return 134217729.0 };
23859staticAccessors$7.MAX_PRINT_DIGITS.get = function () { return 32 };
23860staticAccessors$7.TEN.get = function () { return DD.valueOf(10.0) };
23861staticAccessors$7.ONE.get = function () { return DD.valueOf(1.0) };
23862staticAccessors$7.SCI_NOT_EXPONENT_CHAR.get = function () { return 'E' };
23863staticAccessors$7.SCI_NOT_ZERO.get = function () { return '0.0E0' };
23864
23865Object.defineProperties( DD, staticAccessors$7 );
23866
23867var CGAlgorithmsDD = function CGAlgorithmsDD () {};
23868
23869var staticAccessors$6 = { DP_SAFE_EPSILON: { configurable: true } };
23870
23871CGAlgorithmsDD.prototype.interfaces_ = function interfaces_ () {
23872 return []
23873};
23874CGAlgorithmsDD.prototype.getClass = function getClass () {
23875 return CGAlgorithmsDD
23876};
23877CGAlgorithmsDD.orientationIndex = function orientationIndex (p1, p2, q) {
23878 var index = CGAlgorithmsDD.orientationIndexFilter(p1, p2, q);
23879 if (index <= 1) { return index }
23880 var dx1 = DD.valueOf(p2.x).selfAdd(-p1.x);
23881 var dy1 = DD.valueOf(p2.y).selfAdd(-p1.y);
23882 var dx2 = DD.valueOf(q.x).selfAdd(-p2.x);
23883 var dy2 = DD.valueOf(q.y).selfAdd(-p2.y);
23884 return dx1.selfMultiply(dy2).selfSubtract(dy1.selfMultiply(dx2)).signum()
23885};
23886CGAlgorithmsDD.signOfDet2x2 = function signOfDet2x2 (x1, y1, x2, y2) {
23887 var det = x1.multiply(y2).selfSubtract(y1.multiply(x2));
23888 return det.signum()
23889};
23890CGAlgorithmsDD.intersection = function intersection (p1, p2, q1, q2) {
23891 var denom1 = DD.valueOf(q2.y).selfSubtract(q1.y).selfMultiply(DD.valueOf(p2.x).selfSubtract(p1.x));
23892 var denom2 = DD.valueOf(q2.x).selfSubtract(q1.x).selfMultiply(DD.valueOf(p2.y).selfSubtract(p1.y));
23893 var denom = denom1.subtract(denom2);
23894 var numx1 = DD.valueOf(q2.x).selfSubtract(q1.x).selfMultiply(DD.valueOf(p1.y).selfSubtract(q1.y));
23895 var numx2 = DD.valueOf(q2.y).selfSubtract(q1.y).selfMultiply(DD.valueOf(p1.x).selfSubtract(q1.x));
23896 var numx = numx1.subtract(numx2);
23897 var fracP = numx.selfDivide(denom).doubleValue();
23898 var x = DD.valueOf(p1.x).selfAdd(DD.valueOf(p2.x).selfSubtract(p1.x).selfMultiply(fracP)).doubleValue();
23899 var numy1 = DD.valueOf(p2.x).selfSubtract(p1.x).selfMultiply(DD.valueOf(p1.y).selfSubtract(q1.y));
23900 var numy2 = DD.valueOf(p2.y).selfSubtract(p1.y).selfMultiply(DD.valueOf(p1.x).selfSubtract(q1.x));
23901 var numy = numy1.subtract(numy2);
23902 var fracQ = numy.selfDivide(denom).doubleValue();
23903 var y = DD.valueOf(q1.y).selfAdd(DD.valueOf(q2.y).selfSubtract(q1.y).selfMultiply(fracQ)).doubleValue();
23904 return new Coordinate(x, y)
23905};
23906CGAlgorithmsDD.orientationIndexFilter = function orientationIndexFilter (pa, pb, pc) {
23907 var detsum = null;
23908 var detleft = (pa.x - pc.x) * (pb.y - pc.y);
23909 var detright = (pa.y - pc.y) * (pb.x - pc.x);
23910 var det = detleft - detright;
23911 if (detleft > 0.0) {
23912 if (detright <= 0.0) {
23913 return CGAlgorithmsDD.signum(det)
23914 } else {
23915 detsum = detleft + detright;
23916 }
23917 } else if (detleft < 0.0) {
23918 if (detright >= 0.0) {
23919 return CGAlgorithmsDD.signum(det)
23920 } else {
23921 detsum = -detleft - detright;
23922 }
23923 } else {
23924 return CGAlgorithmsDD.signum(det)
23925 }
23926 var errbound = CGAlgorithmsDD.DP_SAFE_EPSILON * detsum;
23927 if (det >= errbound || -det >= errbound) {
23928 return CGAlgorithmsDD.signum(det)
23929 }
23930 return 2
23931};
23932CGAlgorithmsDD.signum = function signum (x) {
23933 if (x > 0) { return 1 }
23934 if (x < 0) { return -1 }
23935 return 0
23936};
23937staticAccessors$6.DP_SAFE_EPSILON.get = function () { return 1e-15 };
23938
23939Object.defineProperties( CGAlgorithmsDD, staticAccessors$6 );
23940
23941var CoordinateSequence = function CoordinateSequence () {};
23942
23943var staticAccessors$8 = { X: { configurable: true },Y: { configurable: true },Z: { configurable: true },M: { configurable: true } };
23944
23945staticAccessors$8.X.get = function () { return 0 };
23946staticAccessors$8.Y.get = function () { return 1 };
23947staticAccessors$8.Z.get = function () { return 2 };
23948staticAccessors$8.M.get = function () { return 3 };
23949CoordinateSequence.prototype.setOrdinate = function setOrdinate (index, ordinateIndex, value) {};
23950CoordinateSequence.prototype.size = function size () {};
23951CoordinateSequence.prototype.getOrdinate = function getOrdinate (index, ordinateIndex) {};
23952CoordinateSequence.prototype.getCoordinate = function getCoordinate () {};
23953CoordinateSequence.prototype.getCoordinateCopy = function getCoordinateCopy (i) {};
23954CoordinateSequence.prototype.getDimension = function getDimension () {};
23955CoordinateSequence.prototype.getX = function getX (index) {};
23956CoordinateSequence.prototype.clone = function clone () {};
23957CoordinateSequence.prototype.expandEnvelope = function expandEnvelope (env) {};
23958CoordinateSequence.prototype.copy = function copy () {};
23959CoordinateSequence.prototype.getY = function getY (index) {};
23960CoordinateSequence.prototype.toCoordinateArray = function toCoordinateArray () {};
23961CoordinateSequence.prototype.interfaces_ = function interfaces_ () {
23962 return [Clonable]
23963};
23964CoordinateSequence.prototype.getClass = function getClass () {
23965 return CoordinateSequence
23966};
23967
23968Object.defineProperties( CoordinateSequence, staticAccessors$8 );
23969
23970var Exception = function Exception () {};
23971
23972var NotRepresentableException = (function (Exception$$1) {
23973 function NotRepresentableException () {
23974 Exception$$1.call(this, 'Projective point not representable on the Cartesian plane.');
23975 }
23976
23977 if ( Exception$$1 ) NotRepresentableException.__proto__ = Exception$$1;
23978 NotRepresentableException.prototype = Object.create( Exception$$1 && Exception$$1.prototype );
23979 NotRepresentableException.prototype.constructor = NotRepresentableException;
23980 NotRepresentableException.prototype.interfaces_ = function interfaces_ () {
23981 return []
23982 };
23983 NotRepresentableException.prototype.getClass = function getClass () {
23984 return NotRepresentableException
23985 };
23986
23987 return NotRepresentableException;
23988}(Exception));
23989
23990var System = function System () {};
23991
23992System.arraycopy = function arraycopy (src, srcPos, dest, destPos, len) {
23993 var c = 0;
23994 for (var i = srcPos; i < srcPos + len; i++) {
23995 dest[destPos + c] = src[i];
23996 c++;
23997 }
23998};
23999
24000System.getProperty = function getProperty (name) {
24001 return {
24002 'line.separator': '\n'
24003 }[name]
24004};
24005
24006var HCoordinate = function HCoordinate () {
24007 this.x = null;
24008 this.y = null;
24009 this.w = null;
24010 if (arguments.length === 0) {
24011 this.x = 0.0;
24012 this.y = 0.0;
24013 this.w = 1.0;
24014 } else if (arguments.length === 1) {
24015 var p = arguments[0];
24016 this.x = p.x;
24017 this.y = p.y;
24018 this.w = 1.0;
24019 } else if (arguments.length === 2) {
24020 if (typeof arguments[0] === 'number' && typeof arguments[1] === 'number') {
24021 var _x = arguments[0];
24022 var _y = arguments[1];
24023 this.x = _x;
24024 this.y = _y;
24025 this.w = 1.0;
24026 } else if (arguments[0] instanceof HCoordinate && arguments[1] instanceof HCoordinate) {
24027 var p1 = arguments[0];
24028 var p2 = arguments[1];
24029 this.x = p1.y * p2.w - p2.y * p1.w;
24030 this.y = p2.x * p1.w - p1.x * p2.w;
24031 this.w = p1.x * p2.y - p2.x * p1.y;
24032 } else if (arguments[0] instanceof Coordinate && arguments[1] instanceof Coordinate) {
24033 var p1$1 = arguments[0];
24034 var p2$1 = arguments[1];
24035 this.x = p1$1.y - p2$1.y;
24036 this.y = p2$1.x - p1$1.x;
24037 this.w = p1$1.x * p2$1.y - p2$1.x * p1$1.y;
24038 }
24039 } else if (arguments.length === 3) {
24040 var _x$1 = arguments[0];
24041 var _y$1 = arguments[1];
24042 var _w = arguments[2];
24043 this.x = _x$1;
24044 this.y = _y$1;
24045 this.w = _w;
24046 } else if (arguments.length === 4) {
24047 var p1$2 = arguments[0];
24048 var p2$2 = arguments[1];
24049 var q1 = arguments[2];
24050 var q2 = arguments[3];
24051 var px = p1$2.y - p2$2.y;
24052 var py = p2$2.x - p1$2.x;
24053 var pw = p1$2.x * p2$2.y - p2$2.x * p1$2.y;
24054 var qx = q1.y - q2.y;
24055 var qy = q2.x - q1.x;
24056 var qw = q1.x * q2.y - q2.x * q1.y;
24057 this.x = py * qw - qy * pw;
24058 this.y = qx * pw - px * qw;
24059 this.w = px * qy - qx * py;
24060 }
24061};
24062HCoordinate.prototype.getY = function getY () {
24063 var a = this.y / this.w;
24064 if (Double.isNaN(a) || Double.isInfinite(a)) {
24065 throw new NotRepresentableException()
24066 }
24067 return a
24068};
24069HCoordinate.prototype.getX = function getX () {
24070 var a = this.x / this.w;
24071 if (Double.isNaN(a) || Double.isInfinite(a)) {
24072 throw new NotRepresentableException()
24073 }
24074 return a
24075};
24076HCoordinate.prototype.getCoordinate = function getCoordinate () {
24077 var p = new Coordinate();
24078 p.x = this.getX();
24079 p.y = this.getY();
24080 return p
24081};
24082HCoordinate.prototype.interfaces_ = function interfaces_ () {
24083 return []
24084};
24085HCoordinate.prototype.getClass = function getClass () {
24086 return HCoordinate
24087};
24088HCoordinate.intersection = function intersection (p1, p2, q1, q2) {
24089 var px = p1.y - p2.y;
24090 var py = p2.x - p1.x;
24091 var pw = p1.x * p2.y - p2.x * p1.y;
24092 var qx = q1.y - q2.y;
24093 var qy = q2.x - q1.x;
24094 var qw = q1.x * q2.y - q2.x * q1.y;
24095 var x = py * qw - qy * pw;
24096 var y = qx * pw - px * qw;
24097 var w = px * qy - qx * py;
24098 var xInt = x / w;
24099 var yInt = y / w;
24100 if (Double.isNaN(xInt) || (Double.isInfinite(xInt) || Double.isNaN(yInt)) || Double.isInfinite(yInt)) {
24101 throw new NotRepresentableException()
24102 }
24103 return new Coordinate(xInt, yInt)
24104};
24105
24106var Envelope = function Envelope () {
24107 this._minx = null;
24108 this._maxx = null;
24109 this._miny = null;
24110 this._maxy = null;
24111 if (arguments.length === 0) {
24112 this.init();
24113 } else if (arguments.length === 1) {
24114 if (arguments[0] instanceof Coordinate) {
24115 var p = arguments[0];
24116 this.init(p.x, p.x, p.y, p.y);
24117 } else if (arguments[0] instanceof Envelope) {
24118 var env = arguments[0];
24119 this.init(env);
24120 }
24121 } else if (arguments.length === 2) {
24122 var p1 = arguments[0];
24123 var p2 = arguments[1];
24124 this.init(p1.x, p2.x, p1.y, p2.y);
24125 } else if (arguments.length === 4) {
24126 var x1 = arguments[0];
24127 var x2 = arguments[1];
24128 var y1 = arguments[2];
24129 var y2 = arguments[3];
24130 this.init(x1, x2, y1, y2);
24131 }
24132};
24133
24134var staticAccessors$9 = { serialVersionUID: { configurable: true } };
24135Envelope.prototype.getArea = function getArea () {
24136 return this.getWidth() * this.getHeight()
24137};
24138Envelope.prototype.equals = function equals (other) {
24139 if (!(other instanceof Envelope)) {
24140 return false
24141 }
24142 var otherEnvelope = other;
24143 if (this.isNull()) {
24144 return otherEnvelope.isNull()
24145 }
24146 return this._maxx === otherEnvelope.getMaxX() && this._maxy === otherEnvelope.getMaxY() && this._minx === otherEnvelope.getMinX() && this._miny === otherEnvelope.getMinY()
24147};
24148Envelope.prototype.intersection = function intersection (env) {
24149 if (this.isNull() || env.isNull() || !this.intersects(env)) { return new Envelope() }
24150 var intMinX = this._minx > env._minx ? this._minx : env._minx;
24151 var intMinY = this._miny > env._miny ? this._miny : env._miny;
24152 var intMaxX = this._maxx < env._maxx ? this._maxx : env._maxx;
24153 var intMaxY = this._maxy < env._maxy ? this._maxy : env._maxy;
24154 return new Envelope(intMinX, intMaxX, intMinY, intMaxY)
24155};
24156Envelope.prototype.isNull = function isNull () {
24157 return this._maxx < this._minx
24158};
24159Envelope.prototype.getMaxX = function getMaxX () {
24160 return this._maxx
24161};
24162Envelope.prototype.covers = function covers () {
24163 if (arguments.length === 1) {
24164 if (arguments[0] instanceof Coordinate) {
24165 var p = arguments[0];
24166 return this.covers(p.x, p.y)
24167 } else if (arguments[0] instanceof Envelope) {
24168 var other = arguments[0];
24169 if (this.isNull() || other.isNull()) {
24170 return false
24171 }
24172 return other.getMinX() >= this._minx && other.getMaxX() <= this._maxx && other.getMinY() >= this._miny && other.getMaxY() <= this._maxy
24173 }
24174 } else if (arguments.length === 2) {
24175 var x = arguments[0];
24176 var y = arguments[1];
24177 if (this.isNull()) { return false }
24178 return x >= this._minx && x <= this._maxx && y >= this._miny && y <= this._maxy
24179 }
24180};
24181Envelope.prototype.intersects = function intersects () {
24182 if (arguments.length === 1) {
24183 if (arguments[0] instanceof Envelope) {
24184 var other = arguments[0];
24185 if (this.isNull() || other.isNull()) {
24186 return false
24187 }
24188 return !(other._minx > this._maxx || other._maxx < this._minx || other._miny > this._maxy || other._maxy < this._miny)
24189 } else if (arguments[0] instanceof Coordinate) {
24190 var p = arguments[0];
24191 return this.intersects(p.x, p.y)
24192 }
24193 } else if (arguments.length === 2) {
24194 var x = arguments[0];
24195 var y = arguments[1];
24196 if (this.isNull()) { return false }
24197 return !(x > this._maxx || x < this._minx || y > this._maxy || y < this._miny)
24198 }
24199};
24200Envelope.prototype.getMinY = function getMinY () {
24201 return this._miny
24202};
24203Envelope.prototype.getMinX = function getMinX () {
24204 return this._minx
24205};
24206Envelope.prototype.expandToInclude = function expandToInclude () {
24207 if (arguments.length === 1) {
24208 if (arguments[0] instanceof Coordinate) {
24209 var p = arguments[0];
24210 this.expandToInclude(p.x, p.y);
24211 } else if (arguments[0] instanceof Envelope) {
24212 var other = arguments[0];
24213 if (other.isNull()) {
24214 return null
24215 }
24216 if (this.isNull()) {
24217 this._minx = other.getMinX();
24218 this._maxx = other.getMaxX();
24219 this._miny = other.getMinY();
24220 this._maxy = other.getMaxY();
24221 } else {
24222 if (other._minx < this._minx) {
24223 this._minx = other._minx;
24224 }
24225 if (other._maxx > this._maxx) {
24226 this._maxx = other._maxx;
24227 }
24228 if (other._miny < this._miny) {
24229 this._miny = other._miny;
24230 }
24231 if (other._maxy > this._maxy) {
24232 this._maxy = other._maxy;
24233 }
24234 }
24235 }
24236 } else if (arguments.length === 2) {
24237 var x = arguments[0];
24238 var y = arguments[1];
24239 if (this.isNull()) {
24240 this._minx = x;
24241 this._maxx = x;
24242 this._miny = y;
24243 this._maxy = y;
24244 } else {
24245 if (x < this._minx) {
24246 this._minx = x;
24247 }
24248 if (x > this._maxx) {
24249 this._maxx = x;
24250 }
24251 if (y < this._miny) {
24252 this._miny = y;
24253 }
24254 if (y > this._maxy) {
24255 this._maxy = y;
24256 }
24257 }
24258 }
24259};
24260Envelope.prototype.minExtent = function minExtent () {
24261 if (this.isNull()) { return 0.0 }
24262 var w = this.getWidth();
24263 var h = this.getHeight();
24264 if (w < h) { return w }
24265 return h
24266};
24267Envelope.prototype.getWidth = function getWidth () {
24268 if (this.isNull()) {
24269 return 0
24270 }
24271 return this._maxx - this._minx
24272};
24273Envelope.prototype.compareTo = function compareTo (o) {
24274 var env = o;
24275 if (this.isNull()) {
24276 if (env.isNull()) { return 0 }
24277 return -1
24278 } else {
24279 if (env.isNull()) { return 1 }
24280 }
24281 if (this._minx < env._minx) { return -1 }
24282 if (this._minx > env._minx) { return 1 }
24283 if (this._miny < env._miny) { return -1 }
24284 if (this._miny > env._miny) { return 1 }
24285 if (this._maxx < env._maxx) { return -1 }
24286 if (this._maxx > env._maxx) { return 1 }
24287 if (this._maxy < env._maxy) { return -1 }
24288 if (this._maxy > env._maxy) { return 1 }
24289 return 0
24290};
24291Envelope.prototype.translate = function translate (transX, transY) {
24292 if (this.isNull()) {
24293 return null
24294 }
24295 this.init(this.getMinX() + transX, this.getMaxX() + transX, this.getMinY() + transY, this.getMaxY() + transY);
24296};
24297Envelope.prototype.toString = function toString () {
24298 return 'Env[' + this._minx + ' : ' + this._maxx + ', ' + this._miny + ' : ' + this._maxy + ']'
24299};
24300Envelope.prototype.setToNull = function setToNull () {
24301 this._minx = 0;
24302 this._maxx = -1;
24303 this._miny = 0;
24304 this._maxy = -1;
24305};
24306Envelope.prototype.getHeight = function getHeight () {
24307 if (this.isNull()) {
24308 return 0
24309 }
24310 return this._maxy - this._miny
24311};
24312Envelope.prototype.maxExtent = function maxExtent () {
24313 if (this.isNull()) { return 0.0 }
24314 var w = this.getWidth();
24315 var h = this.getHeight();
24316 if (w > h) { return w }
24317 return h
24318};
24319Envelope.prototype.expandBy = function expandBy () {
24320 if (arguments.length === 1) {
24321 var distance = arguments[0];
24322 this.expandBy(distance, distance);
24323 } else if (arguments.length === 2) {
24324 var deltaX = arguments[0];
24325 var deltaY = arguments[1];
24326 if (this.isNull()) { return null }
24327 this._minx -= deltaX;
24328 this._maxx += deltaX;
24329 this._miny -= deltaY;
24330 this._maxy += deltaY;
24331 if (this._minx > this._maxx || this._miny > this._maxy) { this.setToNull(); }
24332 }
24333};
24334Envelope.prototype.contains = function contains () {
24335 if (arguments.length === 1) {
24336 if (arguments[0] instanceof Envelope) {
24337 var other = arguments[0];
24338 return this.covers(other)
24339 } else if (arguments[0] instanceof Coordinate) {
24340 var p = arguments[0];
24341 return this.covers(p)
24342 }
24343 } else if (arguments.length === 2) {
24344 var x = arguments[0];
24345 var y = arguments[1];
24346 return this.covers(x, y)
24347 }
24348};
24349Envelope.prototype.centre = function centre () {
24350 if (this.isNull()) { return null }
24351 return new Coordinate((this.getMinX() + this.getMaxX()) / 2.0, (this.getMinY() + this.getMaxY()) / 2.0)
24352};
24353Envelope.prototype.init = function init () {
24354 if (arguments.length === 0) {
24355 this.setToNull();
24356 } else if (arguments.length === 1) {
24357 if (arguments[0] instanceof Coordinate) {
24358 var p = arguments[0];
24359 this.init(p.x, p.x, p.y, p.y);
24360 } else if (arguments[0] instanceof Envelope) {
24361 var env = arguments[0];
24362 this._minx = env._minx;
24363 this._maxx = env._maxx;
24364 this._miny = env._miny;
24365 this._maxy = env._maxy;
24366 }
24367 } else if (arguments.length === 2) {
24368 var p1 = arguments[0];
24369 var p2 = arguments[1];
24370 this.init(p1.x, p2.x, p1.y, p2.y);
24371 } else if (arguments.length === 4) {
24372 var x1 = arguments[0];
24373 var x2 = arguments[1];
24374 var y1 = arguments[2];
24375 var y2 = arguments[3];
24376 if (x1 < x2) {
24377 this._minx = x1;
24378 this._maxx = x2;
24379 } else {
24380 this._minx = x2;
24381 this._maxx = x1;
24382 }
24383 if (y1 < y2) {
24384 this._miny = y1;
24385 this._maxy = y2;
24386 } else {
24387 this._miny = y2;
24388 this._maxy = y1;
24389 }
24390 }
24391};
24392Envelope.prototype.getMaxY = function getMaxY () {
24393 return this._maxy
24394};
24395Envelope.prototype.distance = function distance (env) {
24396 if (this.intersects(env)) { return 0 }
24397 var dx = 0.0;
24398 if (this._maxx < env._minx) { dx = env._minx - this._maxx; } else if (this._minx > env._maxx) { dx = this._minx - env._maxx; }
24399 var dy = 0.0;
24400 if (this._maxy < env._miny) { dy = env._miny - this._maxy; } else if (this._miny > env._maxy) { dy = this._miny - env._maxy; }
24401 if (dx === 0.0) { return dy }
24402 if (dy === 0.0) { return dx }
24403 return Math.sqrt(dx * dx + dy * dy)
24404};
24405Envelope.prototype.hashCode = function hashCode () {
24406 var result = 17;
24407 result = 37 * result + Coordinate.hashCode(this._minx);
24408 result = 37 * result + Coordinate.hashCode(this._maxx);
24409 result = 37 * result + Coordinate.hashCode(this._miny);
24410 result = 37 * result + Coordinate.hashCode(this._maxy);
24411 return result
24412};
24413Envelope.prototype.interfaces_ = function interfaces_ () {
24414 return [Comparable, Serializable]
24415};
24416Envelope.prototype.getClass = function getClass () {
24417 return Envelope
24418};
24419Envelope.intersects = function intersects () {
24420 if (arguments.length === 3) {
24421 var p1 = arguments[0];
24422 var p2 = arguments[1];
24423 var q = arguments[2];
24424 if (q.x >= (p1.x < p2.x ? p1.x : p2.x) && q.x <= (p1.x > p2.x ? p1.x : p2.x) && (q.y >= (p1.y < p2.y ? p1.y : p2.y) && q.y <= (p1.y > p2.y ? p1.y : p2.y))) {
24425 return true
24426 }
24427 return false
24428 } else if (arguments.length === 4) {
24429 var p1$1 = arguments[0];
24430 var p2$1 = arguments[1];
24431 var q1 = arguments[2];
24432 var q2 = arguments[3];
24433 var minq = Math.min(q1.x, q2.x);
24434 var maxq = Math.max(q1.x, q2.x);
24435 var minp = Math.min(p1$1.x, p2$1.x);
24436 var maxp = Math.max(p1$1.x, p2$1.x);
24437 if (minp > maxq) { return false }
24438 if (maxp < minq) { return false }
24439 minq = Math.min(q1.y, q2.y);
24440 maxq = Math.max(q1.y, q2.y);
24441 minp = Math.min(p1$1.y, p2$1.y);
24442 maxp = Math.max(p1$1.y, p2$1.y);
24443 if (minp > maxq) { return false }
24444 if (maxp < minq) { return false }
24445 return true
24446 }
24447};
24448staticAccessors$9.serialVersionUID.get = function () { return 5873921885273102420 };
24449
24450Object.defineProperties( Envelope, staticAccessors$9 );
24451
24452var regExes = {
24453 'typeStr': /^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/,
24454 'emptyTypeStr': /^\s*(\w+)\s*EMPTY\s*$/,
24455 'spaces': /\s+/,
24456 'parenComma': /\)\s*,\s*\(/,
24457 'doubleParenComma': /\)\s*\)\s*,\s*\(\s*\(/, // can't use {2} here
24458 'trimParens': /^\s*\(?(.*?)\)?\s*$/
24459};
24460
24461/**
24462 * Class for reading and writing Well-Known Text.
24463 *
24464 * NOTE: Adapted from OpenLayers 2.11 implementation.
24465 */
24466
24467/** Create a new parser for WKT
24468 *
24469 * @param {GeometryFactory} geometryFactory
24470 * @return An instance of WKTParser.
24471 * @constructor
24472 * @private
24473 */
24474var WKTParser = function WKTParser (geometryFactory) {
24475 this.geometryFactory = geometryFactory || new GeometryFactory();
24476};
24477/**
24478 * Deserialize a WKT string and return a geometry. Supports WKT for POINT,
24479 * MULTIPOINT, LINESTRING, LINEARRING, MULTILINESTRING, POLYGON, MULTIPOLYGON,
24480 * and GEOMETRYCOLLECTION.
24481 *
24482 * @param {String} wkt A WKT string.
24483 * @return {Geometry} A geometry instance.
24484 * @private
24485 */
24486WKTParser.prototype.read = function read (wkt) {
24487 var geometry, type, str;
24488 wkt = wkt.replace(/[\n\r]/g, ' ');
24489 var matches = regExes.typeStr.exec(wkt);
24490 if (wkt.search('EMPTY') !== -1) {
24491 matches = regExes.emptyTypeStr.exec(wkt);
24492 matches[2] = undefined;
24493 }
24494 if (matches) {
24495 type = matches[1].toLowerCase();
24496 str = matches[2];
24497 if (parse$1[type]) {
24498 geometry = parse$1[type].apply(this, [str]);
24499 }
24500 }
24501
24502 if (geometry === undefined) { throw new Error('Could not parse WKT ' + wkt) }
24503
24504 return geometry
24505};
24506
24507/**
24508 * Serialize a geometry into a WKT string.
24509 *
24510 * @param {Geometry} geometry A feature or array of features.
24511 * @return {String} The WKT string representation of the input geometries.
24512 * @private
24513 */
24514WKTParser.prototype.write = function write (geometry) {
24515 return this.extractGeometry(geometry)
24516};
24517
24518/**
24519 * Entry point to construct the WKT for a single Geometry object.
24520 *
24521 * @param {Geometry} geometry
24522 * @return {String} A WKT string of representing the geometry.
24523 * @private
24524 */
24525WKTParser.prototype.extractGeometry = function extractGeometry (geometry) {
24526 var type = geometry.getGeometryType().toLowerCase();
24527 if (!extract$1[type]) {
24528 return null
24529 }
24530 var wktType = type.toUpperCase();
24531 var data;
24532 if (geometry.isEmpty()) {
24533 data = wktType + ' EMPTY';
24534 } else {
24535 data = wktType + '(' + extract$1[type].apply(this, [geometry]) + ')';
24536 }
24537 return data
24538};
24539
24540/**
24541 * Object with properties corresponding to the geometry types. Property values
24542 * are functions that do the actual data extraction.
24543 * @private
24544 */
24545var extract$1 = {
24546 coordinate: function coordinate (coordinate$1) {
24547 return coordinate$1.x + ' ' + coordinate$1.y
24548 },
24549
24550 /**
24551 * Return a space delimited string of point coordinates.
24552 *
24553 * @param {Point}
24554 * point
24555 * @return {String} A string of coordinates representing the point.
24556 */
24557 point: function point (point$1) {
24558 return extract$1.coordinate.call(this, point$1._coordinates._coordinates[0])
24559 },
24560
24561 /**
24562 * Return a comma delimited string of point coordinates from a multipoint.
24563 *
24564 * @param {MultiPoint}
24565 * multipoint
24566 * @return {String} A string of point coordinate strings representing the
24567 * multipoint.
24568 */
24569 multipoint: function multipoint (multipoint$1) {
24570 var this$1 = this;
24571
24572 var array = [];
24573 for (var i = 0, len = multipoint$1._geometries.length; i < len; ++i) {
24574 array.push('(' + extract$1.point.apply(this$1, [multipoint$1._geometries[i]]) + ')');
24575 }
24576 return array.join(',')
24577 },
24578
24579 /**
24580 * Return a comma delimited string of point coordinates from a line.
24581 *
24582 * @param {LineString} linestring
24583 * @return {String} A string of point coordinate strings representing the linestring.
24584 */
24585 linestring: function linestring (linestring$1) {
24586 var this$1 = this;
24587
24588 var array = [];
24589 for (var i = 0, len = linestring$1._points._coordinates.length; i < len; ++i) {
24590 array.push(extract$1.coordinate.apply(this$1, [linestring$1._points._coordinates[i]]));
24591 }
24592 return array.join(',')
24593 },
24594
24595 linearring: function linearring (linearring$1) {
24596 var this$1 = this;
24597
24598 var array = [];
24599 for (var i = 0, len = linearring$1._points._coordinates.length; i < len; ++i) {
24600 array.push(extract$1.coordinate.apply(this$1, [linearring$1._points._coordinates[i]]));
24601 }
24602 return array.join(',')
24603 },
24604
24605 /**
24606 * Return a comma delimited string of linestring strings from a
24607 * multilinestring.
24608 *
24609 * @param {MultiLineString} multilinestring
24610 * @return {String} A string of of linestring strings representing the multilinestring.
24611 */
24612 multilinestring: function multilinestring (multilinestring$1) {
24613 var this$1 = this;
24614
24615 var array = [];
24616 for (var i = 0, len = multilinestring$1._geometries.length; i < len; ++i) {
24617 array.push('(' +
24618 extract$1.linestring.apply(this$1, [multilinestring$1._geometries[i]]) +
24619 ')');
24620 }
24621 return array.join(',')
24622 },
24623
24624 /**
24625 * Return a comma delimited string of linear ring arrays from a polygon.
24626 *
24627 * @param {Polygon} polygon
24628 * @return {String} An array of linear ring arrays representing the polygon.
24629 */
24630 polygon: function polygon (polygon$1) {
24631 var this$1 = this;
24632
24633 var array = [];
24634 array.push('(' + extract$1.linestring.apply(this, [polygon$1._shell]) + ')');
24635 for (var i = 0, len = polygon$1._holes.length; i < len; ++i) {
24636 array.push('(' + extract$1.linestring.apply(this$1, [polygon$1._holes[i]]) + ')');
24637 }
24638 return array.join(',')
24639 },
24640
24641 /**
24642 * Return an array of polygon arrays from a multipolygon.
24643 *
24644 * @param {MultiPolygon} multipolygon
24645 * @return {String} An array of polygon arrays representing the multipolygon.
24646 */
24647 multipolygon: function multipolygon (multipolygon$1) {
24648 var this$1 = this;
24649
24650 var array = [];
24651 for (var i = 0, len = multipolygon$1._geometries.length; i < len; ++i) {
24652 array.push('(' + extract$1.polygon.apply(this$1, [multipolygon$1._geometries[i]]) + ')');
24653 }
24654 return array.join(',')
24655 },
24656
24657 /**
24658 * Return the WKT portion between 'GEOMETRYCOLLECTION(' and ')' for an
24659 * geometrycollection.
24660 *
24661 * @param {GeometryCollection} collection
24662 * @return {String} internal WKT representation of the collection.
24663 */
24664 geometrycollection: function geometrycollection (collection) {
24665 var this$1 = this;
24666
24667 var array = [];
24668 for (var i = 0, len = collection._geometries.length; i < len; ++i) {
24669 array.push(this$1.extractGeometry(collection._geometries[i]));
24670 }
24671 return array.join(',')
24672 }
24673};
24674
24675/**
24676 * Object with properties corresponding to the geometry types. Property values
24677 * are functions that do the actual parsing.
24678 * @private
24679 */
24680var parse$1 = {
24681 /**
24682 * Return point geometry given a point WKT fragment.
24683 *
24684 * @param {String} str A WKT fragment representing the point.
24685 * @return {Point} A point geometry.
24686 * @private
24687 */
24688 point: function point (str) {
24689 if (str === undefined) {
24690 return this.geometryFactory.createPoint()
24691 }
24692
24693 var coords = str.trim().split(regExes.spaces);
24694 return this.geometryFactory.createPoint(new Coordinate(Number.parseFloat(coords[0]),
24695 Number.parseFloat(coords[1])))
24696 },
24697
24698 /**
24699 * Return a multipoint geometry given a multipoint WKT fragment.
24700 *
24701 * @param {String} str A WKT fragment representing the multipoint.
24702 * @return {Point} A multipoint feature.
24703 * @private
24704 */
24705 multipoint: function multipoint (str) {
24706 var this$1 = this;
24707
24708 if (str === undefined) {
24709 return this.geometryFactory.createMultiPoint()
24710 }
24711
24712 var point;
24713 var points = str.trim().split(',');
24714 var components = [];
24715 for (var i = 0, len = points.length; i < len; ++i) {
24716 point = points[i].replace(regExes.trimParens, '$1');
24717 components.push(parse$1.point.apply(this$1, [point]));
24718 }
24719 return this.geometryFactory.createMultiPoint(components)
24720 },
24721
24722 /**
24723 * Return a linestring geometry given a linestring WKT fragment.
24724 *
24725 * @param {String} str A WKT fragment representing the linestring.
24726 * @return {LineString} A linestring geometry.
24727 * @private
24728 */
24729 linestring: function linestring (str) {
24730 if (str === undefined) {
24731 return this.geometryFactory.createLineString()
24732 }
24733
24734 var points = str.trim().split(',');
24735 var components = [];
24736 var coords;
24737 for (var i = 0, len = points.length; i < len; ++i) {
24738 coords = points[i].trim().split(regExes.spaces);
24739 components.push(new Coordinate(Number.parseFloat(coords[0]), Number.parseFloat(coords[1])));
24740 }
24741 return this.geometryFactory.createLineString(components)
24742 },
24743
24744 /**
24745 * Return a linearring geometry given a linearring WKT fragment.
24746 *
24747 * @param {String} str A WKT fragment representing the linearring.
24748 * @return {LinearRing} A linearring geometry.
24749 * @private
24750 */
24751 linearring: function linearring (str) {
24752 if (str === undefined) {
24753 return this.geometryFactory.createLinearRing()
24754 }
24755
24756 var points = str.trim().split(',');
24757 var components = [];
24758 var coords;
24759 for (var i = 0, len = points.length; i < len; ++i) {
24760 coords = points[i].trim().split(regExes.spaces);
24761 components.push(new Coordinate(Number.parseFloat(coords[0]), Number.parseFloat(coords[1])));
24762 }
24763 return this.geometryFactory.createLinearRing(components)
24764 },
24765
24766 /**
24767 * Return a multilinestring geometry given a multilinestring WKT fragment.
24768 *
24769 * @param {String} str A WKT fragment representing the multilinestring.
24770 * @return {MultiLineString} A multilinestring geometry.
24771 * @private
24772 */
24773 multilinestring: function multilinestring (str) {
24774 var this$1 = this;
24775
24776 if (str === undefined) {
24777 return this.geometryFactory.createMultiLineString()
24778 }
24779
24780 var line;
24781 var lines = str.trim().split(regExes.parenComma);
24782 var components = [];
24783 for (var i = 0, len = lines.length; i < len; ++i) {
24784 line = lines[i].replace(regExes.trimParens, '$1');
24785 components.push(parse$1.linestring.apply(this$1, [line]));
24786 }
24787 return this.geometryFactory.createMultiLineString(components)
24788 },
24789
24790 /**
24791 * Return a polygon geometry given a polygon WKT fragment.
24792 *
24793 * @param {String} str A WKT fragment representing the polygon.
24794 * @return {Polygon} A polygon geometry.
24795 * @private
24796 */
24797 polygon: function polygon (str) {
24798 var this$1 = this;
24799
24800 if (str === undefined) {
24801 return this.geometryFactory.createPolygon()
24802 }
24803
24804 var ring, linestring, linearring;
24805 var rings = str.trim().split(regExes.parenComma);
24806 var shell;
24807 var holes = [];
24808 for (var i = 0, len = rings.length; i < len; ++i) {
24809 ring = rings[i].replace(regExes.trimParens, '$1');
24810 linestring = parse$1.linestring.apply(this$1, [ring]);
24811 linearring = this$1.geometryFactory.createLinearRing(linestring._points);
24812 if (i === 0) {
24813 shell = linearring;
24814 } else {
24815 holes.push(linearring);
24816 }
24817 }
24818 return this.geometryFactory.createPolygon(shell, holes)
24819 },
24820
24821 /**
24822 * Return a multipolygon geometry given a multipolygon WKT fragment.
24823 *
24824 * @param {String} str A WKT fragment representing the multipolygon.
24825 * @return {MultiPolygon} A multipolygon geometry.
24826 * @private
24827 */
24828 multipolygon: function multipolygon (str) {
24829 var this$1 = this;
24830
24831 if (str === undefined) {
24832 return this.geometryFactory.createMultiPolygon()
24833 }
24834
24835 var polygon;
24836 var polygons = str.trim().split(regExes.doubleParenComma);
24837 var components = [];
24838 for (var i = 0, len = polygons.length; i < len; ++i) {
24839 polygon = polygons[i].replace(regExes.trimParens, '$1');
24840 components.push(parse$1.polygon.apply(this$1, [polygon]));
24841 }
24842 return this.geometryFactory.createMultiPolygon(components)
24843 },
24844
24845 /**
24846 * Return a geometrycollection given a geometrycollection WKT fragment.
24847 *
24848 * @param {String} str A WKT fragment representing the geometrycollection.
24849 * @return {GeometryCollection}
24850 * @private
24851 */
24852 geometrycollection: function geometrycollection (str) {
24853 var this$1 = this;
24854
24855 if (str === undefined) {
24856 return this.geometryFactory.createGeometryCollection()
24857 }
24858
24859 // separate components of the collection with |
24860 str = str.replace(/,\s*([A-Za-z])/g, '|$1');
24861 var wktArray = str.trim().split('|');
24862 var components = [];
24863 for (var i = 0, len = wktArray.length; i < len; ++i) {
24864 components.push(this$1.read(wktArray[i]));
24865 }
24866 return this.geometryFactory.createGeometryCollection(components)
24867 }
24868};
24869
24870/**
24871 * Writes the Well-Known Text representation of a {@link Geometry}. The
24872 * Well-Known Text format is defined in the <A
24873 * HREF="http://www.opengis.org/techno/specs.htm"> OGC Simple Features
24874 * Specification for SQL</A>.
24875 * <p>
24876 * The <code>WKTWriter</code> outputs coordinates rounded to the precision
24877 * model. Only the maximum number of decimal places necessary to represent the
24878 * ordinates to the required precision will be output.
24879 * <p>
24880 * The SFS WKT spec does not define a special tag for {@link LinearRing}s.
24881 * Under the spec, rings are output as <code>LINESTRING</code>s.
24882 */
24883
24884/**
24885 * @param {GeometryFactory} geometryFactory
24886 * @constructor
24887 */
24888var WKTWriter = function WKTWriter (geometryFactory) {
24889 this.parser = new WKTParser(geometryFactory);
24890};
24891
24892/**
24893 * Converts a <code>Geometry</code> to its Well-known Text representation.
24894 *
24895 * @param {Geometry} geometry a <code>Geometry</code> to process.
24896 * @return {string} a <Geometry Tagged Text> string (see the OpenGIS Simple
24897 * Features Specification).
24898 * @memberof WKTWriter
24899 */
24900WKTWriter.prototype.write = function write (geometry) {
24901 return this.parser.write(geometry)
24902};
24903/**
24904 * Generates the WKT for a <tt>LINESTRING</tt> specified by two
24905 * {@link Coordinate}s.
24906 *
24907 * @param p0 the first coordinate.
24908 * @param p1 the second coordinate.
24909 *
24910 * @return the WKT.
24911 * @private
24912 */
24913WKTWriter.toLineString = function toLineString (p0, p1) {
24914 if (arguments.length !== 2) {
24915 throw new Error('Not implemented')
24916 }
24917 return 'LINESTRING ( ' + p0.x + ' ' + p0.y + ', ' + p1.x + ' ' + p1.y + ' )'
24918};
24919
24920var RuntimeException = (function (Error) {
24921 function RuntimeException (message) {
24922 Error.call(this, message);
24923 this.name = 'RuntimeException';
24924 this.message = message;
24925 this.stack = (new Error()).stack;
24926 }
24927
24928 if ( Error ) RuntimeException.__proto__ = Error;
24929 RuntimeException.prototype = Object.create( Error && Error.prototype );
24930 RuntimeException.prototype.constructor = RuntimeException;
24931
24932 return RuntimeException;
24933}(Error));
24934
24935var AssertionFailedException = (function (RuntimeException$$1) {
24936 function AssertionFailedException () {
24937 RuntimeException$$1.call(this);
24938 if (arguments.length === 0) {
24939 RuntimeException$$1.call(this);
24940 } else if (arguments.length === 1) {
24941 var message = arguments[0];
24942 RuntimeException$$1.call(this, message);
24943 }
24944 }
24945
24946 if ( RuntimeException$$1 ) AssertionFailedException.__proto__ = RuntimeException$$1;
24947 AssertionFailedException.prototype = Object.create( RuntimeException$$1 && RuntimeException$$1.prototype );
24948 AssertionFailedException.prototype.constructor = AssertionFailedException;
24949 AssertionFailedException.prototype.interfaces_ = function interfaces_ () {
24950 return []
24951 };
24952 AssertionFailedException.prototype.getClass = function getClass () {
24953 return AssertionFailedException
24954 };
24955
24956 return AssertionFailedException;
24957}(RuntimeException));
24958
24959var Assert = function Assert () {};
24960
24961Assert.prototype.interfaces_ = function interfaces_ () {
24962 return []
24963};
24964Assert.prototype.getClass = function getClass () {
24965 return Assert
24966};
24967Assert.shouldNeverReachHere = function shouldNeverReachHere () {
24968 if (arguments.length === 0) {
24969 Assert.shouldNeverReachHere(null);
24970 } else if (arguments.length === 1) {
24971 var message = arguments[0];
24972 throw new AssertionFailedException('Should never reach here' + (message !== null ? ': ' + message : ''))
24973 }
24974};
24975Assert.isTrue = function isTrue () {
24976 var assertion;
24977 var message;
24978 if (arguments.length === 1) {
24979 assertion = arguments[0];
24980 Assert.isTrue(assertion, null);
24981 } else if (arguments.length === 2) {
24982 assertion = arguments[0];
24983 message = arguments[1];
24984 if (!assertion) {
24985 if (message === null) {
24986 throw new AssertionFailedException()
24987 } else {
24988 throw new AssertionFailedException(message)
24989 }
24990 }
24991 }
24992};
24993Assert.equals = function equals () {
24994 var expectedValue;
24995 var actualValue;
24996 var message;
24997 if (arguments.length === 2) {
24998 expectedValue = arguments[0];
24999 actualValue = arguments[1];
25000 Assert.equals(expectedValue, actualValue, null);
25001 } else if (arguments.length === 3) {
25002 expectedValue = arguments[0];
25003 actualValue = arguments[1];
25004 message = arguments[2];
25005 if (!actualValue.equals(expectedValue)) {
25006 throw new AssertionFailedException('Expected ' + expectedValue + ' but encountered ' + actualValue + (message !== null ? ': ' + message : ''))
25007 }
25008 }
25009};
25010
25011var LineIntersector = function LineIntersector () {
25012 this._result = null;
25013 this._inputLines = Array(2).fill().map(function () { return Array(2); });
25014 this._intPt = new Array(2).fill(null);
25015 this._intLineIndex = null;
25016 this._isProper = null;
25017 this._pa = null;
25018 this._pb = null;
25019 this._precisionModel = null;
25020 this._intPt[0] = new Coordinate();
25021 this._intPt[1] = new Coordinate();
25022 this._pa = this._intPt[0];
25023 this._pb = this._intPt[1];
25024 this._result = 0;
25025};
25026
25027var staticAccessors$10 = { DONT_INTERSECT: { configurable: true },DO_INTERSECT: { configurable: true },COLLINEAR: { configurable: true },NO_INTERSECTION: { configurable: true },POINT_INTERSECTION: { configurable: true },COLLINEAR_INTERSECTION: { configurable: true } };
25028LineIntersector.prototype.getIndexAlongSegment = function getIndexAlongSegment (segmentIndex, intIndex) {
25029 this.computeIntLineIndex();
25030 return this._intLineIndex[segmentIndex][intIndex]
25031};
25032LineIntersector.prototype.getTopologySummary = function getTopologySummary () {
25033 var catBuf = new StringBuffer();
25034 if (this.isEndPoint()) { catBuf.append(' endpoint'); }
25035 if (this._isProper) { catBuf.append(' proper'); }
25036 if (this.isCollinear()) { catBuf.append(' collinear'); }
25037 return catBuf.toString()
25038};
25039LineIntersector.prototype.computeIntersection = function computeIntersection (p1, p2, p3, p4) {
25040 this._inputLines[0][0] = p1;
25041 this._inputLines[0][1] = p2;
25042 this._inputLines[1][0] = p3;
25043 this._inputLines[1][1] = p4;
25044 this._result = this.computeIntersect(p1, p2, p3, p4);
25045};
25046LineIntersector.prototype.getIntersectionNum = function getIntersectionNum () {
25047 return this._result
25048};
25049LineIntersector.prototype.computeIntLineIndex = function computeIntLineIndex () {
25050 if (arguments.length === 0) {
25051 if (this._intLineIndex === null) {
25052 this._intLineIndex = Array(2).fill().map(function () { return Array(2); });
25053 this.computeIntLineIndex(0);
25054 this.computeIntLineIndex(1);
25055 }
25056 } else if (arguments.length === 1) {
25057 var segmentIndex = arguments[0];
25058 var dist0 = this.getEdgeDistance(segmentIndex, 0);
25059 var dist1 = this.getEdgeDistance(segmentIndex, 1);
25060 if (dist0 > dist1) {
25061 this._intLineIndex[segmentIndex][0] = 0;
25062 this._intLineIndex[segmentIndex][1] = 1;
25063 } else {
25064 this._intLineIndex[segmentIndex][0] = 1;
25065 this._intLineIndex[segmentIndex][1] = 0;
25066 }
25067 }
25068};
25069LineIntersector.prototype.isProper = function isProper () {
25070 return this.hasIntersection() && this._isProper
25071};
25072LineIntersector.prototype.setPrecisionModel = function setPrecisionModel (precisionModel) {
25073 this._precisionModel = precisionModel;
25074};
25075LineIntersector.prototype.isInteriorIntersection = function isInteriorIntersection () {
25076 var this$1 = this;
25077
25078 if (arguments.length === 0) {
25079 if (this.isInteriorIntersection(0)) { return true }
25080 if (this.isInteriorIntersection(1)) { return true }
25081 return false
25082 } else if (arguments.length === 1) {
25083 var inputLineIndex = arguments[0];
25084 for (var i = 0; i < this._result; i++) {
25085 if (!(this$1._intPt[i].equals2D(this$1._inputLines[inputLineIndex][0]) || this$1._intPt[i].equals2D(this$1._inputLines[inputLineIndex][1]))) {
25086 return true
25087 }
25088 }
25089 return false
25090 }
25091};
25092LineIntersector.prototype.getIntersection = function getIntersection (intIndex) {
25093 return this._intPt[intIndex]
25094};
25095LineIntersector.prototype.isEndPoint = function isEndPoint () {
25096 return this.hasIntersection() && !this._isProper
25097};
25098LineIntersector.prototype.hasIntersection = function hasIntersection () {
25099 return this._result !== LineIntersector.NO_INTERSECTION
25100};
25101LineIntersector.prototype.getEdgeDistance = function getEdgeDistance (segmentIndex, intIndex) {
25102 var dist = LineIntersector.computeEdgeDistance(this._intPt[intIndex], this._inputLines[segmentIndex][0], this._inputLines[segmentIndex][1]);
25103 return dist
25104};
25105LineIntersector.prototype.isCollinear = function isCollinear () {
25106 return this._result === LineIntersector.COLLINEAR_INTERSECTION
25107};
25108LineIntersector.prototype.toString = function toString () {
25109 return WKTWriter.toLineString(this._inputLines[0][0], this._inputLines[0][1]) + ' - ' + WKTWriter.toLineString(this._inputLines[1][0], this._inputLines[1][1]) + this.getTopologySummary()
25110};
25111LineIntersector.prototype.getEndpoint = function getEndpoint (segmentIndex, ptIndex) {
25112 return this._inputLines[segmentIndex][ptIndex]
25113};
25114LineIntersector.prototype.isIntersection = function isIntersection (pt) {
25115 var this$1 = this;
25116
25117 for (var i = 0; i < this._result; i++) {
25118 if (this$1._intPt[i].equals2D(pt)) {
25119 return true
25120 }
25121 }
25122 return false
25123};
25124LineIntersector.prototype.getIntersectionAlongSegment = function getIntersectionAlongSegment (segmentIndex, intIndex) {
25125 this.computeIntLineIndex();
25126 return this._intPt[this._intLineIndex[segmentIndex][intIndex]]
25127};
25128LineIntersector.prototype.interfaces_ = function interfaces_ () {
25129 return []
25130};
25131LineIntersector.prototype.getClass = function getClass () {
25132 return LineIntersector
25133};
25134LineIntersector.computeEdgeDistance = function computeEdgeDistance (p, p0, p1) {
25135 var dx = Math.abs(p1.x - p0.x);
25136 var dy = Math.abs(p1.y - p0.y);
25137 var dist = -1.0;
25138 if (p.equals(p0)) {
25139 dist = 0.0;
25140 } else if (p.equals(p1)) {
25141 if (dx > dy) { dist = dx; } else { dist = dy; }
25142 } else {
25143 var pdx = Math.abs(p.x - p0.x);
25144 var pdy = Math.abs(p.y - p0.y);
25145 if (dx > dy) { dist = pdx; } else { dist = pdy; }
25146 if (dist === 0.0 && !p.equals(p0)) {
25147 dist = Math.max(pdx, pdy);
25148 }
25149 }
25150 Assert.isTrue(!(dist === 0.0 && !p.equals(p0)), 'Bad distance calculation');
25151 return dist
25152};
25153LineIntersector.nonRobustComputeEdgeDistance = function nonRobustComputeEdgeDistance (p, p1, p2) {
25154 var dx = p.x - p1.x;
25155 var dy = p.y - p1.y;
25156 var dist = Math.sqrt(dx * dx + dy * dy);
25157 Assert.isTrue(!(dist === 0.0 && !p.equals(p1)), 'Invalid distance calculation');
25158 return dist
25159};
25160staticAccessors$10.DONT_INTERSECT.get = function () { return 0 };
25161staticAccessors$10.DO_INTERSECT.get = function () { return 1 };
25162staticAccessors$10.COLLINEAR.get = function () { return 2 };
25163staticAccessors$10.NO_INTERSECTION.get = function () { return 0 };
25164staticAccessors$10.POINT_INTERSECTION.get = function () { return 1 };
25165staticAccessors$10.COLLINEAR_INTERSECTION.get = function () { return 2 };
25166
25167Object.defineProperties( LineIntersector, staticAccessors$10 );
25168
25169var RobustLineIntersector = (function (LineIntersector$$1) {
25170 function RobustLineIntersector () {
25171 LineIntersector$$1.apply(this, arguments);
25172 }
25173
25174 if ( LineIntersector$$1 ) RobustLineIntersector.__proto__ = LineIntersector$$1;
25175 RobustLineIntersector.prototype = Object.create( LineIntersector$$1 && LineIntersector$$1.prototype );
25176 RobustLineIntersector.prototype.constructor = RobustLineIntersector;
25177
25178 RobustLineIntersector.prototype.isInSegmentEnvelopes = function isInSegmentEnvelopes (intPt) {
25179 var env0 = new Envelope(this._inputLines[0][0], this._inputLines[0][1]);
25180 var env1 = new Envelope(this._inputLines[1][0], this._inputLines[1][1]);
25181 return env0.contains(intPt) && env1.contains(intPt)
25182 };
25183 RobustLineIntersector.prototype.computeIntersection = function computeIntersection () {
25184 if (arguments.length === 3) {
25185 var p = arguments[0];
25186 var p1 = arguments[1];
25187 var p2 = arguments[2];
25188 this._isProper = false;
25189 if (Envelope.intersects(p1, p2, p)) {
25190 if (CGAlgorithms.orientationIndex(p1, p2, p) === 0 && CGAlgorithms.orientationIndex(p2, p1, p) === 0) {
25191 this._isProper = true;
25192 if (p.equals(p1) || p.equals(p2)) {
25193 this._isProper = false;
25194 }
25195 this._result = LineIntersector$$1.POINT_INTERSECTION;
25196 return null
25197 }
25198 }
25199 this._result = LineIntersector$$1.NO_INTERSECTION;
25200 } else { return LineIntersector$$1.prototype.computeIntersection.apply(this, arguments) }
25201 };
25202 RobustLineIntersector.prototype.normalizeToMinimum = function normalizeToMinimum (n1, n2, n3, n4, normPt) {
25203 normPt.x = this.smallestInAbsValue(n1.x, n2.x, n3.x, n4.x);
25204 normPt.y = this.smallestInAbsValue(n1.y, n2.y, n3.y, n4.y);
25205 n1.x -= normPt.x;
25206 n1.y -= normPt.y;
25207 n2.x -= normPt.x;
25208 n2.y -= normPt.y;
25209 n3.x -= normPt.x;
25210 n3.y -= normPt.y;
25211 n4.x -= normPt.x;
25212 n4.y -= normPt.y;
25213 };
25214 RobustLineIntersector.prototype.safeHCoordinateIntersection = function safeHCoordinateIntersection (p1, p2, q1, q2) {
25215 var intPt = null;
25216 try {
25217 intPt = HCoordinate.intersection(p1, p2, q1, q2);
25218 } catch (e) {
25219 if (e instanceof NotRepresentableException) {
25220 intPt = RobustLineIntersector.nearestEndpoint(p1, p2, q1, q2);
25221 } else { throw e }
25222 } finally {}
25223 return intPt
25224 };
25225 RobustLineIntersector.prototype.intersection = function intersection (p1, p2, q1, q2) {
25226 var intPt = this.intersectionWithNormalization(p1, p2, q1, q2);
25227 if (!this.isInSegmentEnvelopes(intPt)) {
25228 intPt = new Coordinate(RobustLineIntersector.nearestEndpoint(p1, p2, q1, q2));
25229 }
25230 if (this._precisionModel !== null) {
25231 this._precisionModel.makePrecise(intPt);
25232 }
25233 return intPt
25234 };
25235 RobustLineIntersector.prototype.smallestInAbsValue = function smallestInAbsValue (x1, x2, x3, x4) {
25236 var x = x1;
25237 var xabs = Math.abs(x);
25238 if (Math.abs(x2) < xabs) {
25239 x = x2;
25240 xabs = Math.abs(x2);
25241 }
25242 if (Math.abs(x3) < xabs) {
25243 x = x3;
25244 xabs = Math.abs(x3);
25245 }
25246 if (Math.abs(x4) < xabs) {
25247 x = x4;
25248 }
25249 return x
25250 };
25251 RobustLineIntersector.prototype.checkDD = function checkDD (p1, p2, q1, q2, intPt) {
25252 var intPtDD = CGAlgorithmsDD.intersection(p1, p2, q1, q2);
25253 var isIn = this.isInSegmentEnvelopes(intPtDD);
25254 System.out.println('DD in env = ' + isIn + ' --------------------- ' + intPtDD);
25255 if (intPt.distance(intPtDD) > 0.0001) {
25256 System.out.println('Distance = ' + intPt.distance(intPtDD));
25257 }
25258 };
25259 RobustLineIntersector.prototype.intersectionWithNormalization = function intersectionWithNormalization (p1, p2, q1, q2) {
25260 var n1 = new Coordinate(p1);
25261 var n2 = new Coordinate(p2);
25262 var n3 = new Coordinate(q1);
25263 var n4 = new Coordinate(q2);
25264 var normPt = new Coordinate();
25265 this.normalizeToEnvCentre(n1, n2, n3, n4, normPt);
25266 var intPt = this.safeHCoordinateIntersection(n1, n2, n3, n4);
25267 intPt.x += normPt.x;
25268 intPt.y += normPt.y;
25269 return intPt
25270 };
25271 RobustLineIntersector.prototype.computeCollinearIntersection = function computeCollinearIntersection (p1, p2, q1, q2) {
25272 var p1q1p2 = Envelope.intersects(p1, p2, q1);
25273 var p1q2p2 = Envelope.intersects(p1, p2, q2);
25274 var q1p1q2 = Envelope.intersects(q1, q2, p1);
25275 var q1p2q2 = Envelope.intersects(q1, q2, p2);
25276 if (p1q1p2 && p1q2p2) {
25277 this._intPt[0] = q1;
25278 this._intPt[1] = q2;
25279 return LineIntersector$$1.COLLINEAR_INTERSECTION
25280 }
25281 if (q1p1q2 && q1p2q2) {
25282 this._intPt[0] = p1;
25283 this._intPt[1] = p2;
25284 return LineIntersector$$1.COLLINEAR_INTERSECTION
25285 }
25286 if (p1q1p2 && q1p1q2) {
25287 this._intPt[0] = q1;
25288 this._intPt[1] = p1;
25289 return q1.equals(p1) && !p1q2p2 && !q1p2q2 ? LineIntersector$$1.POINT_INTERSECTION : LineIntersector$$1.COLLINEAR_INTERSECTION
25290 }
25291 if (p1q1p2 && q1p2q2) {
25292 this._intPt[0] = q1;
25293 this._intPt[1] = p2;
25294 return q1.equals(p2) && !p1q2p2 && !q1p1q2 ? LineIntersector$$1.POINT_INTERSECTION : LineIntersector$$1.COLLINEAR_INTERSECTION
25295 }
25296 if (p1q2p2 && q1p1q2) {
25297 this._intPt[0] = q2;
25298 this._intPt[1] = p1;
25299 return q2.equals(p1) && !p1q1p2 && !q1p2q2 ? LineIntersector$$1.POINT_INTERSECTION : LineIntersector$$1.COLLINEAR_INTERSECTION
25300 }
25301 if (p1q2p2 && q1p2q2) {
25302 this._intPt[0] = q2;
25303 this._intPt[1] = p2;
25304 return q2.equals(p2) && !p1q1p2 && !q1p1q2 ? LineIntersector$$1.POINT_INTERSECTION : LineIntersector$$1.COLLINEAR_INTERSECTION
25305 }
25306 return LineIntersector$$1.NO_INTERSECTION
25307 };
25308 RobustLineIntersector.prototype.normalizeToEnvCentre = function normalizeToEnvCentre (n00, n01, n10, n11, normPt) {
25309 var minX0 = n00.x < n01.x ? n00.x : n01.x;
25310 var minY0 = n00.y < n01.y ? n00.y : n01.y;
25311 var maxX0 = n00.x > n01.x ? n00.x : n01.x;
25312 var maxY0 = n00.y > n01.y ? n00.y : n01.y;
25313 var minX1 = n10.x < n11.x ? n10.x : n11.x;
25314 var minY1 = n10.y < n11.y ? n10.y : n11.y;
25315 var maxX1 = n10.x > n11.x ? n10.x : n11.x;
25316 var maxY1 = n10.y > n11.y ? n10.y : n11.y;
25317 var intMinX = minX0 > minX1 ? minX0 : minX1;
25318 var intMaxX = maxX0 < maxX1 ? maxX0 : maxX1;
25319 var intMinY = minY0 > minY1 ? minY0 : minY1;
25320 var intMaxY = maxY0 < maxY1 ? maxY0 : maxY1;
25321 var intMidX = (intMinX + intMaxX) / 2.0;
25322 var intMidY = (intMinY + intMaxY) / 2.0;
25323 normPt.x = intMidX;
25324 normPt.y = intMidY;
25325 n00.x -= normPt.x;
25326 n00.y -= normPt.y;
25327 n01.x -= normPt.x;
25328 n01.y -= normPt.y;
25329 n10.x -= normPt.x;
25330 n10.y -= normPt.y;
25331 n11.x -= normPt.x;
25332 n11.y -= normPt.y;
25333 };
25334 RobustLineIntersector.prototype.computeIntersect = function computeIntersect (p1, p2, q1, q2) {
25335 this._isProper = false;
25336 if (!Envelope.intersects(p1, p2, q1, q2)) { return LineIntersector$$1.NO_INTERSECTION }
25337 var Pq1 = CGAlgorithms.orientationIndex(p1, p2, q1);
25338 var Pq2 = CGAlgorithms.orientationIndex(p1, p2, q2);
25339 if ((Pq1 > 0 && Pq2 > 0) || (Pq1 < 0 && Pq2 < 0)) {
25340 return LineIntersector$$1.NO_INTERSECTION
25341 }
25342 var Qp1 = CGAlgorithms.orientationIndex(q1, q2, p1);
25343 var Qp2 = CGAlgorithms.orientationIndex(q1, q2, p2);
25344 if ((Qp1 > 0 && Qp2 > 0) || (Qp1 < 0 && Qp2 < 0)) {
25345 return LineIntersector$$1.NO_INTERSECTION
25346 }
25347 var collinear = Pq1 === 0 && Pq2 === 0 && Qp1 === 0 && Qp2 === 0;
25348 if (collinear) {
25349 return this.computeCollinearIntersection(p1, p2, q1, q2)
25350 }
25351 if (Pq1 === 0 || Pq2 === 0 || Qp1 === 0 || Qp2 === 0) {
25352 this._isProper = false;
25353 if (p1.equals2D(q1) || p1.equals2D(q2)) {
25354 this._intPt[0] = p1;
25355 } else if (p2.equals2D(q1) || p2.equals2D(q2)) {
25356 this._intPt[0] = p2;
25357 } else if (Pq1 === 0) {
25358 this._intPt[0] = new Coordinate(q1);
25359 } else if (Pq2 === 0) {
25360 this._intPt[0] = new Coordinate(q2);
25361 } else if (Qp1 === 0) {
25362 this._intPt[0] = new Coordinate(p1);
25363 } else if (Qp2 === 0) {
25364 this._intPt[0] = new Coordinate(p2);
25365 }
25366 } else {
25367 this._isProper = true;
25368 this._intPt[0] = this.intersection(p1, p2, q1, q2);
25369 }
25370 return LineIntersector$$1.POINT_INTERSECTION
25371 };
25372 RobustLineIntersector.prototype.interfaces_ = function interfaces_ () {
25373 return []
25374 };
25375 RobustLineIntersector.prototype.getClass = function getClass () {
25376 return RobustLineIntersector
25377 };
25378 RobustLineIntersector.nearestEndpoint = function nearestEndpoint (p1, p2, q1, q2) {
25379 var nearestPt = p1;
25380 var minDist = CGAlgorithms.distancePointLine(p1, q1, q2);
25381 var dist = CGAlgorithms.distancePointLine(p2, q1, q2);
25382 if (dist < minDist) {
25383 minDist = dist;
25384 nearestPt = p2;
25385 }
25386 dist = CGAlgorithms.distancePointLine(q1, p1, p2);
25387 if (dist < minDist) {
25388 minDist = dist;
25389 nearestPt = q1;
25390 }
25391 dist = CGAlgorithms.distancePointLine(q2, p1, p2);
25392 if (dist < minDist) {
25393 minDist = dist;
25394 nearestPt = q2;
25395 }
25396 return nearestPt
25397 };
25398
25399 return RobustLineIntersector;
25400}(LineIntersector));
25401
25402var RobustDeterminant = function RobustDeterminant () {};
25403
25404RobustDeterminant.prototype.interfaces_ = function interfaces_ () {
25405 return []
25406};
25407RobustDeterminant.prototype.getClass = function getClass () {
25408 return RobustDeterminant
25409};
25410RobustDeterminant.orientationIndex = function orientationIndex (p1, p2, q) {
25411 var dx1 = p2.x - p1.x;
25412 var dy1 = p2.y - p1.y;
25413 var dx2 = q.x - p2.x;
25414 var dy2 = q.y - p2.y;
25415 return RobustDeterminant.signOfDet2x2(dx1, dy1, dx2, dy2)
25416};
25417RobustDeterminant.signOfDet2x2 = function signOfDet2x2 (x1, y1, x2, y2) {
25418 var sign = null;
25419 var swap = null;
25420 var k = null;
25421 sign = 1;
25422 if (x1 === 0.0 || y2 === 0.0) {
25423 if (y1 === 0.0 || x2 === 0.0) {
25424 return 0
25425 } else if (y1 > 0) {
25426 if (x2 > 0) {
25427 return -sign
25428 } else {
25429 return sign
25430 }
25431 } else {
25432 if (x2 > 0) {
25433 return sign
25434 } else {
25435 return -sign
25436 }
25437 }
25438 }
25439 if (y1 === 0.0 || x2 === 0.0) {
25440 if (y2 > 0) {
25441 if (x1 > 0) {
25442 return sign
25443 } else {
25444 return -sign
25445 }
25446 } else {
25447 if (x1 > 0) {
25448 return -sign
25449 } else {
25450 return sign
25451 }
25452 }
25453 }
25454 if (y1 > 0.0) {
25455 if (y2 > 0.0) {
25456 if (y1 <= y2) {
25457
25458 } else {
25459 sign = -sign;
25460 swap = x1;
25461 x1 = x2;
25462 x2 = swap;
25463 swap = y1;
25464 y1 = y2;
25465 y2 = swap;
25466 }
25467 } else {
25468 if (y1 <= -y2) {
25469 sign = -sign;
25470 x2 = -x2;
25471 y2 = -y2;
25472 } else {
25473 swap = x1;
25474 x1 = -x2;
25475 x2 = swap;
25476 swap = y1;
25477 y1 = -y2;
25478 y2 = swap;
25479 }
25480 }
25481 } else {
25482 if (y2 > 0.0) {
25483 if (-y1 <= y2) {
25484 sign = -sign;
25485 x1 = -x1;
25486 y1 = -y1;
25487 } else {
25488 swap = -x1;
25489 x1 = x2;
25490 x2 = swap;
25491 swap = -y1;
25492 y1 = y2;
25493 y2 = swap;
25494 }
25495 } else {
25496 if (y1 >= y2) {
25497 x1 = -x1;
25498 y1 = -y1;
25499 x2 = -x2;
25500 y2 = -y2;
25501 } else {
25502 sign = -sign;
25503 swap = -x1;
25504 x1 = -x2;
25505 x2 = swap;
25506 swap = -y1;
25507 y1 = -y2;
25508 y2 = swap;
25509 }
25510 }
25511 }
25512 if (x1 > 0.0) {
25513 if (x2 > 0.0) {
25514 if (x1 <= x2) {
25515
25516 } else {
25517 return sign
25518 }
25519 } else {
25520 return sign
25521 }
25522 } else {
25523 if (x2 > 0.0) {
25524 return -sign
25525 } else {
25526 if (x1 >= x2) {
25527 sign = -sign;
25528 x1 = -x1;
25529 x2 = -x2;
25530 } else {
25531 return -sign
25532 }
25533 }
25534 }
25535 while (true) {
25536 k = Math.floor(x2 / x1);
25537 x2 = x2 - k * x1;
25538 y2 = y2 - k * y1;
25539 if (y2 < 0.0) {
25540 return -sign
25541 }
25542 if (y2 > y1) {
25543 return sign
25544 }
25545 if (x1 > x2 + x2) {
25546 if (y1 < y2 + y2) {
25547 return sign
25548 }
25549 } else {
25550 if (y1 > y2 + y2) {
25551 return -sign
25552 } else {
25553 x2 = x1 - x2;
25554 y2 = y1 - y2;
25555 sign = -sign;
25556 }
25557 }
25558 if (y2 === 0.0) {
25559 if (x2 === 0.0) {
25560 return 0
25561 } else {
25562 return -sign
25563 }
25564 }
25565 if (x2 === 0.0) {
25566 return sign
25567 }
25568 k = Math.floor(x1 / x2);
25569 x1 = x1 - k * x2;
25570 y1 = y1 - k * y2;
25571 if (y1 < 0.0) {
25572 return sign
25573 }
25574 if (y1 > y2) {
25575 return -sign
25576 }
25577 if (x2 > x1 + x1) {
25578 if (y2 < y1 + y1) {
25579 return -sign
25580 }
25581 } else {
25582 if (y2 > y1 + y1) {
25583 return sign
25584 } else {
25585 x1 = x2 - x1;
25586 y1 = y2 - y1;
25587 sign = -sign;
25588 }
25589 }
25590 if (y1 === 0.0) {
25591 if (x1 === 0.0) {
25592 return 0
25593 } else {
25594 return sign
25595 }
25596 }
25597 if (x1 === 0.0) {
25598 return -sign
25599 }
25600 }
25601};
25602
25603var RayCrossingCounter = function RayCrossingCounter () {
25604 this._p = null;
25605 this._crossingCount = 0;
25606 this._isPointOnSegment = false;
25607 var p = arguments[0];
25608 this._p = p;
25609};
25610RayCrossingCounter.prototype.countSegment = function countSegment (p1, p2) {
25611 if (p1.x < this._p.x && p2.x < this._p.x) { return null }
25612 if (this._p.x === p2.x && this._p.y === p2.y) {
25613 this._isPointOnSegment = true;
25614 return null
25615 }
25616 if (p1.y === this._p.y && p2.y === this._p.y) {
25617 var minx = p1.x;
25618 var maxx = p2.x;
25619 if (minx > maxx) {
25620 minx = p2.x;
25621 maxx = p1.x;
25622 }
25623 if (this._p.x >= minx && this._p.x <= maxx) {
25624 this._isPointOnSegment = true;
25625 }
25626 return null
25627 }
25628 if ((p1.y > this._p.y && p2.y <= this._p.y) || (p2.y > this._p.y && p1.y <= this._p.y)) {
25629 var x1 = p1.x - this._p.x;
25630 var y1 = p1.y - this._p.y;
25631 var x2 = p2.x - this._p.x;
25632 var y2 = p2.y - this._p.y;
25633 var xIntSign = RobustDeterminant.signOfDet2x2(x1, y1, x2, y2);
25634 if (xIntSign === 0.0) {
25635 this._isPointOnSegment = true;
25636 return null
25637 }
25638 if (y2 < y1) { xIntSign = -xIntSign; }
25639 if (xIntSign > 0.0) {
25640 this._crossingCount++;
25641 }
25642 }
25643};
25644RayCrossingCounter.prototype.isPointInPolygon = function isPointInPolygon () {
25645 return this.getLocation() !== Location.EXTERIOR
25646};
25647RayCrossingCounter.prototype.getLocation = function getLocation () {
25648 if (this._isPointOnSegment) { return Location.BOUNDARY }
25649 if (this._crossingCount % 2 === 1) {
25650 return Location.INTERIOR
25651 }
25652 return Location.EXTERIOR
25653};
25654RayCrossingCounter.prototype.isOnSegment = function isOnSegment () {
25655 return this._isPointOnSegment
25656};
25657RayCrossingCounter.prototype.interfaces_ = function interfaces_ () {
25658 return []
25659};
25660RayCrossingCounter.prototype.getClass = function getClass () {
25661 return RayCrossingCounter
25662};
25663RayCrossingCounter.locatePointInRing = function locatePointInRing () {
25664 if (arguments[0] instanceof Coordinate && hasInterface(arguments[1], CoordinateSequence)) {
25665 var p = arguments[0];
25666 var ring = arguments[1];
25667 var counter = new RayCrossingCounter(p);
25668 var p1 = new Coordinate();
25669 var p2 = new Coordinate();
25670 for (var i = 1; i < ring.size(); i++) {
25671 ring.getCoordinate(i, p1);
25672 ring.getCoordinate(i - 1, p2);
25673 counter.countSegment(p1, p2);
25674 if (counter.isOnSegment()) { return counter.getLocation() }
25675 }
25676 return counter.getLocation()
25677 } else if (arguments[0] instanceof Coordinate && arguments[1] instanceof Array) {
25678 var p$1 = arguments[0];
25679 var ring$1 = arguments[1];
25680 var counter$1 = new RayCrossingCounter(p$1);
25681 for (var i$1 = 1; i$1 < ring$1.length; i$1++) {
25682 var p1$1 = ring$1[i$1];
25683 var p2$1 = ring$1[i$1 - 1];
25684 counter$1.countSegment(p1$1, p2$1);
25685 if (counter$1.isOnSegment()) { return counter$1.getLocation() }
25686 }
25687 return counter$1.getLocation()
25688 }
25689};
25690
25691var CGAlgorithms = function CGAlgorithms () {};
25692
25693var staticAccessors$3 = { CLOCKWISE: { configurable: true },RIGHT: { configurable: true },COUNTERCLOCKWISE: { configurable: true },LEFT: { configurable: true },COLLINEAR: { configurable: true },STRAIGHT: { configurable: true } };
25694
25695CGAlgorithms.prototype.interfaces_ = function interfaces_ () {
25696 return []
25697};
25698CGAlgorithms.prototype.getClass = function getClass () {
25699 return CGAlgorithms
25700};
25701CGAlgorithms.orientationIndex = function orientationIndex (p1, p2, q) {
25702 return CGAlgorithmsDD.orientationIndex(p1, p2, q)
25703};
25704CGAlgorithms.signedArea = function signedArea () {
25705 if (arguments[0] instanceof Array) {
25706 var ring = arguments[0];
25707 if (ring.length < 3) { return 0.0 }
25708 var sum = 0.0;
25709 var x0 = ring[0].x;
25710 for (var i = 1; i < ring.length - 1; i++) {
25711 var x = ring[i].x - x0;
25712 var y1 = ring[i + 1].y;
25713 var y2 = ring[i - 1].y;
25714 sum += x * (y2 - y1);
25715 }
25716 return sum / 2.0
25717 } else if (hasInterface(arguments[0], CoordinateSequence)) {
25718 var ring$1 = arguments[0];
25719 var n = ring$1.size();
25720 if (n < 3) { return 0.0 }
25721 var p0 = new Coordinate();
25722 var p1 = new Coordinate();
25723 var p2 = new Coordinate();
25724 ring$1.getCoordinate(0, p1);
25725 ring$1.getCoordinate(1, p2);
25726 var x0$1 = p1.x;
25727 p2.x -= x0$1;
25728 var sum$1 = 0.0;
25729 for (var i$1 = 1; i$1 < n - 1; i$1++) {
25730 p0.y = p1.y;
25731 p1.x = p2.x;
25732 p1.y = p2.y;
25733 ring$1.getCoordinate(i$1 + 1, p2);
25734 p2.x -= x0$1;
25735 sum$1 += p1.x * (p0.y - p2.y);
25736 }
25737 return sum$1 / 2.0
25738 }
25739};
25740CGAlgorithms.distanceLineLine = function distanceLineLine (A, B, C, D) {
25741 if (A.equals(B)) { return CGAlgorithms.distancePointLine(A, C, D) }
25742 if (C.equals(D)) { return CGAlgorithms.distancePointLine(D, A, B) }
25743 var noIntersection = false;
25744 if (!Envelope.intersects(A, B, C, D)) {
25745 noIntersection = true;
25746 } else {
25747 var denom = (B.x - A.x) * (D.y - C.y) - (B.y - A.y) * (D.x - C.x);
25748 if (denom === 0) {
25749 noIntersection = true;
25750 } else {
25751 var rNumb = (A.y - C.y) * (D.x - C.x) - (A.x - C.x) * (D.y - C.y);
25752 var sNum = (A.y - C.y) * (B.x - A.x) - (A.x - C.x) * (B.y - A.y);
25753 var s = sNum / denom;
25754 var r = rNumb / denom;
25755 if (r < 0 || r > 1 || s < 0 || s > 1) {
25756 noIntersection = true;
25757 }
25758 }
25759 }
25760 if (noIntersection) {
25761 return MathUtil.min(CGAlgorithms.distancePointLine(A, C, D), CGAlgorithms.distancePointLine(B, C, D), CGAlgorithms.distancePointLine(C, A, B), CGAlgorithms.distancePointLine(D, A, B))
25762 }
25763 return 0.0
25764};
25765CGAlgorithms.isPointInRing = function isPointInRing (p, ring) {
25766 return CGAlgorithms.locatePointInRing(p, ring) !== Location.EXTERIOR
25767};
25768CGAlgorithms.computeLength = function computeLength (pts) {
25769 var n = pts.size();
25770 if (n <= 1) { return 0.0 }
25771 var len = 0.0;
25772 var p = new Coordinate();
25773 pts.getCoordinate(0, p);
25774 var x0 = p.x;
25775 var y0 = p.y;
25776 for (var i = 1; i < n; i++) {
25777 pts.getCoordinate(i, p);
25778 var x1 = p.x;
25779 var y1 = p.y;
25780 var dx = x1 - x0;
25781 var dy = y1 - y0;
25782 len += Math.sqrt(dx * dx + dy * dy);
25783 x0 = x1;
25784 y0 = y1;
25785 }
25786 return len
25787};
25788CGAlgorithms.isCCW = function isCCW (ring) {
25789 var nPts = ring.length - 1;
25790 if (nPts < 3) { throw new IllegalArgumentException('Ring has fewer than 4 points, so orientation cannot be determined') }
25791 var hiPt = ring[0];
25792 var hiIndex = 0;
25793 for (var i = 1; i <= nPts; i++) {
25794 var p = ring[i];
25795 if (p.y > hiPt.y) {
25796 hiPt = p;
25797 hiIndex = i;
25798 }
25799 }
25800 var iPrev = hiIndex;
25801 do {
25802 iPrev = iPrev - 1;
25803 if (iPrev < 0) { iPrev = nPts; }
25804 } while (ring[iPrev].equals2D(hiPt) && iPrev !== hiIndex)
25805 var iNext = hiIndex;
25806 do {
25807 iNext = (iNext + 1) % nPts;
25808 } while (ring[iNext].equals2D(hiPt) && iNext !== hiIndex)
25809 var prev = ring[iPrev];
25810 var next = ring[iNext];
25811 if (prev.equals2D(hiPt) || next.equals2D(hiPt) || prev.equals2D(next)) { return false }
25812 var disc = CGAlgorithms.computeOrientation(prev, hiPt, next);
25813 var isCCW = false;
25814 if (disc === 0) {
25815 isCCW = prev.x > next.x;
25816 } else {
25817 isCCW = disc > 0;
25818 }
25819 return isCCW
25820};
25821CGAlgorithms.locatePointInRing = function locatePointInRing (p, ring) {
25822 return RayCrossingCounter.locatePointInRing(p, ring)
25823};
25824CGAlgorithms.distancePointLinePerpendicular = function distancePointLinePerpendicular (p, A, B) {
25825 var len2 = (B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y);
25826 var s = ((A.y - p.y) * (B.x - A.x) - (A.x - p.x) * (B.y - A.y)) / len2;
25827 return Math.abs(s) * Math.sqrt(len2)
25828};
25829CGAlgorithms.computeOrientation = function computeOrientation (p1, p2, q) {
25830 return CGAlgorithms.orientationIndex(p1, p2, q)
25831};
25832CGAlgorithms.distancePointLine = function distancePointLine () {
25833 if (arguments.length === 2) {
25834 var p = arguments[0];
25835 var line = arguments[1];
25836 if (line.length === 0) { throw new IllegalArgumentException('Line array must contain at least one vertex') }
25837 var minDistance = p.distance(line[0]);
25838 for (var i = 0; i < line.length - 1; i++) {
25839 var dist = CGAlgorithms.distancePointLine(p, line[i], line[i + 1]);
25840 if (dist < minDistance) {
25841 minDistance = dist;
25842 }
25843 }
25844 return minDistance
25845 } else if (arguments.length === 3) {
25846 var p$1 = arguments[0];
25847 var A = arguments[1];
25848 var B = arguments[2];
25849 if (A.x === B.x && A.y === B.y) { return p$1.distance(A) }
25850 var len2 = (B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y);
25851 var r = ((p$1.x - A.x) * (B.x - A.x) + (p$1.y - A.y) * (B.y - A.y)) / len2;
25852 if (r <= 0.0) { return p$1.distance(A) }
25853 if (r >= 1.0) { return p$1.distance(B) }
25854 var s = ((A.y - p$1.y) * (B.x - A.x) - (A.x - p$1.x) * (B.y - A.y)) / len2;
25855 return Math.abs(s) * Math.sqrt(len2)
25856 }
25857};
25858CGAlgorithms.isOnLine = function isOnLine (p, pt) {
25859 var lineIntersector = new RobustLineIntersector();
25860 for (var i = 1; i < pt.length; i++) {
25861 var p0 = pt[i - 1];
25862 var p1 = pt[i];
25863 lineIntersector.computeIntersection(p, p0, p1);
25864 if (lineIntersector.hasIntersection()) {
25865 return true
25866 }
25867 }
25868 return false
25869};
25870staticAccessors$3.CLOCKWISE.get = function () { return -1 };
25871staticAccessors$3.RIGHT.get = function () { return CGAlgorithms.CLOCKWISE };
25872staticAccessors$3.COUNTERCLOCKWISE.get = function () { return 1 };
25873staticAccessors$3.LEFT.get = function () { return CGAlgorithms.COUNTERCLOCKWISE };
25874staticAccessors$3.COLLINEAR.get = function () { return 0 };
25875staticAccessors$3.STRAIGHT.get = function () { return CGAlgorithms.COLLINEAR };
25876
25877Object.defineProperties( CGAlgorithms, staticAccessors$3 );
25878
25879var GeometryComponentFilter = function GeometryComponentFilter () {};
25880
25881GeometryComponentFilter.prototype.filter = function filter (geom) {};
25882GeometryComponentFilter.prototype.interfaces_ = function interfaces_ () {
25883 return []
25884};
25885GeometryComponentFilter.prototype.getClass = function getClass () {
25886 return GeometryComponentFilter
25887};
25888
25889var Geometry = function Geometry () {
25890 var factory = arguments[0];
25891
25892 this._envelope = null;
25893 this._factory = null;
25894 this._SRID = null;
25895 this._userData = null;
25896 this._factory = factory;
25897 this._SRID = factory.getSRID();
25898};
25899
25900var staticAccessors$11 = { serialVersionUID: { configurable: true },SORTINDEX_POINT: { configurable: true },SORTINDEX_MULTIPOINT: { configurable: true },SORTINDEX_LINESTRING: { configurable: true },SORTINDEX_LINEARRING: { configurable: true },SORTINDEX_MULTILINESTRING: { configurable: true },SORTINDEX_POLYGON: { configurable: true },SORTINDEX_MULTIPOLYGON: { configurable: true },SORTINDEX_GEOMETRYCOLLECTION: { configurable: true },geometryChangedFilter: { configurable: true } };
25901Geometry.prototype.isGeometryCollection = function isGeometryCollection () {
25902 return this.getSortIndex() === Geometry.SORTINDEX_GEOMETRYCOLLECTION
25903};
25904Geometry.prototype.getFactory = function getFactory () {
25905 return this._factory
25906};
25907Geometry.prototype.getGeometryN = function getGeometryN (n) {
25908 return this
25909};
25910Geometry.prototype.getArea = function getArea () {
25911 return 0.0
25912};
25913Geometry.prototype.isRectangle = function isRectangle () {
25914 return false
25915};
25916Geometry.prototype.equals = function equals () {
25917 if (arguments[0] instanceof Geometry) {
25918 var g$1 = arguments[0];
25919 if (g$1 === null) { return false }
25920 return this.equalsTopo(g$1)
25921 } else if (arguments[0] instanceof Object) {
25922 var o = arguments[0];
25923 if (!(o instanceof Geometry)) { return false }
25924 var g = o;
25925 return this.equalsExact(g)
25926 }
25927};
25928Geometry.prototype.equalsExact = function equalsExact (other) {
25929 return this === other || this.equalsExact(other, 0)
25930};
25931Geometry.prototype.geometryChanged = function geometryChanged () {
25932 this.apply(Geometry.geometryChangedFilter);
25933};
25934Geometry.prototype.geometryChangedAction = function geometryChangedAction () {
25935 this._envelope = null;
25936};
25937Geometry.prototype.equalsNorm = function equalsNorm (g) {
25938 if (g === null) { return false }
25939 return this.norm().equalsExact(g.norm())
25940};
25941Geometry.prototype.getLength = function getLength () {
25942 return 0.0
25943};
25944Geometry.prototype.getNumGeometries = function getNumGeometries () {
25945 return 1
25946};
25947Geometry.prototype.compareTo = function compareTo () {
25948 if (arguments.length === 1) {
25949 var o = arguments[0];
25950 var other = o;
25951 if (this.getSortIndex() !== other.getSortIndex()) {
25952 return this.getSortIndex() - other.getSortIndex()
25953 }
25954 if (this.isEmpty() && other.isEmpty()) {
25955 return 0
25956 }
25957 if (this.isEmpty()) {
25958 return -1
25959 }
25960 if (other.isEmpty()) {
25961 return 1
25962 }
25963 return this.compareToSameClass(o)
25964 } else if (arguments.length === 2) {
25965 var other$1 = arguments[0];
25966 var comp = arguments[1];
25967 if (this.getSortIndex() !== other$1.getSortIndex()) {
25968 return this.getSortIndex() - other$1.getSortIndex()
25969 }
25970 if (this.isEmpty() && other$1.isEmpty()) {
25971 return 0
25972 }
25973 if (this.isEmpty()) {
25974 return -1
25975 }
25976 if (other$1.isEmpty()) {
25977 return 1
25978 }
25979 return this.compareToSameClass(other$1, comp)
25980 }
25981};
25982Geometry.prototype.getUserData = function getUserData () {
25983 return this._userData
25984};
25985Geometry.prototype.getSRID = function getSRID () {
25986 return this._SRID
25987};
25988Geometry.prototype.getEnvelope = function getEnvelope () {
25989 return this.getFactory().toGeometry(this.getEnvelopeInternal())
25990};
25991Geometry.prototype.checkNotGeometryCollection = function checkNotGeometryCollection (g) {
25992 if (g.getSortIndex() === Geometry.SORTINDEX_GEOMETRYCOLLECTION) {
25993 throw new IllegalArgumentException('This method does not support GeometryCollection arguments')
25994 }
25995};
25996Geometry.prototype.equal = function equal (a, b, tolerance) {
25997 if (tolerance === 0) {
25998 return a.equals(b)
25999 }
26000 return a.distance(b) <= tolerance
26001};
26002Geometry.prototype.norm = function norm () {
26003 var copy = this.copy();
26004 copy.normalize();
26005 return copy
26006};
26007Geometry.prototype.getPrecisionModel = function getPrecisionModel () {
26008 return this._factory.getPrecisionModel()
26009};
26010Geometry.prototype.getEnvelopeInternal = function getEnvelopeInternal () {
26011 if (this._envelope === null) {
26012 this._envelope = this.computeEnvelopeInternal();
26013 }
26014 return new Envelope(this._envelope)
26015};
26016Geometry.prototype.setSRID = function setSRID (SRID) {
26017 this._SRID = SRID;
26018};
26019Geometry.prototype.setUserData = function setUserData (userData) {
26020 this._userData = userData;
26021};
26022Geometry.prototype.compare = function compare (a, b) {
26023 var i = a.iterator();
26024 var j = b.iterator();
26025 while (i.hasNext() && j.hasNext()) {
26026 var aElement = i.next();
26027 var bElement = j.next();
26028 var comparison = aElement.compareTo(bElement);
26029 if (comparison !== 0) {
26030 return comparison
26031 }
26032 }
26033 if (i.hasNext()) {
26034 return 1
26035 }
26036 if (j.hasNext()) {
26037 return -1
26038 }
26039 return 0
26040};
26041Geometry.prototype.hashCode = function hashCode () {
26042 return this.getEnvelopeInternal().hashCode()
26043};
26044Geometry.prototype.isGeometryCollectionOrDerived = function isGeometryCollectionOrDerived () {
26045 if (this.getSortIndex() === Geometry.SORTINDEX_GEOMETRYCOLLECTION || this.getSortIndex() === Geometry.SORTINDEX_MULTIPOINT || this.getSortIndex() === Geometry.SORTINDEX_MULTILINESTRING || this.getSortIndex() === Geometry.SORTINDEX_MULTIPOLYGON) {
26046 return true
26047 }
26048 return false
26049};
26050Geometry.prototype.interfaces_ = function interfaces_ () {
26051 return [Clonable, Comparable, Serializable]
26052};
26053Geometry.prototype.getClass = function getClass () {
26054 return Geometry
26055};
26056Geometry.hasNonEmptyElements = function hasNonEmptyElements (geometries) {
26057 for (var i = 0; i < geometries.length; i++) {
26058 if (!geometries[i].isEmpty()) {
26059 return true
26060 }
26061 }
26062 return false
26063};
26064Geometry.hasNullElements = function hasNullElements (array) {
26065 for (var i = 0; i < array.length; i++) {
26066 if (array[i] === null) {
26067 return true
26068 }
26069 }
26070 return false
26071};
26072staticAccessors$11.serialVersionUID.get = function () { return 8763622679187376702 };
26073staticAccessors$11.SORTINDEX_POINT.get = function () { return 0 };
26074staticAccessors$11.SORTINDEX_MULTIPOINT.get = function () { return 1 };
26075staticAccessors$11.SORTINDEX_LINESTRING.get = function () { return 2 };
26076staticAccessors$11.SORTINDEX_LINEARRING.get = function () { return 3 };
26077staticAccessors$11.SORTINDEX_MULTILINESTRING.get = function () { return 4 };
26078staticAccessors$11.SORTINDEX_POLYGON.get = function () { return 5 };
26079staticAccessors$11.SORTINDEX_MULTIPOLYGON.get = function () { return 6 };
26080staticAccessors$11.SORTINDEX_GEOMETRYCOLLECTION.get = function () { return 7 };
26081staticAccessors$11.geometryChangedFilter.get = function () { return geometryChangedFilter };
26082
26083Object.defineProperties( Geometry, staticAccessors$11 );
26084
26085var geometryChangedFilter = function geometryChangedFilter () {};
26086
26087geometryChangedFilter.interfaces_ = function interfaces_ () {
26088 return [GeometryComponentFilter]
26089};
26090geometryChangedFilter.filter = function filter (geom) {
26091 geom.geometryChangedAction();
26092};
26093
26094var CoordinateFilter = function CoordinateFilter () {};
26095
26096CoordinateFilter.prototype.filter = function filter (coord) {};
26097CoordinateFilter.prototype.interfaces_ = function interfaces_ () {
26098 return []
26099};
26100CoordinateFilter.prototype.getClass = function getClass () {
26101 return CoordinateFilter
26102};
26103
26104var BoundaryNodeRule = function BoundaryNodeRule () {};
26105
26106var staticAccessors$12 = { Mod2BoundaryNodeRule: { configurable: true },EndPointBoundaryNodeRule: { configurable: true },MultiValentEndPointBoundaryNodeRule: { configurable: true },MonoValentEndPointBoundaryNodeRule: { configurable: true },MOD2_BOUNDARY_RULE: { configurable: true },ENDPOINT_BOUNDARY_RULE: { configurable: true },MULTIVALENT_ENDPOINT_BOUNDARY_RULE: { configurable: true },MONOVALENT_ENDPOINT_BOUNDARY_RULE: { configurable: true },OGC_SFS_BOUNDARY_RULE: { configurable: true } };
26107
26108BoundaryNodeRule.prototype.isInBoundary = function isInBoundary (boundaryCount) {};
26109BoundaryNodeRule.prototype.interfaces_ = function interfaces_ () {
26110 return []
26111};
26112BoundaryNodeRule.prototype.getClass = function getClass () {
26113 return BoundaryNodeRule
26114};
26115staticAccessors$12.Mod2BoundaryNodeRule.get = function () { return Mod2BoundaryNodeRule };
26116staticAccessors$12.EndPointBoundaryNodeRule.get = function () { return EndPointBoundaryNodeRule };
26117staticAccessors$12.MultiValentEndPointBoundaryNodeRule.get = function () { return MultiValentEndPointBoundaryNodeRule };
26118staticAccessors$12.MonoValentEndPointBoundaryNodeRule.get = function () { return MonoValentEndPointBoundaryNodeRule };
26119staticAccessors$12.MOD2_BOUNDARY_RULE.get = function () { return new Mod2BoundaryNodeRule() };
26120staticAccessors$12.ENDPOINT_BOUNDARY_RULE.get = function () { return new EndPointBoundaryNodeRule() };
26121staticAccessors$12.MULTIVALENT_ENDPOINT_BOUNDARY_RULE.get = function () { return new MultiValentEndPointBoundaryNodeRule() };
26122staticAccessors$12.MONOVALENT_ENDPOINT_BOUNDARY_RULE.get = function () { return new MonoValentEndPointBoundaryNodeRule() };
26123staticAccessors$12.OGC_SFS_BOUNDARY_RULE.get = function () { return BoundaryNodeRule.MOD2_BOUNDARY_RULE };
26124
26125Object.defineProperties( BoundaryNodeRule, staticAccessors$12 );
26126
26127var Mod2BoundaryNodeRule = function Mod2BoundaryNodeRule () {};
26128
26129Mod2BoundaryNodeRule.prototype.isInBoundary = function isInBoundary (boundaryCount) {
26130 return boundaryCount % 2 === 1
26131};
26132Mod2BoundaryNodeRule.prototype.interfaces_ = function interfaces_ () {
26133 return [BoundaryNodeRule]
26134};
26135Mod2BoundaryNodeRule.prototype.getClass = function getClass () {
26136 return Mod2BoundaryNodeRule
26137};
26138
26139var EndPointBoundaryNodeRule = function EndPointBoundaryNodeRule () {};
26140
26141EndPointBoundaryNodeRule.prototype.isInBoundary = function isInBoundary (boundaryCount) {
26142 return boundaryCount > 0
26143};
26144EndPointBoundaryNodeRule.prototype.interfaces_ = function interfaces_ () {
26145 return [BoundaryNodeRule]
26146};
26147EndPointBoundaryNodeRule.prototype.getClass = function getClass () {
26148 return EndPointBoundaryNodeRule
26149};
26150
26151var MultiValentEndPointBoundaryNodeRule = function MultiValentEndPointBoundaryNodeRule () {};
26152
26153MultiValentEndPointBoundaryNodeRule.prototype.isInBoundary = function isInBoundary (boundaryCount) {
26154 return boundaryCount > 1
26155};
26156MultiValentEndPointBoundaryNodeRule.prototype.interfaces_ = function interfaces_ () {
26157 return [BoundaryNodeRule]
26158};
26159MultiValentEndPointBoundaryNodeRule.prototype.getClass = function getClass () {
26160 return MultiValentEndPointBoundaryNodeRule
26161};
26162
26163var MonoValentEndPointBoundaryNodeRule = function MonoValentEndPointBoundaryNodeRule () {};
26164
26165MonoValentEndPointBoundaryNodeRule.prototype.isInBoundary = function isInBoundary (boundaryCount) {
26166 return boundaryCount === 1
26167};
26168MonoValentEndPointBoundaryNodeRule.prototype.interfaces_ = function interfaces_ () {
26169 return [BoundaryNodeRule]
26170};
26171MonoValentEndPointBoundaryNodeRule.prototype.getClass = function getClass () {
26172 return MonoValentEndPointBoundaryNodeRule
26173};
26174
26175// import Iterator from './Iterator'
26176
26177/**
26178 * @see http://download.oracle.com/javase/6/docs/api/java/util/Collection.html
26179 *
26180 * @constructor
26181 * @private
26182 */
26183var Collection = function Collection () {};
26184
26185Collection.prototype.add = function add () {};
26186
26187/**
26188 * Appends all of the elements in the specified collection to the end of this
26189 * list, in the order that they are returned by the specified collection's
26190 * iterator (optional operation).
26191 * @param {javascript.util.Collection} c
26192 * @return {boolean}
26193 */
26194Collection.prototype.addAll = function addAll () {};
26195
26196/**
26197 * Returns true if this collection contains no elements.
26198 * @return {boolean}
26199 */
26200Collection.prototype.isEmpty = function isEmpty () {};
26201
26202/**
26203 * Returns an iterator over the elements in this collection.
26204 * @return {javascript.util.Iterator}
26205 */
26206Collection.prototype.iterator = function iterator () {};
26207
26208/**
26209 * Returns an iterator over the elements in this collection.
26210 * @return {number}
26211 */
26212Collection.prototype.size = function size () {};
26213
26214/**
26215 * Returns an array containing all of the elements in this collection.
26216 * @return {Array}
26217 */
26218Collection.prototype.toArray = function toArray () {};
26219
26220/**
26221 * Removes a single instance of the specified element from this collection if it
26222 * is present. (optional)
26223 * @param {Object} e
26224 * @return {boolean}
26225 */
26226Collection.prototype.remove = function remove () {};
26227
26228/**
26229 * @param {string} [message] Optional message
26230 * @extends {Error}
26231 * @constructor
26232 * @private
26233 */
26234var IndexOutOfBoundsException = (function (Error) {
26235 function IndexOutOfBoundsException (message) {
26236 Error.call(this);
26237 this.message = message || '';
26238 }
26239
26240 if ( Error ) IndexOutOfBoundsException.__proto__ = Error;
26241 IndexOutOfBoundsException.prototype = Object.create( Error && Error.prototype );
26242 IndexOutOfBoundsException.prototype.constructor = IndexOutOfBoundsException;
26243
26244 var staticAccessors = { name: { configurable: true } };
26245
26246 /**
26247 * @type {string}
26248 */
26249 staticAccessors.name.get = function () { return 'IndexOutOfBoundsException' };
26250
26251 Object.defineProperties( IndexOutOfBoundsException, staticAccessors );
26252
26253 return IndexOutOfBoundsException;
26254}(Error));
26255
26256/**
26257 * @see http://download.oracle.com/javase/6/docs/api/java/util/Iterator.html
26258 * @constructor
26259 * @private
26260 */
26261var Iterator = function Iterator () {};
26262
26263Iterator.prototype.hasNext = function hasNext () {};
26264
26265/**
26266 * Returns the next element in the iteration.
26267 * @return {Object}
26268 */
26269Iterator.prototype.next = function next () {};
26270
26271/**
26272 * Removes from the underlying collection the last element returned by the
26273 * iterator (optional operation).
26274 */
26275Iterator.prototype.remove = function remove () {};
26276
26277/**
26278 * @see http://download.oracle.com/javase/6/docs/api/java/util/List.html
26279 *
26280 * @extends {javascript.util.Collection}
26281 * @constructor
26282 * @private
26283 */
26284var List = (function (Collection$$1) {
26285 function List () {
26286 Collection$$1.apply(this, arguments);
26287 }
26288
26289 if ( Collection$$1 ) List.__proto__ = Collection$$1;
26290 List.prototype = Object.create( Collection$$1 && Collection$$1.prototype );
26291 List.prototype.constructor = List;
26292
26293 List.prototype.get = function get () { };
26294
26295 /**
26296 * Replaces the element at the specified position in this list with the
26297 * specified element (optional operation).
26298 * @param {number} index
26299 * @param {Object} e
26300 * @return {Object}
26301 */
26302 List.prototype.set = function set () { };
26303
26304 /**
26305 * Returns true if this collection contains no elements.
26306 * @return {boolean}
26307 */
26308 List.prototype.isEmpty = function isEmpty () { };
26309
26310 return List;
26311}(Collection));
26312
26313/**
26314 * @param {string=} message Optional message
26315 * @extends {Error}
26316 * @constructor
26317 * @private
26318 */
26319function NoSuchElementException (message) {
26320 this.message = message || '';
26321}
26322NoSuchElementException.prototype = new Error();
26323
26324/**
26325 * @type {string}
26326 */
26327NoSuchElementException.prototype.name = 'NoSuchElementException';
26328
26329// import OperationNotSupported from './OperationNotSupported'
26330
26331/**
26332 * @see http://download.oracle.com/javase/6/docs/api/java/util/ArrayList.html
26333 *
26334 * @extends List
26335 * @private
26336 */
26337var ArrayList = (function (List$$1) {
26338 function ArrayList () {
26339 List$$1.call(this);
26340 this.array_ = [];
26341
26342 if (arguments[0] instanceof Collection) {
26343 this.addAll(arguments[0]);
26344 }
26345 }
26346
26347 if ( List$$1 ) ArrayList.__proto__ = List$$1;
26348 ArrayList.prototype = Object.create( List$$1 && List$$1.prototype );
26349 ArrayList.prototype.constructor = ArrayList;
26350
26351 ArrayList.prototype.ensureCapacity = function ensureCapacity () {};
26352 ArrayList.prototype.interfaces_ = function interfaces_ () { return [List$$1, Collection] };
26353
26354 /**
26355 * @override
26356 */
26357 ArrayList.prototype.add = function add (e) {
26358 if (arguments.length === 1) {
26359 this.array_.push(e);
26360 } else {
26361 this.array_.splice(arguments[0], arguments[1]);
26362 }
26363 return true
26364 };
26365
26366 ArrayList.prototype.clear = function clear () {
26367 this.array_ = [];
26368 };
26369
26370 /**
26371 * @override
26372 */
26373 ArrayList.prototype.addAll = function addAll (c) {
26374 var this$1 = this;
26375
26376 for (var i = c.iterator(); i.hasNext();) {
26377 this$1.add(i.next());
26378 }
26379 return true
26380 };
26381
26382 /**
26383 * @override
26384 */
26385 ArrayList.prototype.set = function set (index, element) {
26386 var oldElement = this.array_[index];
26387 this.array_[index] = element;
26388 return oldElement
26389 };
26390
26391 /**
26392 * @override
26393 */
26394 ArrayList.prototype.iterator = function iterator () {
26395 return new Iterator_(this)
26396 };
26397
26398 /**
26399 * @override
26400 */
26401 ArrayList.prototype.get = function get (index) {
26402 if (index < 0 || index >= this.size()) {
26403 throw new IndexOutOfBoundsException()
26404 }
26405
26406 return this.array_[index]
26407 };
26408
26409 /**
26410 * @override
26411 */
26412 ArrayList.prototype.isEmpty = function isEmpty () {
26413 return this.array_.length === 0
26414 };
26415
26416 /**
26417 * @override
26418 */
26419 ArrayList.prototype.size = function size () {
26420 return this.array_.length
26421 };
26422
26423 /**
26424 * @override
26425 */
26426 ArrayList.prototype.toArray = function toArray () {
26427 var this$1 = this;
26428
26429 var array = [];
26430
26431 for (var i = 0, len = this.array_.length; i < len; i++) {
26432 array.push(this$1.array_[i]);
26433 }
26434
26435 return array
26436 };
26437
26438 /**
26439 * @override
26440 */
26441 ArrayList.prototype.remove = function remove (o) {
26442 var this$1 = this;
26443
26444 var found = false;
26445
26446 for (var i = 0, len = this.array_.length; i < len; i++) {
26447 if (this$1.array_[i] === o) {
26448 this$1.array_.splice(i, 1);
26449 found = true;
26450 break
26451 }
26452 }
26453
26454 return found
26455 };
26456
26457 return ArrayList;
26458}(List));
26459
26460/**
26461 * @extends {Iterator}
26462 * @param {ArrayList} arrayList
26463 * @constructor
26464 * @private
26465 */
26466var Iterator_ = (function (Iterator$$1) {
26467 function Iterator_ (arrayList) {
26468 Iterator$$1.call(this);
26469 /**
26470 * @type {ArrayList}
26471 * @private
26472 */
26473 this.arrayList_ = arrayList;
26474 /**
26475 * @type {number}
26476 * @private
26477 */
26478 this.position_ = 0;
26479 }
26480
26481 if ( Iterator$$1 ) Iterator_.__proto__ = Iterator$$1;
26482 Iterator_.prototype = Object.create( Iterator$$1 && Iterator$$1.prototype );
26483 Iterator_.prototype.constructor = Iterator_;
26484
26485 /**
26486 * @override
26487 */
26488 Iterator_.prototype.next = function next () {
26489 if (this.position_ === this.arrayList_.size()) {
26490 throw new NoSuchElementException()
26491 }
26492 return this.arrayList_.get(this.position_++)
26493 };
26494
26495 /**
26496 * @override
26497 */
26498 Iterator_.prototype.hasNext = function hasNext () {
26499 if (this.position_ < this.arrayList_.size()) {
26500 return true
26501 } else {
26502 return false
26503 }
26504 };
26505
26506 /**
26507 * TODO: should be in ListIterator
26508 * @override
26509 */
26510 Iterator_.prototype.set = function set (element) {
26511 return this.arrayList_.set(this.position_ - 1, element)
26512 };
26513
26514 /**
26515 * @override
26516 */
26517 Iterator_.prototype.remove = function remove () {
26518 this.arrayList_.remove(this.arrayList_.get(this.position_));
26519 };
26520
26521 return Iterator_;
26522}(Iterator));
26523
26524var CoordinateList = (function (ArrayList$$1) {
26525 function CoordinateList () {
26526 ArrayList$$1.call(this);
26527 if (arguments.length === 0) {
26528 } else if (arguments.length === 1) {
26529 var coord = arguments[0];
26530 this.ensureCapacity(coord.length);
26531 this.add(coord, true);
26532 } else if (arguments.length === 2) {
26533 var coord$1 = arguments[0];
26534 var allowRepeated = arguments[1];
26535 this.ensureCapacity(coord$1.length);
26536 this.add(coord$1, allowRepeated);
26537 }
26538 }
26539
26540 if ( ArrayList$$1 ) CoordinateList.__proto__ = ArrayList$$1;
26541 CoordinateList.prototype = Object.create( ArrayList$$1 && ArrayList$$1.prototype );
26542 CoordinateList.prototype.constructor = CoordinateList;
26543
26544 var staticAccessors = { coordArrayType: { configurable: true } };
26545 staticAccessors.coordArrayType.get = function () { return new Array(0).fill(null) };
26546 CoordinateList.prototype.getCoordinate = function getCoordinate (i) {
26547 return this.get(i)
26548 };
26549 CoordinateList.prototype.addAll = function addAll () {
26550 var this$1 = this;
26551
26552 if (arguments.length === 2) {
26553 var coll = arguments[0];
26554 var allowRepeated = arguments[1];
26555 var isChanged = false;
26556 for (var i = coll.iterator(); i.hasNext();) {
26557 this$1.add(i.next(), allowRepeated);
26558 isChanged = true;
26559 }
26560 return isChanged
26561 } else { return ArrayList$$1.prototype.addAll.apply(this, arguments) }
26562 };
26563 CoordinateList.prototype.clone = function clone () {
26564 var this$1 = this;
26565
26566 var clone = ArrayList$$1.prototype.clone.call(this);
26567 for (var i = 0; i < this.size(); i++) {
26568 clone.add(i, this$1.get(i).copy());
26569 }
26570 return clone
26571 };
26572 CoordinateList.prototype.toCoordinateArray = function toCoordinateArray () {
26573 return this.toArray(CoordinateList.coordArrayType)
26574 };
26575 CoordinateList.prototype.add = function add () {
26576 var this$1 = this;
26577
26578 if (arguments.length === 1) {
26579 var coord = arguments[0];
26580 ArrayList$$1.prototype.add.call(this, coord);
26581 } else if (arguments.length === 2) {
26582 if (arguments[0] instanceof Array && typeof arguments[1] === 'boolean') {
26583 var coord$1 = arguments[0];
26584 var allowRepeated = arguments[1];
26585 this.add(coord$1, allowRepeated, true);
26586 return true
26587 } else if (arguments[0] instanceof Coordinate && typeof arguments[1] === 'boolean') {
26588 var coord$2 = arguments[0];
26589 var allowRepeated$1 = arguments[1];
26590 if (!allowRepeated$1) {
26591 if (this.size() >= 1) {
26592 var last = this.get(this.size() - 1);
26593 if (last.equals2D(coord$2)) { return null }
26594 }
26595 }
26596 ArrayList$$1.prototype.add.call(this, coord$2);
26597 } else if (arguments[0] instanceof Object && typeof arguments[1] === 'boolean') {
26598 var obj = arguments[0];
26599 var allowRepeated$2 = arguments[1];
26600 this.add(obj, allowRepeated$2);
26601 return true
26602 }
26603 } else if (arguments.length === 3) {
26604 if (typeof arguments[2] === 'boolean' && (arguments[0] instanceof Array && typeof arguments[1] === 'boolean')) {
26605 var coord$3 = arguments[0];
26606 var allowRepeated$3 = arguments[1];
26607 var direction = arguments[2];
26608 if (direction) {
26609 for (var i$1 = 0; i$1 < coord$3.length; i$1++) {
26610 this$1.add(coord$3[i$1], allowRepeated$3);
26611 }
26612 } else {
26613 for (var i$2 = coord$3.length - 1; i$2 >= 0; i$2--) {
26614 this$1.add(coord$3[i$2], allowRepeated$3);
26615 }
26616 }
26617 return true
26618 } else if (typeof arguments[2] === 'boolean' && (Number.isInteger(arguments[0]) && arguments[1] instanceof Coordinate)) {
26619 var i$3 = arguments[0];
26620 var coord$4 = arguments[1];
26621 var allowRepeated$4 = arguments[2];
26622 if (!allowRepeated$4) {
26623 var size = this.size();
26624 if (size > 0) {
26625 if (i$3 > 0) {
26626 var prev = this.get(i$3 - 1);
26627 if (prev.equals2D(coord$4)) { return null }
26628 }
26629 if (i$3 < size) {
26630 var next = this.get(i$3);
26631 if (next.equals2D(coord$4)) { return null }
26632 }
26633 }
26634 }
26635 ArrayList$$1.prototype.add.call(this, i$3, coord$4);
26636 }
26637 } else if (arguments.length === 4) {
26638 var coord$5 = arguments[0];
26639 var allowRepeated$5 = arguments[1];
26640 var start = arguments[2];
26641 var end = arguments[3];
26642 var inc = 1;
26643 if (start > end) { inc = -1; }
26644 for (var i = start; i !== end; i += inc) {
26645 this$1.add(coord$5[i], allowRepeated$5);
26646 }
26647 return true
26648 }
26649 };
26650 CoordinateList.prototype.closeRing = function closeRing () {
26651 if (this.size() > 0) { this.add(new Coordinate(this.get(0)), false); }
26652 };
26653 CoordinateList.prototype.interfaces_ = function interfaces_ () {
26654 return []
26655 };
26656 CoordinateList.prototype.getClass = function getClass () {
26657 return CoordinateList
26658 };
26659
26660 Object.defineProperties( CoordinateList, staticAccessors );
26661
26662 return CoordinateList;
26663}(ArrayList));
26664
26665var CoordinateArrays = function CoordinateArrays () {};
26666
26667var staticAccessors$13 = { ForwardComparator: { configurable: true },BidirectionalComparator: { configurable: true },coordArrayType: { configurable: true } };
26668
26669staticAccessors$13.ForwardComparator.get = function () { return ForwardComparator };
26670staticAccessors$13.BidirectionalComparator.get = function () { return BidirectionalComparator };
26671staticAccessors$13.coordArrayType.get = function () { return new Array(0).fill(null) };
26672
26673CoordinateArrays.prototype.interfaces_ = function interfaces_ () {
26674 return []
26675};
26676CoordinateArrays.prototype.getClass = function getClass () {
26677 return CoordinateArrays
26678};
26679CoordinateArrays.isRing = function isRing (pts) {
26680 if (pts.length < 4) { return false }
26681 if (!pts[0].equals2D(pts[pts.length - 1])) { return false }
26682 return true
26683};
26684CoordinateArrays.ptNotInList = function ptNotInList (testPts, pts) {
26685 for (var i = 0; i < testPts.length; i++) {
26686 var testPt = testPts[i];
26687 if (CoordinateArrays.indexOf(testPt, pts) < 0) { return testPt }
26688 }
26689 return null
26690};
26691CoordinateArrays.scroll = function scroll (coordinates, firstCoordinate) {
26692 var i = CoordinateArrays.indexOf(firstCoordinate, coordinates);
26693 if (i < 0) { return null }
26694 var newCoordinates = new Array(coordinates.length).fill(null);
26695 System.arraycopy(coordinates, i, newCoordinates, 0, coordinates.length - i);
26696 System.arraycopy(coordinates, 0, newCoordinates, coordinates.length - i, i);
26697 System.arraycopy(newCoordinates, 0, coordinates, 0, coordinates.length);
26698};
26699CoordinateArrays.equals = function equals () {
26700 if (arguments.length === 2) {
26701 var coord1 = arguments[0];
26702 var coord2 = arguments[1];
26703 if (coord1 === coord2) { return true }
26704 if (coord1 === null || coord2 === null) { return false }
26705 if (coord1.length !== coord2.length) { return false }
26706 for (var i = 0; i < coord1.length; i++) {
26707 if (!coord1[i].equals(coord2[i])) { return false }
26708 }
26709 return true
26710 } else if (arguments.length === 3) {
26711 var coord1$1 = arguments[0];
26712 var coord2$1 = arguments[1];
26713 var coordinateComparator = arguments[2];
26714 if (coord1$1 === coord2$1) { return true }
26715 if (coord1$1 === null || coord2$1 === null) { return false }
26716 if (coord1$1.length !== coord2$1.length) { return false }
26717 for (var i$1 = 0; i$1 < coord1$1.length; i$1++) {
26718 if (coordinateComparator.compare(coord1$1[i$1], coord2$1[i$1]) !== 0) { return false }
26719 }
26720 return true
26721 }
26722};
26723CoordinateArrays.intersection = function intersection (coordinates, env) {
26724 var coordList = new CoordinateList();
26725 for (var i = 0; i < coordinates.length; i++) {
26726 if (env.intersects(coordinates[i])) { coordList.add(coordinates[i], true); }
26727 }
26728 return coordList.toCoordinateArray()
26729};
26730CoordinateArrays.hasRepeatedPoints = function hasRepeatedPoints (coord) {
26731 for (var i = 1; i < coord.length; i++) {
26732 if (coord[i - 1].equals(coord[i])) {
26733 return true
26734 }
26735 }
26736 return false
26737};
26738CoordinateArrays.removeRepeatedPoints = function removeRepeatedPoints (coord) {
26739 if (!CoordinateArrays.hasRepeatedPoints(coord)) { return coord }
26740 var coordList = new CoordinateList(coord, false);
26741 return coordList.toCoordinateArray()
26742};
26743CoordinateArrays.reverse = function reverse (coord) {
26744 var last = coord.length - 1;
26745 var mid = Math.trunc(last / 2);
26746 for (var i = 0; i <= mid; i++) {
26747 var tmp = coord[i];
26748 coord[i] = coord[last - i];
26749 coord[last - i] = tmp;
26750 }
26751};
26752CoordinateArrays.removeNull = function removeNull (coord) {
26753 var nonNull = 0;
26754 for (var i = 0; i < coord.length; i++) {
26755 if (coord[i] !== null) { nonNull++; }
26756 }
26757 var newCoord = new Array(nonNull).fill(null);
26758 if (nonNull === 0) { return newCoord }
26759 var j = 0;
26760 for (var i$1 = 0; i$1 < coord.length; i$1++) {
26761 if (coord[i$1] !== null) { newCoord[j++] = coord[i$1]; }
26762 }
26763 return newCoord
26764};
26765CoordinateArrays.copyDeep = function copyDeep () {
26766 if (arguments.length === 1) {
26767 var coordinates = arguments[0];
26768 var copy = new Array(coordinates.length).fill(null);
26769 for (var i = 0; i < coordinates.length; i++) {
26770 copy[i] = new Coordinate(coordinates[i]);
26771 }
26772 return copy
26773 } else if (arguments.length === 5) {
26774 var src = arguments[0];
26775 var srcStart = arguments[1];
26776 var dest = arguments[2];
26777 var destStart = arguments[3];
26778 var length = arguments[4];
26779 for (var i$1 = 0; i$1 < length; i$1++) {
26780 dest[destStart + i$1] = new Coordinate(src[srcStart + i$1]);
26781 }
26782 }
26783};
26784CoordinateArrays.isEqualReversed = function isEqualReversed (pts1, pts2) {
26785 for (var i = 0; i < pts1.length; i++) {
26786 var p1 = pts1[i];
26787 var p2 = pts2[pts1.length - i - 1];
26788 if (p1.compareTo(p2) !== 0) { return false }
26789 }
26790 return true
26791};
26792CoordinateArrays.envelope = function envelope (coordinates) {
26793 var env = new Envelope();
26794 for (var i = 0; i < coordinates.length; i++) {
26795 env.expandToInclude(coordinates[i]);
26796 }
26797 return env
26798};
26799CoordinateArrays.toCoordinateArray = function toCoordinateArray (coordList) {
26800 return coordList.toArray(CoordinateArrays.coordArrayType)
26801};
26802CoordinateArrays.atLeastNCoordinatesOrNothing = function atLeastNCoordinatesOrNothing (n, c) {
26803 return c.length >= n ? c : []
26804};
26805CoordinateArrays.indexOf = function indexOf (coordinate, coordinates) {
26806 for (var i = 0; i < coordinates.length; i++) {
26807 if (coordinate.equals(coordinates[i])) {
26808 return i
26809 }
26810 }
26811 return -1
26812};
26813CoordinateArrays.increasingDirection = function increasingDirection (pts) {
26814 for (var i = 0; i < Math.trunc(pts.length / 2); i++) {
26815 var j = pts.length - 1 - i;
26816 var comp = pts[i].compareTo(pts[j]);
26817 if (comp !== 0) { return comp }
26818 }
26819 return 1
26820};
26821CoordinateArrays.compare = function compare (pts1, pts2) {
26822 var i = 0;
26823 while (i < pts1.length && i < pts2.length) {
26824 var compare = pts1[i].compareTo(pts2[i]);
26825 if (compare !== 0) { return compare }
26826 i++;
26827 }
26828 if (i < pts2.length) { return -1 }
26829 if (i < pts1.length) { return 1 }
26830 return 0
26831};
26832CoordinateArrays.minCoordinate = function minCoordinate (coordinates) {
26833 var minCoord = null;
26834 for (var i = 0; i < coordinates.length; i++) {
26835 if (minCoord === null || minCoord.compareTo(coordinates[i]) > 0) {
26836 minCoord = coordinates[i];
26837 }
26838 }
26839 return minCoord
26840};
26841CoordinateArrays.extract = function extract (pts, start, end) {
26842 start = MathUtil.clamp(start, 0, pts.length);
26843 end = MathUtil.clamp(end, -1, pts.length);
26844 var npts = end - start + 1;
26845 if (end < 0) { npts = 0; }
26846 if (start >= pts.length) { npts = 0; }
26847 if (end < start) { npts = 0; }
26848 var extractPts = new Array(npts).fill(null);
26849 if (npts === 0) { return extractPts }
26850 var iPts = 0;
26851 for (var i = start; i <= end; i++) {
26852 extractPts[iPts++] = pts[i];
26853 }
26854 return extractPts
26855};
26856
26857Object.defineProperties( CoordinateArrays, staticAccessors$13 );
26858
26859var ForwardComparator = function ForwardComparator () {};
26860
26861ForwardComparator.prototype.compare = function compare (o1, o2) {
26862 var pts1 = o1;
26863 var pts2 = o2;
26864 return CoordinateArrays.compare(pts1, pts2)
26865};
26866ForwardComparator.prototype.interfaces_ = function interfaces_ () {
26867 return [Comparator]
26868};
26869ForwardComparator.prototype.getClass = function getClass () {
26870 return ForwardComparator
26871};
26872
26873var BidirectionalComparator = function BidirectionalComparator () {};
26874
26875BidirectionalComparator.prototype.compare = function compare (o1, o2) {
26876 var pts1 = o1;
26877 var pts2 = o2;
26878 if (pts1.length < pts2.length) { return -1 }
26879 if (pts1.length > pts2.length) { return 1 }
26880 if (pts1.length === 0) { return 0 }
26881 var forwardComp = CoordinateArrays.compare(pts1, pts2);
26882 var isEqualRev = CoordinateArrays.isEqualReversed(pts1, pts2);
26883 if (isEqualRev) { return 0 }
26884 return forwardComp
26885};
26886BidirectionalComparator.prototype.OLDcompare = function OLDcompare (o1, o2) {
26887 var pts1 = o1;
26888 var pts2 = o2;
26889 if (pts1.length < pts2.length) { return -1 }
26890 if (pts1.length > pts2.length) { return 1 }
26891 if (pts1.length === 0) { return 0 }
26892 var dir1 = CoordinateArrays.increasingDirection(pts1);
26893 var dir2 = CoordinateArrays.increasingDirection(pts2);
26894 var i1 = dir1 > 0 ? 0 : pts1.length - 1;
26895 var i2 = dir2 > 0 ? 0 : pts1.length - 1;
26896 for (var i = 0; i < pts1.length; i++) {
26897 var comparePt = pts1[i1].compareTo(pts2[i2]);
26898 if (comparePt !== 0) { return comparePt }
26899 i1 += dir1;
26900 i2 += dir2;
26901 }
26902 return 0
26903};
26904BidirectionalComparator.prototype.interfaces_ = function interfaces_ () {
26905 return [Comparator]
26906};
26907BidirectionalComparator.prototype.getClass = function getClass () {
26908 return BidirectionalComparator
26909};
26910
26911/**
26912 * @see http://download.oracle.com/javase/6/docs/api/java/util/Map.html
26913 *
26914 * @constructor
26915 * @private
26916 */
26917var Map$1 = function Map () {};
26918
26919Map$1.prototype.get = function get () {};
26920/**
26921 * Associates the specified value with the specified key in this map (optional
26922 * operation).
26923 * @param {Object} key
26924 * @param {Object} value
26925 * @return {Object}
26926 */
26927Map$1.prototype.put = function put () {};
26928
26929/**
26930 * Returns the number of key-value mappings in this map.
26931 * @return {number}
26932 */
26933Map$1.prototype.size = function size () {};
26934
26935/**
26936 * Returns a Collection view of the values contained in this map.
26937 * @return {javascript.util.Collection}
26938 */
26939Map$1.prototype.values = function values () {};
26940
26941/**
26942 * Returns a {@link Set} view of the mappings contained in this map.
26943 * The set is backed by the map, so changes to the map are
26944 * reflected in the set, and vice-versa.If the map is modified
26945 * while an iteration over the set is in progress (except through
26946 * the iterator's own <tt>remove</tt> operation, or through the
26947 * <tt>setValue</tt> operation on a map entry returned by the
26948 * iterator) the results of the iteration are undefined.The set
26949 * supports element removal, which removes the corresponding
26950 * mapping from the map, via the <tt>Iterator.remove</tt>,
26951 * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
26952 * <tt>clear</tt> operations.It does not support the
26953 * <tt>add</tt> or <tt>addAll</tt> operations.
26954 *
26955 * @return {Set} a set view of the mappings contained in this map
26956 */
26957Map$1.prototype.entrySet = function entrySet () {};
26958
26959/**
26960 * @see http://download.oracle.com/javase/6/docs/api/java/util/SortedMap.html
26961 *
26962 * @extends {Map}
26963 * @constructor
26964 * @private
26965 */
26966var SortedMap = (function (Map) {
26967 function SortedMap () {
26968 Map.apply(this, arguments);
26969 }if ( Map ) SortedMap.__proto__ = Map;
26970 SortedMap.prototype = Object.create( Map && Map.prototype );
26971 SortedMap.prototype.constructor = SortedMap;
26972
26973
26974
26975 return SortedMap;
26976}(Map$1));
26977
26978/**
26979 * @param {string=} message Optional message
26980 * @extends {Error}
26981 * @constructor
26982 * @private
26983 */
26984function OperationNotSupported (message) {
26985 this.message = message || '';
26986}
26987OperationNotSupported.prototype = new Error();
26988
26989/**
26990 * @type {string}
26991 */
26992OperationNotSupported.prototype.name = 'OperationNotSupported';
26993
26994/**
26995 * @see http://download.oracle.com/javase/6/docs/api/java/util/Set.html
26996 *
26997 * @extends {Collection}
26998 * @constructor
26999 * @private
27000 */
27001function Set() {}
27002Set.prototype = new Collection();
27003
27004
27005/**
27006 * Returns true if this set contains the specified element. More formally,
27007 * returns true if and only if this set contains an element e such that (o==null ?
27008 * e==null : o.equals(e)).
27009 * @param {Object} e
27010 * @return {boolean}
27011 */
27012Set.prototype.contains = function() {};
27013
27014/**
27015 * @see http://docs.oracle.com/javase/6/docs/api/java/util/HashSet.html
27016 *
27017 * @extends {javascript.util.Set}
27018 * @constructor
27019 * @private
27020 */
27021var HashSet = (function (Set$$1) {
27022 function HashSet () {
27023 Set$$1.call(this);
27024 this.array_ = [];
27025
27026 if (arguments[0] instanceof Collection) {
27027 this.addAll(arguments[0]);
27028 }
27029 }
27030
27031 if ( Set$$1 ) HashSet.__proto__ = Set$$1;
27032 HashSet.prototype = Object.create( Set$$1 && Set$$1.prototype );
27033 HashSet.prototype.constructor = HashSet;
27034
27035 /**
27036 * @override
27037 */
27038 HashSet.prototype.contains = function contains (o) {
27039 var this$1 = this;
27040
27041 for (var i = 0, len = this.array_.length; i < len; i++) {
27042 var e = this$1.array_[i];
27043 if (e === o) {
27044 return true
27045 }
27046 }
27047 return false
27048 };
27049
27050 /**
27051 * @override
27052 */
27053 HashSet.prototype.add = function add (o) {
27054 if (this.contains(o)) {
27055 return false
27056 }
27057
27058 this.array_.push(o);
27059
27060 return true
27061 };
27062
27063 /**
27064 * @override
27065 */
27066 HashSet.prototype.addAll = function addAll (c) {
27067 var this$1 = this;
27068
27069 for (var i = c.iterator(); i.hasNext();) {
27070 this$1.add(i.next());
27071 }
27072 return true
27073 };
27074
27075 /**
27076 * @override
27077 */
27078 HashSet.prototype.remove = function remove (o) {
27079 // throw new javascript.util.OperationNotSupported()
27080 throw new Error()
27081 };
27082
27083 /**
27084 * @override
27085 */
27086 HashSet.prototype.size = function size () {
27087 return this.array_.length
27088 };
27089
27090 /**
27091 * @override
27092 */
27093 HashSet.prototype.isEmpty = function isEmpty () {
27094 return this.array_.length === 0
27095 };
27096
27097 /**
27098 * @override
27099 */
27100 HashSet.prototype.toArray = function toArray () {
27101 var this$1 = this;
27102
27103 var array = [];
27104
27105 for (var i = 0, len = this.array_.length; i < len; i++) {
27106 array.push(this$1.array_[i]);
27107 }
27108
27109 return array
27110 };
27111
27112 /**
27113 * @override
27114 */
27115 HashSet.prototype.iterator = function iterator () {
27116 return new Iterator_$1(this)
27117 };
27118
27119 return HashSet;
27120}(Set));
27121
27122/**
27123 * @extends {Iterator}
27124 * @param {HashSet} hashSet
27125 * @constructor
27126 * @private
27127 */
27128var Iterator_$1 = (function (Iterator$$1) {
27129 function Iterator_ (hashSet) {
27130 Iterator$$1.call(this);
27131 /**
27132 * @type {HashSet}
27133 * @private
27134 */
27135 this.hashSet_ = hashSet;
27136 /**
27137 * @type {number}
27138 * @private
27139 */
27140 this.position_ = 0;
27141 }
27142
27143 if ( Iterator$$1 ) Iterator_.__proto__ = Iterator$$1;
27144 Iterator_.prototype = Object.create( Iterator$$1 && Iterator$$1.prototype );
27145 Iterator_.prototype.constructor = Iterator_;
27146
27147 /**
27148 * @override
27149 */
27150 Iterator_.prototype.next = function next () {
27151 if (this.position_ === this.hashSet_.size()) {
27152 throw new NoSuchElementException()
27153 }
27154 return this.hashSet_.array_[this.position_++]
27155 };
27156
27157 /**
27158 * @override
27159 */
27160 Iterator_.prototype.hasNext = function hasNext () {
27161 if (this.position_ < this.hashSet_.size()) {
27162 return true
27163 } else {
27164 return false
27165 }
27166 };
27167
27168 /**
27169 * @override
27170 */
27171 Iterator_.prototype.remove = function remove () {
27172 throw new OperationNotSupported()
27173 };
27174
27175 return Iterator_;
27176}(Iterator));
27177
27178var BLACK = 0;
27179var RED = 1;
27180function colorOf (p) { return (p === null ? BLACK : p.color) }
27181function parentOf (p) { return (p === null ? null : p.parent) }
27182function setColor (p, c) { if (p !== null) { p.color = c; } }
27183function leftOf (p) { return (p === null ? null : p.left) }
27184function rightOf (p) { return (p === null ? null : p.right) }
27185
27186/**
27187 * @see http://download.oracle.com/javase/6/docs/api/java/util/TreeMap.html
27188 *
27189 * @extends {SortedMap}
27190 * @constructor
27191 * @private
27192 */
27193function TreeMap () {
27194 /**
27195 * @type {Object}
27196 * @private
27197 */
27198 this.root_ = null;
27199 /**
27200 * @type {number}
27201 * @private
27202 */
27203 this.size_ = 0;
27204}
27205TreeMap.prototype = new SortedMap();
27206
27207/**
27208 * @override
27209 */
27210TreeMap.prototype.get = function (key) {
27211 var p = this.root_;
27212 while (p !== null) {
27213 var cmp = key['compareTo'](p.key);
27214 if (cmp < 0) { p = p.left; }
27215 else if (cmp > 0) { p = p.right; }
27216 else { return p.value }
27217 }
27218 return null
27219};
27220
27221/**
27222 * @override
27223 */
27224TreeMap.prototype.put = function (key, value) {
27225 if (this.root_ === null) {
27226 this.root_ = {
27227 key: key,
27228 value: value,
27229 left: null,
27230 right: null,
27231 parent: null,
27232 color: BLACK,
27233 getValue: function getValue () { return this.value },
27234 getKey: function getKey () { return this.key }
27235 };
27236 this.size_ = 1;
27237 return null
27238 }
27239 var t = this.root_;
27240 var parent;
27241 var cmp;
27242 do {
27243 parent = t;
27244 cmp = key['compareTo'](t.key);
27245 if (cmp < 0) {
27246 t = t.left;
27247 } else if (cmp > 0) {
27248 t = t.right;
27249 } else {
27250 var oldValue = t.value;
27251 t.value = value;
27252 return oldValue
27253 }
27254 } while (t !== null)
27255 var e = {
27256 key: key,
27257 left: null,
27258 right: null,
27259 value: value,
27260 parent: parent,
27261 color: BLACK,
27262 getValue: function getValue () { return this.value },
27263 getKey: function getKey () { return this.key }
27264 };
27265 if (cmp < 0) {
27266 parent.left = e;
27267 } else {
27268 parent.right = e;
27269 }
27270 this.fixAfterInsertion(e);
27271 this.size_++;
27272 return null
27273};
27274
27275/**
27276 * @param {Object} x
27277 */
27278TreeMap.prototype.fixAfterInsertion = function (x) {
27279 var this$1 = this;
27280
27281 x.color = RED;
27282 while (x != null && x !== this.root_ && x.parent.color === RED) {
27283 if (parentOf(x) === leftOf(parentOf(parentOf(x)))) {
27284 var y = rightOf(parentOf(parentOf(x)));
27285 if (colorOf(y) === RED) {
27286 setColor(parentOf(x), BLACK);
27287 setColor(y, BLACK);
27288 setColor(parentOf(parentOf(x)), RED);
27289 x = parentOf(parentOf(x));
27290 } else {
27291 if (x === rightOf(parentOf(x))) {
27292 x = parentOf(x);
27293 this$1.rotateLeft(x);
27294 }
27295 setColor(parentOf(x), BLACK);
27296 setColor(parentOf(parentOf(x)), RED);
27297 this$1.rotateRight(parentOf(parentOf(x)));
27298 }
27299 } else {
27300 var y$1 = leftOf(parentOf(parentOf(x)));
27301 if (colorOf(y$1) === RED) {
27302 setColor(parentOf(x), BLACK);
27303 setColor(y$1, BLACK);
27304 setColor(parentOf(parentOf(x)), RED);
27305 x = parentOf(parentOf(x));
27306 } else {
27307 if (x === leftOf(parentOf(x))) {
27308 x = parentOf(x);
27309 this$1.rotateRight(x);
27310 }
27311 setColor(parentOf(x), BLACK);
27312 setColor(parentOf(parentOf(x)), RED);
27313 this$1.rotateLeft(parentOf(parentOf(x)));
27314 }
27315 }
27316 }
27317 this.root_.color = BLACK;
27318};
27319
27320/**
27321 * @override
27322 */
27323TreeMap.prototype.values = function () {
27324 var arrayList = new ArrayList();
27325 var p = this.getFirstEntry();
27326 if (p !== null) {
27327 arrayList.add(p.value);
27328 while ((p = TreeMap.successor(p)) !== null) {
27329 arrayList.add(p.value);
27330 }
27331 }
27332 return arrayList
27333};
27334
27335/**
27336 * @override
27337 */
27338TreeMap.prototype.entrySet = function () {
27339 var hashSet = new HashSet();
27340 var p = this.getFirstEntry();
27341 if (p !== null) {
27342 hashSet.add(p);
27343 while ((p = TreeMap.successor(p)) !== null) {
27344 hashSet.add(p);
27345 }
27346 }
27347 return hashSet
27348};
27349
27350/**
27351 * @param {Object} p
27352 */
27353TreeMap.prototype.rotateLeft = function (p) {
27354 if (p != null) {
27355 var r = p.right;
27356 p.right = r.left;
27357 if (r.left != null) { r.left.parent = p; }
27358 r.parent = p.parent;
27359 if (p.parent === null) { this.root_ = r; } else if (p.parent.left === p) { p.parent.left = r; } else { p.parent.right = r; }
27360 r.left = p;
27361 p.parent = r;
27362 }
27363};
27364
27365/**
27366 * @param {Object} p
27367 */
27368TreeMap.prototype.rotateRight = function (p) {
27369 if (p != null) {
27370 var l = p.left;
27371 p.left = l.right;
27372 if (l.right != null) { l.right.parent = p; }
27373 l.parent = p.parent;
27374 if (p.parent === null) { this.root_ = l; } else if (p.parent.right === p) { p.parent.right = l; } else { p.parent.left = l; }
27375 l.right = p;
27376 p.parent = l;
27377 }
27378};
27379
27380/**
27381 * @return {Object}
27382 */
27383TreeMap.prototype.getFirstEntry = function () {
27384 var p = this.root_;
27385 if (p != null) {
27386 while (p.left != null) {
27387 p = p.left;
27388 }
27389 }
27390 return p
27391};
27392
27393/**
27394 * @param {Object} t
27395 * @return {Object}
27396 * @private
27397 */
27398TreeMap.successor = function (t) {
27399 if (t === null) { return null } else if (t.right !== null) {
27400 var p = t.right;
27401 while (p.left !== null) {
27402 p = p.left;
27403 }
27404 return p
27405 } else {
27406 var p$1 = t.parent;
27407 var ch = t;
27408 while (p$1 !== null && ch === p$1.right) {
27409 ch = p$1;
27410 p$1 = p$1.parent;
27411 }
27412 return p$1
27413 }
27414};
27415
27416/**
27417 * @override
27418 */
27419TreeMap.prototype.size = function () {
27420 return this.size_
27421};
27422
27423var Lineal = function Lineal () {};
27424
27425Lineal.prototype.interfaces_ = function interfaces_ () {
27426 return []
27427};
27428Lineal.prototype.getClass = function getClass () {
27429 return Lineal
27430};
27431
27432/**
27433 * @see http://download.oracle.com/javase/6/docs/api/java/util/SortedSet.html
27434 *
27435 * @extends {Set}
27436 * @constructor
27437 * @private
27438 */
27439function SortedSet () {}
27440SortedSet.prototype = new Set();
27441
27442// import Iterator from './Iterator'
27443/**
27444 * @see http://download.oracle.com/javase/6/docs/api/java/util/TreeSet.html
27445 *
27446 * @extends {SortedSet}
27447 * @constructor
27448 * @private
27449 */
27450function TreeSet () {
27451 /**
27452 * @type {Array}
27453 * @private
27454 */
27455 this.array_ = [];
27456
27457 if (arguments[0] instanceof Collection) {
27458 this.addAll(arguments[0]);
27459 }
27460}
27461TreeSet.prototype = new SortedSet();
27462
27463/**
27464 * @override
27465 */
27466TreeSet.prototype.contains = function (o) {
27467 var this$1 = this;
27468
27469 for (var i = 0, len = this.array_.length; i < len; i++) {
27470 var e = this$1.array_[i];
27471 if (e['compareTo'](o) === 0) {
27472 return true
27473 }
27474 }
27475 return false
27476};
27477
27478/**
27479 * @override
27480 */
27481TreeSet.prototype.add = function (o) {
27482 var this$1 = this;
27483
27484 if (this.contains(o)) {
27485 return false
27486 }
27487
27488 for (var i = 0, len = this.array_.length; i < len; i++) {
27489 var e = this$1.array_[i];
27490 if (e['compareTo'](o) === 1) {
27491 this$1.array_.splice(i, 0, o);
27492 return true
27493 }
27494 }
27495
27496 this.array_.push(o);
27497
27498 return true
27499};
27500
27501/**
27502 * @override
27503 */
27504TreeSet.prototype.addAll = function (c) {
27505 var this$1 = this;
27506
27507 for (var i = c.iterator(); i.hasNext();) {
27508 this$1.add(i.next());
27509 }
27510 return true
27511};
27512
27513/**
27514 * @override
27515 */
27516TreeSet.prototype.remove = function (e) {
27517 throw new OperationNotSupported()
27518};
27519
27520/**
27521 * @override
27522 */
27523TreeSet.prototype.size = function () {
27524 return this.array_.length
27525};
27526
27527/**
27528 * @override
27529 */
27530TreeSet.prototype.isEmpty = function () {
27531 return this.array_.length === 0
27532};
27533
27534/**
27535 * @override
27536 */
27537TreeSet.prototype.toArray = function () {
27538 var this$1 = this;
27539
27540 var array = [];
27541
27542 for (var i = 0, len = this.array_.length; i < len; i++) {
27543 array.push(this$1.array_[i]);
27544 }
27545
27546 return array
27547};
27548
27549/**
27550 * @override
27551 */
27552TreeSet.prototype.iterator = function () {
27553 return new Iterator_$2(this)
27554};
27555
27556/**
27557 * @extends {javascript.util.Iterator}
27558 * @param {javascript.util.TreeSet} treeSet
27559 * @constructor
27560 * @private
27561 */
27562var Iterator_$2 = function (treeSet) {
27563 /**
27564 * @type {javascript.util.TreeSet}
27565 * @private
27566 */
27567 this.treeSet_ = treeSet;
27568 /**
27569 * @type {number}
27570 * @private
27571 */
27572 this.position_ = 0;
27573};
27574
27575/**
27576 * @override
27577 */
27578Iterator_$2.prototype.next = function () {
27579 if (this.position_ === this.treeSet_.size()) {
27580 throw new NoSuchElementException()
27581 }
27582 return this.treeSet_.array_[this.position_++]
27583};
27584
27585/**
27586 * @override
27587 */
27588Iterator_$2.prototype.hasNext = function () {
27589 if (this.position_ < this.treeSet_.size()) {
27590 return true
27591 } else {
27592 return false
27593 }
27594};
27595
27596/**
27597 * @override
27598 */
27599Iterator_$2.prototype.remove = function () {
27600 throw new OperationNotSupported()
27601};
27602
27603/**
27604 * @see http://download.oracle.com/javase/6/docs/api/java/util/Arrays.html
27605 *
27606 * @constructor
27607 * @private
27608 */
27609var Arrays = function Arrays () {};
27610
27611Arrays.sort = function sort () {
27612 var a = arguments[0];
27613 var i;
27614 var t;
27615 var comparator;
27616 var compare;
27617 if (arguments.length === 1) {
27618 compare = function (a, b) {
27619 return a.compareTo(b)
27620 };
27621 a.sort(compare);
27622 } else if (arguments.length === 2) {
27623 comparator = arguments[1];
27624 compare = function (a, b) {
27625 return comparator['compare'](a, b)
27626 };
27627 a.sort(compare);
27628 } else if (arguments.length === 3) {
27629 t = a.slice(arguments[1], arguments[2]);
27630 t.sort();
27631 var r = a.slice(0, arguments[1]).concat(t, a.slice(arguments[2], a.length));
27632 a.splice(0, a.length);
27633 for (i = 0; i < r.length; i++) {
27634 a.push(r[i]);
27635 }
27636 } else if (arguments.length === 4) {
27637 t = a.slice(arguments[1], arguments[2]);
27638 comparator = arguments[3];
27639 compare = function (a, b) {
27640 return comparator['compare'](a, b)
27641 };
27642 t.sort(compare);
27643 r = a.slice(0, arguments[1]).concat(t, a.slice(arguments[2], a.length));
27644 a.splice(0, a.length);
27645 for (i = 0; i < r.length; i++) {
27646 a.push(r[i]);
27647 }
27648 }
27649};
27650/**
27651 * @param {Array} array
27652 * @return {ArrayList}
27653 */
27654Arrays.asList = function asList (array) {
27655 var arrayList = new ArrayList();
27656 for (var i = 0, len = array.length; i < len; i++) {
27657 arrayList.add(array[i]);
27658 }
27659 return arrayList
27660};
27661
27662var Dimension = function Dimension () {};
27663
27664var staticAccessors$14 = { P: { configurable: true },L: { configurable: true },A: { configurable: true },FALSE: { configurable: true },TRUE: { configurable: true },DONTCARE: { configurable: true },SYM_FALSE: { configurable: true },SYM_TRUE: { configurable: true },SYM_DONTCARE: { configurable: true },SYM_P: { configurable: true },SYM_L: { configurable: true },SYM_A: { configurable: true } };
27665
27666staticAccessors$14.P.get = function () { return 0 };
27667staticAccessors$14.L.get = function () { return 1 };
27668staticAccessors$14.A.get = function () { return 2 };
27669staticAccessors$14.FALSE.get = function () { return -1 };
27670staticAccessors$14.TRUE.get = function () { return -2 };
27671staticAccessors$14.DONTCARE.get = function () { return -3 };
27672staticAccessors$14.SYM_FALSE.get = function () { return 'F' };
27673staticAccessors$14.SYM_TRUE.get = function () { return 'T' };
27674staticAccessors$14.SYM_DONTCARE.get = function () { return '*' };
27675staticAccessors$14.SYM_P.get = function () { return '0' };
27676staticAccessors$14.SYM_L.get = function () { return '1' };
27677staticAccessors$14.SYM_A.get = function () { return '2' };
27678
27679Dimension.prototype.interfaces_ = function interfaces_ () {
27680 return []
27681};
27682Dimension.prototype.getClass = function getClass () {
27683 return Dimension
27684};
27685Dimension.toDimensionSymbol = function toDimensionSymbol (dimensionValue) {
27686 switch (dimensionValue) {
27687 case Dimension.FALSE:
27688 return Dimension.SYM_FALSE
27689 case Dimension.TRUE:
27690 return Dimension.SYM_TRUE
27691 case Dimension.DONTCARE:
27692 return Dimension.SYM_DONTCARE
27693 case Dimension.P:
27694 return Dimension.SYM_P
27695 case Dimension.L:
27696 return Dimension.SYM_L
27697 case Dimension.A:
27698 return Dimension.SYM_A
27699 default:
27700 }
27701 throw new IllegalArgumentException('Unknown dimension value: ' + dimensionValue)
27702};
27703Dimension.toDimensionValue = function toDimensionValue (dimensionSymbol) {
27704 switch (Character.toUpperCase(dimensionSymbol)) {
27705 case Dimension.SYM_FALSE:
27706 return Dimension.FALSE
27707 case Dimension.SYM_TRUE:
27708 return Dimension.TRUE
27709 case Dimension.SYM_DONTCARE:
27710 return Dimension.DONTCARE
27711 case Dimension.SYM_P:
27712 return Dimension.P
27713 case Dimension.SYM_L:
27714 return Dimension.L
27715 case Dimension.SYM_A:
27716 return Dimension.A
27717 default:
27718 }
27719 throw new IllegalArgumentException('Unknown dimension symbol: ' + dimensionSymbol)
27720};
27721
27722Object.defineProperties( Dimension, staticAccessors$14 );
27723
27724var GeometryFilter = function GeometryFilter () {};
27725
27726GeometryFilter.prototype.filter = function filter (geom) {};
27727GeometryFilter.prototype.interfaces_ = function interfaces_ () {
27728 return []
27729};
27730GeometryFilter.prototype.getClass = function getClass () {
27731 return GeometryFilter
27732};
27733
27734var CoordinateSequenceFilter = function CoordinateSequenceFilter () {};
27735
27736CoordinateSequenceFilter.prototype.filter = function filter (seq, i) {};
27737CoordinateSequenceFilter.prototype.isDone = function isDone () {};
27738CoordinateSequenceFilter.prototype.isGeometryChanged = function isGeometryChanged () {};
27739CoordinateSequenceFilter.prototype.interfaces_ = function interfaces_ () {
27740 return []
27741};
27742CoordinateSequenceFilter.prototype.getClass = function getClass () {
27743 return CoordinateSequenceFilter
27744};
27745
27746var GeometryCollection = (function (Geometry$$1) {
27747 function GeometryCollection (geometries, factory) {
27748 Geometry$$1.call(this, factory);
27749 this._geometries = geometries || [];
27750
27751 if (Geometry$$1.hasNullElements(this._geometries)) {
27752 throw new IllegalArgumentException('geometries must not contain null elements')
27753 }
27754 }
27755
27756 if ( Geometry$$1 ) GeometryCollection.__proto__ = Geometry$$1;
27757 GeometryCollection.prototype = Object.create( Geometry$$1 && Geometry$$1.prototype );
27758 GeometryCollection.prototype.constructor = GeometryCollection;
27759
27760 var staticAccessors = { serialVersionUID: { configurable: true } };
27761 GeometryCollection.prototype.computeEnvelopeInternal = function computeEnvelopeInternal () {
27762 var this$1 = this;
27763
27764 var envelope = new Envelope();
27765 for (var i = 0; i < this._geometries.length; i++) {
27766 envelope.expandToInclude(this$1._geometries[i].getEnvelopeInternal());
27767 }
27768 return envelope
27769 };
27770 GeometryCollection.prototype.getGeometryN = function getGeometryN (n) {
27771 return this._geometries[n]
27772 };
27773 GeometryCollection.prototype.getSortIndex = function getSortIndex () {
27774 return Geometry$$1.SORTINDEX_GEOMETRYCOLLECTION
27775 };
27776 GeometryCollection.prototype.getCoordinates = function getCoordinates () {
27777 var this$1 = this;
27778
27779 var coordinates = new Array(this.getNumPoints()).fill(null);
27780 var k = -1;
27781 for (var i = 0; i < this._geometries.length; i++) {
27782 var childCoordinates = this$1._geometries[i].getCoordinates();
27783 for (var j = 0; j < childCoordinates.length; j++) {
27784 k++;
27785 coordinates[k] = childCoordinates[j];
27786 }
27787 }
27788 return coordinates
27789 };
27790 GeometryCollection.prototype.getArea = function getArea () {
27791 var this$1 = this;
27792
27793 var area = 0.0;
27794 for (var i = 0; i < this._geometries.length; i++) {
27795 area += this$1._geometries[i].getArea();
27796 }
27797 return area
27798 };
27799 GeometryCollection.prototype.equalsExact = function equalsExact () {
27800 var this$1 = this;
27801
27802 if (arguments.length === 2) {
27803 var other = arguments[0];
27804 var tolerance = arguments[1];
27805 if (!this.isEquivalentClass(other)) {
27806 return false
27807 }
27808 var otherCollection = other;
27809 if (this._geometries.length !== otherCollection._geometries.length) {
27810 return false
27811 }
27812 for (var i = 0; i < this._geometries.length; i++) {
27813 if (!this$1._geometries[i].equalsExact(otherCollection._geometries[i], tolerance)) {
27814 return false
27815 }
27816 }
27817 return true
27818 } else { return Geometry$$1.prototype.equalsExact.apply(this, arguments) }
27819 };
27820 GeometryCollection.prototype.normalize = function normalize () {
27821 var this$1 = this;
27822
27823 for (var i = 0; i < this._geometries.length; i++) {
27824 this$1._geometries[i].normalize();
27825 }
27826 Arrays.sort(this._geometries);
27827 };
27828 GeometryCollection.prototype.getCoordinate = function getCoordinate () {
27829 if (this.isEmpty()) { return null }
27830 return this._geometries[0].getCoordinate()
27831 };
27832 GeometryCollection.prototype.getBoundaryDimension = function getBoundaryDimension () {
27833 var this$1 = this;
27834
27835 var dimension = Dimension.FALSE;
27836 for (var i = 0; i < this._geometries.length; i++) {
27837 dimension = Math.max(dimension, this$1._geometries[i].getBoundaryDimension());
27838 }
27839 return dimension
27840 };
27841 GeometryCollection.prototype.getDimension = function getDimension () {
27842 var this$1 = this;
27843
27844 var dimension = Dimension.FALSE;
27845 for (var i = 0; i < this._geometries.length; i++) {
27846 dimension = Math.max(dimension, this$1._geometries[i].getDimension());
27847 }
27848 return dimension
27849 };
27850 GeometryCollection.prototype.getLength = function getLength () {
27851 var this$1 = this;
27852
27853 var sum = 0.0;
27854 for (var i = 0; i < this._geometries.length; i++) {
27855 sum += this$1._geometries[i].getLength();
27856 }
27857 return sum
27858 };
27859 GeometryCollection.prototype.getNumPoints = function getNumPoints () {
27860 var this$1 = this;
27861
27862 var numPoints = 0;
27863 for (var i = 0; i < this._geometries.length; i++) {
27864 numPoints += this$1._geometries[i].getNumPoints();
27865 }
27866 return numPoints
27867 };
27868 GeometryCollection.prototype.getNumGeometries = function getNumGeometries () {
27869 return this._geometries.length
27870 };
27871 GeometryCollection.prototype.reverse = function reverse () {
27872 var this$1 = this;
27873
27874 var n = this._geometries.length;
27875 var revGeoms = new Array(n).fill(null);
27876 for (var i = 0; i < this._geometries.length; i++) {
27877 revGeoms[i] = this$1._geometries[i].reverse();
27878 }
27879 return this.getFactory().createGeometryCollection(revGeoms)
27880 };
27881 GeometryCollection.prototype.compareToSameClass = function compareToSameClass () {
27882 var this$1 = this;
27883
27884 if (arguments.length === 1) {
27885 var o = arguments[0];
27886 var theseElements = new TreeSet(Arrays.asList(this._geometries));
27887 var otherElements = new TreeSet(Arrays.asList(o._geometries));
27888 return this.compare(theseElements, otherElements)
27889 } else if (arguments.length === 2) {
27890 var o$1 = arguments[0];
27891 var comp = arguments[1];
27892 var gc = o$1;
27893 var n1 = this.getNumGeometries();
27894 var n2 = gc.getNumGeometries();
27895 var i = 0;
27896 while (i < n1 && i < n2) {
27897 var thisGeom = this$1.getGeometryN(i);
27898 var otherGeom = gc.getGeometryN(i);
27899 var holeComp = thisGeom.compareToSameClass(otherGeom, comp);
27900 if (holeComp !== 0) { return holeComp }
27901 i++;
27902 }
27903 if (i < n1) { return 1 }
27904 if (i < n2) { return -1 }
27905 return 0
27906 }
27907 };
27908 GeometryCollection.prototype.apply = function apply () {
27909 var this$1 = this;
27910
27911 if (hasInterface(arguments[0], CoordinateFilter)) {
27912 var filter = arguments[0];
27913 for (var i = 0; i < this._geometries.length; i++) {
27914 this$1._geometries[i].apply(filter);
27915 }
27916 } else if (hasInterface(arguments[0], CoordinateSequenceFilter)) {
27917 var filter$1 = arguments[0];
27918 if (this._geometries.length === 0) { return null }
27919 for (var i$1 = 0; i$1 < this._geometries.length; i$1++) {
27920 this$1._geometries[i$1].apply(filter$1);
27921 if (filter$1.isDone()) {
27922 break
27923 }
27924 }
27925 if (filter$1.isGeometryChanged()) { this.geometryChanged(); }
27926 } else if (hasInterface(arguments[0], GeometryFilter)) {
27927 var filter$2 = arguments[0];
27928 filter$2.filter(this);
27929 for (var i$2 = 0; i$2 < this._geometries.length; i$2++) {
27930 this$1._geometries[i$2].apply(filter$2);
27931 }
27932 } else if (hasInterface(arguments[0], GeometryComponentFilter)) {
27933 var filter$3 = arguments[0];
27934 filter$3.filter(this);
27935 for (var i$3 = 0; i$3 < this._geometries.length; i$3++) {
27936 this$1._geometries[i$3].apply(filter$3);
27937 }
27938 }
27939 };
27940 GeometryCollection.prototype.getBoundary = function getBoundary () {
27941 this.checkNotGeometryCollection(this);
27942 Assert.shouldNeverReachHere();
27943 return null
27944 };
27945 GeometryCollection.prototype.clone = function clone () {
27946 var this$1 = this;
27947
27948 var gc = Geometry$$1.prototype.clone.call(this);
27949 gc._geometries = new Array(this._geometries.length).fill(null);
27950 for (var i = 0; i < this._geometries.length; i++) {
27951 gc._geometries[i] = this$1._geometries[i].clone();
27952 }
27953 return gc
27954 };
27955 GeometryCollection.prototype.getGeometryType = function getGeometryType () {
27956 return 'GeometryCollection'
27957 };
27958 GeometryCollection.prototype.copy = function copy () {
27959 var this$1 = this;
27960
27961 var geometries = new Array(this._geometries.length).fill(null);
27962 for (var i = 0; i < geometries.length; i++) {
27963 geometries[i] = this$1._geometries[i].copy();
27964 }
27965 return new GeometryCollection(geometries, this._factory)
27966 };
27967 GeometryCollection.prototype.isEmpty = function isEmpty () {
27968 var this$1 = this;
27969
27970 for (var i = 0; i < this._geometries.length; i++) {
27971 if (!this$1._geometries[i].isEmpty()) {
27972 return false
27973 }
27974 }
27975 return true
27976 };
27977 GeometryCollection.prototype.interfaces_ = function interfaces_ () {
27978 return []
27979 };
27980 GeometryCollection.prototype.getClass = function getClass () {
27981 return GeometryCollection
27982 };
27983 staticAccessors.serialVersionUID.get = function () { return -5694727726395021467 };
27984
27985 Object.defineProperties( GeometryCollection, staticAccessors );
27986
27987 return GeometryCollection;
27988}(Geometry));
27989
27990var MultiLineString = (function (GeometryCollection$$1) {
27991 function MultiLineString () {
27992 GeometryCollection$$1.apply(this, arguments);
27993 }
27994
27995 if ( GeometryCollection$$1 ) MultiLineString.__proto__ = GeometryCollection$$1;
27996 MultiLineString.prototype = Object.create( GeometryCollection$$1 && GeometryCollection$$1.prototype );
27997 MultiLineString.prototype.constructor = MultiLineString;
27998
27999 var staticAccessors = { serialVersionUID: { configurable: true } };
28000
28001 MultiLineString.prototype.getSortIndex = function getSortIndex () {
28002 return Geometry.SORTINDEX_MULTILINESTRING
28003 };
28004 MultiLineString.prototype.equalsExact = function equalsExact () {
28005 if (arguments.length === 2) {
28006 var other = arguments[0];
28007 var tolerance = arguments[1];
28008 if (!this.isEquivalentClass(other)) {
28009 return false
28010 }
28011 return GeometryCollection$$1.prototype.equalsExact.call(this, other, tolerance)
28012 } else { return GeometryCollection$$1.prototype.equalsExact.apply(this, arguments) }
28013 };
28014 MultiLineString.prototype.getBoundaryDimension = function getBoundaryDimension () {
28015 if (this.isClosed()) {
28016 return Dimension.FALSE
28017 }
28018 return 0
28019 };
28020 MultiLineString.prototype.isClosed = function isClosed () {
28021 var this$1 = this;
28022
28023 if (this.isEmpty()) {
28024 return false
28025 }
28026 for (var i = 0; i < this._geometries.length; i++) {
28027 if (!this$1._geometries[i].isClosed()) {
28028 return false
28029 }
28030 }
28031 return true
28032 };
28033 MultiLineString.prototype.getDimension = function getDimension () {
28034 return 1
28035 };
28036 MultiLineString.prototype.reverse = function reverse () {
28037 var this$1 = this;
28038
28039 var nLines = this._geometries.length;
28040 var revLines = new Array(nLines).fill(null);
28041 for (var i = 0; i < this._geometries.length; i++) {
28042 revLines[nLines - 1 - i] = this$1._geometries[i].reverse();
28043 }
28044 return this.getFactory().createMultiLineString(revLines)
28045 };
28046 MultiLineString.prototype.getBoundary = function getBoundary () {
28047 return new BoundaryOp(this).getBoundary()
28048 };
28049 MultiLineString.prototype.getGeometryType = function getGeometryType () {
28050 return 'MultiLineString'
28051 };
28052 MultiLineString.prototype.copy = function copy () {
28053 var this$1 = this;
28054
28055 var lineStrings = new Array(this._geometries.length).fill(null);
28056 for (var i = 0; i < lineStrings.length; i++) {
28057 lineStrings[i] = this$1._geometries[i].copy();
28058 }
28059 return new MultiLineString(lineStrings, this._factory)
28060 };
28061 MultiLineString.prototype.interfaces_ = function interfaces_ () {
28062 return [Lineal]
28063 };
28064 MultiLineString.prototype.getClass = function getClass () {
28065 return MultiLineString
28066 };
28067 staticAccessors.serialVersionUID.get = function () { return 8166665132445433741 };
28068
28069 Object.defineProperties( MultiLineString, staticAccessors );
28070
28071 return MultiLineString;
28072}(GeometryCollection));
28073
28074var BoundaryOp = function BoundaryOp () {
28075 this._geom = null;
28076 this._geomFact = null;
28077 this._bnRule = null;
28078 this._endpointMap = null;
28079 if (arguments.length === 1) {
28080 var geom = arguments[0];
28081 var bnRule = BoundaryNodeRule.MOD2_BOUNDARY_RULE;
28082 this._geom = geom;
28083 this._geomFact = geom.getFactory();
28084 this._bnRule = bnRule;
28085 } else if (arguments.length === 2) {
28086 var geom$1 = arguments[0];
28087 var bnRule$1 = arguments[1];
28088 this._geom = geom$1;
28089 this._geomFact = geom$1.getFactory();
28090 this._bnRule = bnRule$1;
28091 }
28092};
28093BoundaryOp.prototype.boundaryMultiLineString = function boundaryMultiLineString (mLine) {
28094 if (this._geom.isEmpty()) {
28095 return this.getEmptyMultiPoint()
28096 }
28097 var bdyPts = this.computeBoundaryCoordinates(mLine);
28098 if (bdyPts.length === 1) {
28099 return this._geomFact.createPoint(bdyPts[0])
28100 }
28101 return this._geomFact.createMultiPointFromCoords(bdyPts)
28102};
28103BoundaryOp.prototype.getBoundary = function getBoundary () {
28104 if (this._geom instanceof LineString$1) { return this.boundaryLineString(this._geom) }
28105 if (this._geom instanceof MultiLineString) { return this.boundaryMultiLineString(this._geom) }
28106 return this._geom.getBoundary()
28107};
28108BoundaryOp.prototype.boundaryLineString = function boundaryLineString (line) {
28109 if (this._geom.isEmpty()) {
28110 return this.getEmptyMultiPoint()
28111 }
28112 if (line.isClosed()) {
28113 var closedEndpointOnBoundary = this._bnRule.isInBoundary(2);
28114 if (closedEndpointOnBoundary) {
28115 return line.getStartPoint()
28116 } else {
28117 return this._geomFact.createMultiPoint()
28118 }
28119 }
28120 return this._geomFact.createMultiPoint([line.getStartPoint(), line.getEndPoint()])
28121};
28122BoundaryOp.prototype.getEmptyMultiPoint = function getEmptyMultiPoint () {
28123 return this._geomFact.createMultiPoint()
28124};
28125BoundaryOp.prototype.computeBoundaryCoordinates = function computeBoundaryCoordinates (mLine) {
28126 var this$1 = this;
28127
28128 var bdyPts = new ArrayList();
28129 this._endpointMap = new TreeMap();
28130 for (var i = 0; i < mLine.getNumGeometries(); i++) {
28131 var line = mLine.getGeometryN(i);
28132 if (line.getNumPoints() === 0) { continue }
28133 this$1.addEndpoint(line.getCoordinateN(0));
28134 this$1.addEndpoint(line.getCoordinateN(line.getNumPoints() - 1));
28135 }
28136 for (var it = this._endpointMap.entrySet().iterator(); it.hasNext();) {
28137 var entry = it.next();
28138 var counter = entry.getValue();
28139 var valence = counter.count;
28140 if (this$1._bnRule.isInBoundary(valence)) {
28141 bdyPts.add(entry.getKey());
28142 }
28143 }
28144 return CoordinateArrays.toCoordinateArray(bdyPts)
28145};
28146BoundaryOp.prototype.addEndpoint = function addEndpoint (pt) {
28147 var counter = this._endpointMap.get(pt);
28148 if (counter === null) {
28149 counter = new Counter();
28150 this._endpointMap.put(pt, counter);
28151 }
28152 counter.count++;
28153};
28154BoundaryOp.prototype.interfaces_ = function interfaces_ () {
28155 return []
28156};
28157BoundaryOp.prototype.getClass = function getClass () {
28158 return BoundaryOp
28159};
28160BoundaryOp.getBoundary = function getBoundary () {
28161 if (arguments.length === 1) {
28162 var g = arguments[0];
28163 var bop = new BoundaryOp(g);
28164 return bop.getBoundary()
28165 } else if (arguments.length === 2) {
28166 var g$1 = arguments[0];
28167 var bnRule = arguments[1];
28168 var bop$1 = new BoundaryOp(g$1, bnRule);
28169 return bop$1.getBoundary()
28170 }
28171};
28172
28173var Counter = function Counter () {
28174 this.count = null;
28175};
28176Counter.prototype.interfaces_ = function interfaces_ () {
28177 return []
28178};
28179Counter.prototype.getClass = function getClass () {
28180 return Counter
28181};
28182
28183// boundary
28184
28185function PrintStream () {}
28186
28187function StringReader () {}
28188
28189var DecimalFormat = function DecimalFormat () {};
28190
28191function ByteArrayOutputStream () {}
28192
28193function IOException () {}
28194
28195function LineNumberReader () {}
28196
28197var StringUtil = function StringUtil () {};
28198
28199var staticAccessors$15 = { NEWLINE: { configurable: true },SIMPLE_ORDINATE_FORMAT: { configurable: true } };
28200
28201StringUtil.prototype.interfaces_ = function interfaces_ () {
28202 return []
28203};
28204StringUtil.prototype.getClass = function getClass () {
28205 return StringUtil
28206};
28207StringUtil.chars = function chars (c, n) {
28208 var ch = new Array(n).fill(null);
28209 for (var i = 0; i < n; i++) {
28210 ch[i] = c;
28211 }
28212 return String(ch)
28213};
28214StringUtil.getStackTrace = function getStackTrace () {
28215 if (arguments.length === 1) {
28216 var t = arguments[0];
28217 var os = new ByteArrayOutputStream();
28218 var ps = new PrintStream(os);
28219 t.printStackTrace(ps);
28220 return os.toString()
28221 } else if (arguments.length === 2) {
28222 var t$1 = arguments[0];
28223 var depth = arguments[1];
28224 var stackTrace = '';
28225 var stringReader = new StringReader(StringUtil.getStackTrace(t$1));
28226 var lineNumberReader = new LineNumberReader(stringReader);
28227 for (var i = 0; i < depth; i++) {
28228 try {
28229 stackTrace += lineNumberReader.readLine() + StringUtil.NEWLINE;
28230 } catch (e) {
28231 if (e instanceof IOException) {
28232 Assert.shouldNeverReachHere();
28233 } else { throw e }
28234 } finally {}
28235 }
28236 return stackTrace
28237 }
28238};
28239StringUtil.split = function split (s, separator) {
28240 var separatorlen = separator.length;
28241 var tokenList = new ArrayList();
28242 var tmpString = '' + s;
28243 var pos = tmpString.indexOf(separator);
28244 while (pos >= 0) {
28245 var token = tmpString.substring(0, pos);
28246 tokenList.add(token);
28247 tmpString = tmpString.substring(pos + separatorlen);
28248 pos = tmpString.indexOf(separator);
28249 }
28250 if (tmpString.length > 0) { tokenList.add(tmpString); }
28251 var res = new Array(tokenList.size()).fill(null);
28252 for (var i = 0; i < res.length; i++) {
28253 res[i] = tokenList.get(i);
28254 }
28255 return res
28256};
28257StringUtil.toString = function toString () {
28258 if (arguments.length === 1) {
28259 var d = arguments[0];
28260 return StringUtil.SIMPLE_ORDINATE_FORMAT.format(d)
28261 }
28262};
28263StringUtil.spaces = function spaces (n) {
28264 return StringUtil.chars(' ', n)
28265};
28266staticAccessors$15.NEWLINE.get = function () { return System.getProperty('line.separator') };
28267staticAccessors$15.SIMPLE_ORDINATE_FORMAT.get = function () { return new DecimalFormat('0.#') };
28268
28269Object.defineProperties( StringUtil, staticAccessors$15 );
28270
28271var CoordinateSequences = function CoordinateSequences () {};
28272
28273CoordinateSequences.prototype.interfaces_ = function interfaces_ () {
28274 return []
28275};
28276CoordinateSequences.prototype.getClass = function getClass () {
28277 return CoordinateSequences
28278};
28279CoordinateSequences.copyCoord = function copyCoord (src, srcPos, dest, destPos) {
28280 var minDim = Math.min(src.getDimension(), dest.getDimension());
28281 for (var dim = 0; dim < minDim; dim++) {
28282 dest.setOrdinate(destPos, dim, src.getOrdinate(srcPos, dim));
28283 }
28284};
28285CoordinateSequences.isRing = function isRing (seq) {
28286 var n = seq.size();
28287 if (n === 0) { return true }
28288 if (n <= 3) { return false }
28289 return seq.getOrdinate(0, CoordinateSequence.X) === seq.getOrdinate(n - 1, CoordinateSequence.X) && seq.getOrdinate(0, CoordinateSequence.Y) === seq.getOrdinate(n - 1, CoordinateSequence.Y)
28290};
28291CoordinateSequences.isEqual = function isEqual (cs1, cs2) {
28292 var cs1Size = cs1.size();
28293 var cs2Size = cs2.size();
28294 if (cs1Size !== cs2Size) { return false }
28295 var dim = Math.min(cs1.getDimension(), cs2.getDimension());
28296 for (var i = 0; i < cs1Size; i++) {
28297 for (var d = 0; d < dim; d++) {
28298 var v1 = cs1.getOrdinate(i, d);
28299 var v2 = cs2.getOrdinate(i, d);
28300 if (cs1.getOrdinate(i, d) === cs2.getOrdinate(i, d)) { continue }
28301 if (Double.isNaN(v1) && Double.isNaN(v2)) { continue }
28302 return false
28303 }
28304 }
28305 return true
28306};
28307CoordinateSequences.extend = function extend (fact, seq, size) {
28308 var newseq = fact.create(size, seq.getDimension());
28309 var n = seq.size();
28310 CoordinateSequences.copy(seq, 0, newseq, 0, n);
28311 if (n > 0) {
28312 for (var i = n; i < size; i++) { CoordinateSequences.copy(seq, n - 1, newseq, i, 1); }
28313 }
28314 return newseq
28315};
28316CoordinateSequences.reverse = function reverse (seq) {
28317 var last = seq.size() - 1;
28318 var mid = Math.trunc(last / 2);
28319 for (var i = 0; i <= mid; i++) {
28320 CoordinateSequences.swap(seq, i, last - i);
28321 }
28322};
28323CoordinateSequences.swap = function swap (seq, i, j) {
28324 if (i === j) { return null }
28325 for (var dim = 0; dim < seq.getDimension(); dim++) {
28326 var tmp = seq.getOrdinate(i, dim);
28327 seq.setOrdinate(i, dim, seq.getOrdinate(j, dim));
28328 seq.setOrdinate(j, dim, tmp);
28329 }
28330};
28331CoordinateSequences.copy = function copy (src, srcPos, dest, destPos, length) {
28332 for (var i = 0; i < length; i++) {
28333 CoordinateSequences.copyCoord(src, srcPos + i, dest, destPos + i);
28334 }
28335};
28336CoordinateSequences.toString = function toString () {
28337 if (arguments.length === 1) {
28338 var cs = arguments[0];
28339 var size = cs.size();
28340 if (size === 0) { return '()' }
28341 var dim = cs.getDimension();
28342 var buf = new StringBuffer();
28343 buf.append('(');
28344 for (var i = 0; i < size; i++) {
28345 if (i > 0) { buf.append(' '); }
28346 for (var d = 0; d < dim; d++) {
28347 if (d > 0) { buf.append(','); }
28348 buf.append(StringUtil.toString(cs.getOrdinate(i, d)));
28349 }
28350 }
28351 buf.append(')');
28352 return buf.toString()
28353 }
28354};
28355CoordinateSequences.ensureValidRing = function ensureValidRing (fact, seq) {
28356 var n = seq.size();
28357 if (n === 0) { return seq }
28358 if (n <= 3) { return CoordinateSequences.createClosedRing(fact, seq, 4) }
28359 var isClosed = seq.getOrdinate(0, CoordinateSequence.X) === seq.getOrdinate(n - 1, CoordinateSequence.X) && seq.getOrdinate(0, CoordinateSequence.Y) === seq.getOrdinate(n - 1, CoordinateSequence.Y);
28360 if (isClosed) { return seq }
28361 return CoordinateSequences.createClosedRing(fact, seq, n + 1)
28362};
28363CoordinateSequences.createClosedRing = function createClosedRing (fact, seq, size) {
28364 var newseq = fact.create(size, seq.getDimension());
28365 var n = seq.size();
28366 CoordinateSequences.copy(seq, 0, newseq, 0, n);
28367 for (var i = n; i < size; i++) { CoordinateSequences.copy(seq, 0, newseq, i, 1); }
28368 return newseq
28369};
28370
28371var LineString$1 = (function (Geometry$$1) {
28372 function LineString (points, factory) {
28373 Geometry$$1.call(this, factory);
28374 this._points = null;
28375 this.init(points);
28376 }
28377
28378 if ( Geometry$$1 ) LineString.__proto__ = Geometry$$1;
28379 LineString.prototype = Object.create( Geometry$$1 && Geometry$$1.prototype );
28380 LineString.prototype.constructor = LineString;
28381
28382 var staticAccessors = { serialVersionUID: { configurable: true } };
28383 LineString.prototype.computeEnvelopeInternal = function computeEnvelopeInternal () {
28384 if (this.isEmpty()) {
28385 return new Envelope()
28386 }
28387 return this._points.expandEnvelope(new Envelope())
28388 };
28389 LineString.prototype.isRing = function isRing () {
28390 return this.isClosed() && this.isSimple()
28391 };
28392 LineString.prototype.getSortIndex = function getSortIndex () {
28393 return Geometry$$1.SORTINDEX_LINESTRING
28394 };
28395 LineString.prototype.getCoordinates = function getCoordinates () {
28396 return this._points.toCoordinateArray()
28397 };
28398 LineString.prototype.equalsExact = function equalsExact () {
28399 var this$1 = this;
28400
28401 if (arguments.length === 2) {
28402 var other = arguments[0];
28403 var tolerance = arguments[1];
28404 if (!this.isEquivalentClass(other)) {
28405 return false
28406 }
28407 var otherLineString = other;
28408 if (this._points.size() !== otherLineString._points.size()) {
28409 return false
28410 }
28411 for (var i = 0; i < this._points.size(); i++) {
28412 if (!this$1.equal(this$1._points.getCoordinate(i), otherLineString._points.getCoordinate(i), tolerance)) {
28413 return false
28414 }
28415 }
28416 return true
28417 } else { return Geometry$$1.prototype.equalsExact.apply(this, arguments) }
28418 };
28419 LineString.prototype.normalize = function normalize () {
28420 var this$1 = this;
28421
28422 for (var i = 0; i < Math.trunc(this._points.size() / 2); i++) {
28423 var j = this$1._points.size() - 1 - i;
28424 if (!this$1._points.getCoordinate(i).equals(this$1._points.getCoordinate(j))) {
28425 if (this$1._points.getCoordinate(i).compareTo(this$1._points.getCoordinate(j)) > 0) {
28426 CoordinateSequences.reverse(this$1._points);
28427 }
28428 return null
28429 }
28430 }
28431 };
28432 LineString.prototype.getCoordinate = function getCoordinate () {
28433 if (this.isEmpty()) { return null }
28434 return this._points.getCoordinate(0)
28435 };
28436 LineString.prototype.getBoundaryDimension = function getBoundaryDimension () {
28437 if (this.isClosed()) {
28438 return Dimension.FALSE
28439 }
28440 return 0
28441 };
28442 LineString.prototype.isClosed = function isClosed () {
28443 if (this.isEmpty()) {
28444 return false
28445 }
28446 return this.getCoordinateN(0).equals2D(this.getCoordinateN(this.getNumPoints() - 1))
28447 };
28448 LineString.prototype.getEndPoint = function getEndPoint () {
28449 if (this.isEmpty()) {
28450 return null
28451 }
28452 return this.getPointN(this.getNumPoints() - 1)
28453 };
28454 LineString.prototype.getDimension = function getDimension () {
28455 return 1
28456 };
28457 LineString.prototype.getLength = function getLength () {
28458 return CGAlgorithms.computeLength(this._points)
28459 };
28460 LineString.prototype.getNumPoints = function getNumPoints () {
28461 return this._points.size()
28462 };
28463 LineString.prototype.reverse = function reverse () {
28464 var seq = this._points.copy();
28465 CoordinateSequences.reverse(seq);
28466 var revLine = this.getFactory().createLineString(seq);
28467 return revLine
28468 };
28469 LineString.prototype.compareToSameClass = function compareToSameClass () {
28470 var this$1 = this;
28471
28472 if (arguments.length === 1) {
28473 var o = arguments[0];
28474 var line = o;
28475 var i = 0;
28476 var j = 0;
28477 while (i < this._points.size() && j < line._points.size()) {
28478 var comparison = this$1._points.getCoordinate(i).compareTo(line._points.getCoordinate(j));
28479 if (comparison !== 0) {
28480 return comparison
28481 }
28482 i++;
28483 j++;
28484 }
28485 if (i < this._points.size()) {
28486 return 1
28487 }
28488 if (j < line._points.size()) {
28489 return -1
28490 }
28491 return 0
28492 } else if (arguments.length === 2) {
28493 var o$1 = arguments[0];
28494 var comp = arguments[1];
28495 var line$1 = o$1;
28496 return comp.compare(this._points, line$1._points)
28497 }
28498 };
28499 LineString.prototype.apply = function apply () {
28500 var this$1 = this;
28501
28502 if (hasInterface(arguments[0], CoordinateFilter)) {
28503 var filter = arguments[0];
28504 for (var i = 0; i < this._points.size(); i++) {
28505 filter.filter(this$1._points.getCoordinate(i));
28506 }
28507 } else if (hasInterface(arguments[0], CoordinateSequenceFilter)) {
28508 var filter$1 = arguments[0];
28509 if (this._points.size() === 0) { return null }
28510 for (var i$1 = 0; i$1 < this._points.size(); i$1++) {
28511 filter$1.filter(this$1._points, i$1);
28512 if (filter$1.isDone()) { break }
28513 }
28514 if (filter$1.isGeometryChanged()) { this.geometryChanged(); }
28515 } else if (hasInterface(arguments[0], GeometryFilter)) {
28516 var filter$2 = arguments[0];
28517 filter$2.filter(this);
28518 } else if (hasInterface(arguments[0], GeometryComponentFilter)) {
28519 var filter$3 = arguments[0];
28520 filter$3.filter(this);
28521 }
28522 };
28523 LineString.prototype.getBoundary = function getBoundary () {
28524 return new BoundaryOp(this).getBoundary()
28525 };
28526 LineString.prototype.isEquivalentClass = function isEquivalentClass (other) {
28527 return other instanceof LineString
28528 };
28529 LineString.prototype.clone = function clone () {
28530 var ls = Geometry$$1.prototype.clone.call(this);
28531 ls._points = this._points.clone();
28532 return ls
28533 };
28534 LineString.prototype.getCoordinateN = function getCoordinateN (n) {
28535 return this._points.getCoordinate(n)
28536 };
28537 LineString.prototype.getGeometryType = function getGeometryType () {
28538 return 'LineString'
28539 };
28540 LineString.prototype.copy = function copy () {
28541 return new LineString(this._points.copy(), this._factory)
28542 };
28543 LineString.prototype.getCoordinateSequence = function getCoordinateSequence () {
28544 return this._points
28545 };
28546 LineString.prototype.isEmpty = function isEmpty () {
28547 return this._points.size() === 0
28548 };
28549 LineString.prototype.init = function init (points) {
28550 if (points === null) {
28551 points = this.getFactory().getCoordinateSequenceFactory().create([]);
28552 }
28553 if (points.size() === 1) {
28554 throw new IllegalArgumentException('Invalid number of points in LineString (found ' + points.size() + ' - must be 0 or >= 2)')
28555 }
28556 this._points = points;
28557 };
28558 LineString.prototype.isCoordinate = function isCoordinate (pt) {
28559 var this$1 = this;
28560
28561 for (var i = 0; i < this._points.size(); i++) {
28562 if (this$1._points.getCoordinate(i).equals(pt)) {
28563 return true
28564 }
28565 }
28566 return false
28567 };
28568 LineString.prototype.getStartPoint = function getStartPoint () {
28569 if (this.isEmpty()) {
28570 return null
28571 }
28572 return this.getPointN(0)
28573 };
28574 LineString.prototype.getPointN = function getPointN (n) {
28575 return this.getFactory().createPoint(this._points.getCoordinate(n))
28576 };
28577 LineString.prototype.interfaces_ = function interfaces_ () {
28578 return [Lineal]
28579 };
28580 LineString.prototype.getClass = function getClass () {
28581 return LineString
28582 };
28583 staticAccessors.serialVersionUID.get = function () { return 3110669828065365560 };
28584
28585 Object.defineProperties( LineString, staticAccessors );
28586
28587 return LineString;
28588}(Geometry));
28589
28590var Puntal = function Puntal () {};
28591
28592Puntal.prototype.interfaces_ = function interfaces_ () {
28593 return []
28594};
28595Puntal.prototype.getClass = function getClass () {
28596 return Puntal
28597};
28598
28599var Point = (function (Geometry$$1) {
28600 function Point (coordinates, factory) {
28601 Geometry$$1.call(this, factory);
28602 this._coordinates = coordinates || null;
28603 this.init(this._coordinates);
28604 }
28605
28606 if ( Geometry$$1 ) Point.__proto__ = Geometry$$1;
28607 Point.prototype = Object.create( Geometry$$1 && Geometry$$1.prototype );
28608 Point.prototype.constructor = Point;
28609
28610 var staticAccessors = { serialVersionUID: { configurable: true } };
28611 Point.prototype.computeEnvelopeInternal = function computeEnvelopeInternal () {
28612 if (this.isEmpty()) {
28613 return new Envelope()
28614 }
28615 var env = new Envelope();
28616 env.expandToInclude(this._coordinates.getX(0), this._coordinates.getY(0));
28617 return env
28618 };
28619 Point.prototype.getSortIndex = function getSortIndex () {
28620 return Geometry$$1.SORTINDEX_POINT
28621 };
28622 Point.prototype.getCoordinates = function getCoordinates () {
28623 return this.isEmpty() ? [] : [this.getCoordinate()]
28624 };
28625 Point.prototype.equalsExact = function equalsExact () {
28626 if (arguments.length === 2) {
28627 var other = arguments[0];
28628 var tolerance = arguments[1];
28629 if (!this.isEquivalentClass(other)) {
28630 return false
28631 }
28632 if (this.isEmpty() && other.isEmpty()) {
28633 return true
28634 }
28635 if (this.isEmpty() !== other.isEmpty()) {
28636 return false
28637 }
28638 return this.equal(other.getCoordinate(), this.getCoordinate(), tolerance)
28639 } else { return Geometry$$1.prototype.equalsExact.apply(this, arguments) }
28640 };
28641 Point.prototype.normalize = function normalize () {};
28642 Point.prototype.getCoordinate = function getCoordinate () {
28643 return this._coordinates.size() !== 0 ? this._coordinates.getCoordinate(0) : null
28644 };
28645 Point.prototype.getBoundaryDimension = function getBoundaryDimension () {
28646 return Dimension.FALSE
28647 };
28648 Point.prototype.getDimension = function getDimension () {
28649 return 0
28650 };
28651 Point.prototype.getNumPoints = function getNumPoints () {
28652 return this.isEmpty() ? 0 : 1
28653 };
28654 Point.prototype.reverse = function reverse () {
28655 return this.copy()
28656 };
28657 Point.prototype.getX = function getX () {
28658 if (this.getCoordinate() === null) {
28659 throw new Error('getX called on empty Point')
28660 }
28661 return this.getCoordinate().x
28662 };
28663 Point.prototype.compareToSameClass = function compareToSameClass () {
28664 if (arguments.length === 1) {
28665 var other = arguments[0];
28666 var point$1 = other;
28667 return this.getCoordinate().compareTo(point$1.getCoordinate())
28668 } else if (arguments.length === 2) {
28669 var other$1 = arguments[0];
28670 var comp = arguments[1];
28671 var point = other$1;
28672 return comp.compare(this._coordinates, point._coordinates)
28673 }
28674 };
28675 Point.prototype.apply = function apply () {
28676 if (hasInterface(arguments[0], CoordinateFilter)) {
28677 var filter = arguments[0];
28678 if (this.isEmpty()) {
28679 return null
28680 }
28681 filter.filter(this.getCoordinate());
28682 } else if (hasInterface(arguments[0], CoordinateSequenceFilter)) {
28683 var filter$1 = arguments[0];
28684 if (this.isEmpty()) { return null }
28685 filter$1.filter(this._coordinates, 0);
28686 if (filter$1.isGeometryChanged()) { this.geometryChanged(); }
28687 } else if (hasInterface(arguments[0], GeometryFilter)) {
28688 var filter$2 = arguments[0];
28689 filter$2.filter(this);
28690 } else if (hasInterface(arguments[0], GeometryComponentFilter)) {
28691 var filter$3 = arguments[0];
28692 filter$3.filter(this);
28693 }
28694 };
28695 Point.prototype.getBoundary = function getBoundary () {
28696 return this.getFactory().createGeometryCollection(null)
28697 };
28698 Point.prototype.clone = function clone () {
28699 var p = Geometry$$1.prototype.clone.call(this);
28700 p._coordinates = this._coordinates.clone();
28701 return p
28702 };
28703 Point.prototype.getGeometryType = function getGeometryType () {
28704 return 'Point'
28705 };
28706 Point.prototype.copy = function copy () {
28707 return new Point(this._coordinates.copy(), this._factory)
28708 };
28709 Point.prototype.getCoordinateSequence = function getCoordinateSequence () {
28710 return this._coordinates
28711 };
28712 Point.prototype.getY = function getY () {
28713 if (this.getCoordinate() === null) {
28714 throw new Error('getY called on empty Point')
28715 }
28716 return this.getCoordinate().y
28717 };
28718 Point.prototype.isEmpty = function isEmpty () {
28719 return this._coordinates.size() === 0
28720 };
28721 Point.prototype.init = function init (coordinates) {
28722 if (coordinates === null) {
28723 coordinates = this.getFactory().getCoordinateSequenceFactory().create([]);
28724 }
28725 Assert.isTrue(coordinates.size() <= 1);
28726 this._coordinates = coordinates;
28727 };
28728 Point.prototype.isSimple = function isSimple () {
28729 return true
28730 };
28731 Point.prototype.interfaces_ = function interfaces_ () {
28732 return [Puntal]
28733 };
28734 Point.prototype.getClass = function getClass () {
28735 return Point
28736 };
28737 staticAccessors.serialVersionUID.get = function () { return 4902022702746614570 };
28738
28739 Object.defineProperties( Point, staticAccessors );
28740
28741 return Point;
28742}(Geometry));
28743
28744var Polygonal = function Polygonal () {};
28745
28746Polygonal.prototype.interfaces_ = function interfaces_ () {
28747 return []
28748};
28749Polygonal.prototype.getClass = function getClass () {
28750 return Polygonal
28751};
28752
28753var Polygon = (function (Geometry$$1) {
28754 function Polygon (shell, holes, factory) {
28755 Geometry$$1.call(this, factory);
28756 this._shell = null;
28757 this._holes = null;
28758 if (shell === null) {
28759 shell = this.getFactory().createLinearRing();
28760 }
28761 if (holes === null) {
28762 holes = [];
28763 }
28764 if (Geometry$$1.hasNullElements(holes)) {
28765 throw new IllegalArgumentException('holes must not contain null elements')
28766 }
28767 if (shell.isEmpty() && Geometry$$1.hasNonEmptyElements(holes)) {
28768 throw new IllegalArgumentException('shell is empty but holes are not')
28769 }
28770 this._shell = shell;
28771 this._holes = holes;
28772 }
28773
28774 if ( Geometry$$1 ) Polygon.__proto__ = Geometry$$1;
28775 Polygon.prototype = Object.create( Geometry$$1 && Geometry$$1.prototype );
28776 Polygon.prototype.constructor = Polygon;
28777
28778 var staticAccessors = { serialVersionUID: { configurable: true } };
28779 Polygon.prototype.computeEnvelopeInternal = function computeEnvelopeInternal () {
28780 return this._shell.getEnvelopeInternal()
28781 };
28782 Polygon.prototype.getSortIndex = function getSortIndex () {
28783 return Geometry$$1.SORTINDEX_POLYGON
28784 };
28785 Polygon.prototype.getCoordinates = function getCoordinates () {
28786 var this$1 = this;
28787
28788 if (this.isEmpty()) {
28789 return []
28790 }
28791 var coordinates = new Array(this.getNumPoints()).fill(null);
28792 var k = -1;
28793 var shellCoordinates = this._shell.getCoordinates();
28794 for (var x = 0; x < shellCoordinates.length; x++) {
28795 k++;
28796 coordinates[k] = shellCoordinates[x];
28797 }
28798 for (var i = 0; i < this._holes.length; i++) {
28799 var childCoordinates = this$1._holes[i].getCoordinates();
28800 for (var j = 0; j < childCoordinates.length; j++) {
28801 k++;
28802 coordinates[k] = childCoordinates[j];
28803 }
28804 }
28805 return coordinates
28806 };
28807 Polygon.prototype.getArea = function getArea () {
28808 var this$1 = this;
28809
28810 var area = 0.0;
28811 area += Math.abs(CGAlgorithms.signedArea(this._shell.getCoordinateSequence()));
28812 for (var i = 0; i < this._holes.length; i++) {
28813 area -= Math.abs(CGAlgorithms.signedArea(this$1._holes[i].getCoordinateSequence()));
28814 }
28815 return area
28816 };
28817 Polygon.prototype.isRectangle = function isRectangle () {
28818 if (this.getNumInteriorRing() !== 0) { return false }
28819 if (this._shell === null) { return false }
28820 if (this._shell.getNumPoints() !== 5) { return false }
28821 var seq = this._shell.getCoordinateSequence();
28822 var env = this.getEnvelopeInternal();
28823 for (var i = 0; i < 5; i++) {
28824 var x = seq.getX(i);
28825 if (!(x === env.getMinX() || x === env.getMaxX())) { return false }
28826 var y = seq.getY(i);
28827 if (!(y === env.getMinY() || y === env.getMaxY())) { return false }
28828 }
28829 var prevX = seq.getX(0);
28830 var prevY = seq.getY(0);
28831 for (var i$1 = 1; i$1 <= 4; i$1++) {
28832 var x$1 = seq.getX(i$1);
28833 var y$1 = seq.getY(i$1);
28834 var xChanged = x$1 !== prevX;
28835 var yChanged = y$1 !== prevY;
28836 if (xChanged === yChanged) { return false }
28837 prevX = x$1;
28838 prevY = y$1;
28839 }
28840 return true
28841 };
28842 Polygon.prototype.equalsExact = function equalsExact () {
28843 var this$1 = this;
28844
28845 if (arguments.length === 2) {
28846 var other = arguments[0];
28847 var tolerance = arguments[1];
28848 if (!this.isEquivalentClass(other)) {
28849 return false
28850 }
28851 var otherPolygon = other;
28852 var thisShell = this._shell;
28853 var otherPolygonShell = otherPolygon._shell;
28854 if (!thisShell.equalsExact(otherPolygonShell, tolerance)) {
28855 return false
28856 }
28857 if (this._holes.length !== otherPolygon._holes.length) {
28858 return false
28859 }
28860 for (var i = 0; i < this._holes.length; i++) {
28861 if (!this$1._holes[i].equalsExact(otherPolygon._holes[i], tolerance)) {
28862 return false
28863 }
28864 }
28865 return true
28866 } else { return Geometry$$1.prototype.equalsExact.apply(this, arguments) }
28867 };
28868 Polygon.prototype.normalize = function normalize () {
28869 var this$1 = this;
28870
28871 if (arguments.length === 0) {
28872 this.normalize(this._shell, true);
28873 for (var i = 0; i < this._holes.length; i++) {
28874 this$1.normalize(this$1._holes[i], false);
28875 }
28876 Arrays.sort(this._holes);
28877 } else if (arguments.length === 2) {
28878 var ring = arguments[0];
28879 var clockwise = arguments[1];
28880 if (ring.isEmpty()) {
28881 return null
28882 }
28883 var uniqueCoordinates = new Array(ring.getCoordinates().length - 1).fill(null);
28884 System.arraycopy(ring.getCoordinates(), 0, uniqueCoordinates, 0, uniqueCoordinates.length);
28885 var minCoordinate = CoordinateArrays.minCoordinate(ring.getCoordinates());
28886 CoordinateArrays.scroll(uniqueCoordinates, minCoordinate);
28887 System.arraycopy(uniqueCoordinates, 0, ring.getCoordinates(), 0, uniqueCoordinates.length);
28888 ring.getCoordinates()[uniqueCoordinates.length] = uniqueCoordinates[0];
28889 if (CGAlgorithms.isCCW(ring.getCoordinates()) === clockwise) {
28890 CoordinateArrays.reverse(ring.getCoordinates());
28891 }
28892 }
28893 };
28894 Polygon.prototype.getCoordinate = function getCoordinate () {
28895 return this._shell.getCoordinate()
28896 };
28897 Polygon.prototype.getNumInteriorRing = function getNumInteriorRing () {
28898 return this._holes.length
28899 };
28900 Polygon.prototype.getBoundaryDimension = function getBoundaryDimension () {
28901 return 1
28902 };
28903 Polygon.prototype.getDimension = function getDimension () {
28904 return 2
28905 };
28906 Polygon.prototype.getLength = function getLength () {
28907 var this$1 = this;
28908
28909 var len = 0.0;
28910 len += this._shell.getLength();
28911 for (var i = 0; i < this._holes.length; i++) {
28912 len += this$1._holes[i].getLength();
28913 }
28914 return len
28915 };
28916 Polygon.prototype.getNumPoints = function getNumPoints () {
28917 var this$1 = this;
28918
28919 var numPoints = this._shell.getNumPoints();
28920 for (var i = 0; i < this._holes.length; i++) {
28921 numPoints += this$1._holes[i].getNumPoints();
28922 }
28923 return numPoints
28924 };
28925 Polygon.prototype.reverse = function reverse () {
28926 var this$1 = this;
28927
28928 var poly = this.copy();
28929 poly._shell = this._shell.copy().reverse();
28930 poly._holes = new Array(this._holes.length).fill(null);
28931 for (var i = 0; i < this._holes.length; i++) {
28932 poly._holes[i] = this$1._holes[i].copy().reverse();
28933 }
28934 return poly
28935 };
28936 Polygon.prototype.convexHull = function convexHull () {
28937 return this.getExteriorRing().convexHull()
28938 };
28939 Polygon.prototype.compareToSameClass = function compareToSameClass () {
28940 var this$1 = this;
28941
28942 if (arguments.length === 1) {
28943 var o = arguments[0];
28944 var thisShell = this._shell;
28945 var otherShell = o._shell;
28946 return thisShell.compareToSameClass(otherShell)
28947 } else if (arguments.length === 2) {
28948 var o$1 = arguments[0];
28949 var comp = arguments[1];
28950 var poly = o$1;
28951 var thisShell$1 = this._shell;
28952 var otherShell$1 = poly._shell;
28953 var shellComp = thisShell$1.compareToSameClass(otherShell$1, comp);
28954 if (shellComp !== 0) { return shellComp }
28955 var nHole1 = this.getNumInteriorRing();
28956 var nHole2 = poly.getNumInteriorRing();
28957 var i = 0;
28958 while (i < nHole1 && i < nHole2) {
28959 var thisHole = this$1.getInteriorRingN(i);
28960 var otherHole = poly.getInteriorRingN(i);
28961 var holeComp = thisHole.compareToSameClass(otherHole, comp);
28962 if (holeComp !== 0) { return holeComp }
28963 i++;
28964 }
28965 if (i < nHole1) { return 1 }
28966 if (i < nHole2) { return -1 }
28967 return 0
28968 }
28969 };
28970 Polygon.prototype.apply = function apply (filter) {
28971 var this$1 = this;
28972
28973 if (hasInterface(filter, CoordinateFilter)) {
28974 this._shell.apply(filter);
28975 for (var i$1 = 0; i$1 < this._holes.length; i$1++) {
28976 this$1._holes[i$1].apply(filter);
28977 }
28978 } else if (hasInterface(filter, CoordinateSequenceFilter)) {
28979 this._shell.apply(filter);
28980 if (!filter.isDone()) {
28981 for (var i$2 = 0; i$2 < this._holes.length; i$2++) {
28982 this$1._holes[i$2].apply(filter);
28983 if (filter.isDone()) { break }
28984 }
28985 }
28986 if (filter.isGeometryChanged()) { this.geometryChanged(); }
28987 } else if (hasInterface(filter, GeometryFilter)) {
28988 filter.filter(this);
28989 } else if (hasInterface(filter, GeometryComponentFilter)) {
28990 filter.filter(this);
28991 this._shell.apply(filter);
28992 for (var i = 0; i < this._holes.length; i++) {
28993 this$1._holes[i].apply(filter);
28994 }
28995 }
28996 };
28997 Polygon.prototype.getBoundary = function getBoundary () {
28998 var this$1 = this;
28999
29000 if (this.isEmpty()) {
29001 return this.getFactory().createMultiLineString()
29002 }
29003 var rings = new Array(this._holes.length + 1).fill(null);
29004 rings[0] = this._shell;
29005 for (var i = 0; i < this._holes.length; i++) {
29006 rings[i + 1] = this$1._holes[i];
29007 }
29008 if (rings.length <= 1) { return this.getFactory().createLinearRing(rings[0].getCoordinateSequence()) }
29009 return this.getFactory().createMultiLineString(rings)
29010 };
29011 Polygon.prototype.clone = function clone () {
29012 var this$1 = this;
29013
29014 var poly = Geometry$$1.prototype.clone.call(this);
29015 poly._shell = this._shell.clone();
29016 poly._holes = new Array(this._holes.length).fill(null);
29017 for (var i = 0; i < this._holes.length; i++) {
29018 poly._holes[i] = this$1._holes[i].clone();
29019 }
29020 return poly
29021 };
29022 Polygon.prototype.getGeometryType = function getGeometryType () {
29023 return 'Polygon'
29024 };
29025 Polygon.prototype.copy = function copy () {
29026 var this$1 = this;
29027
29028 var shell = this._shell.copy();
29029 var holes = new Array(this._holes.length).fill(null);
29030 for (var i = 0; i < holes.length; i++) {
29031 holes[i] = this$1._holes[i].copy();
29032 }
29033 return new Polygon(shell, holes, this._factory)
29034 };
29035 Polygon.prototype.getExteriorRing = function getExteriorRing () {
29036 return this._shell
29037 };
29038 Polygon.prototype.isEmpty = function isEmpty () {
29039 return this._shell.isEmpty()
29040 };
29041 Polygon.prototype.getInteriorRingN = function getInteriorRingN (n) {
29042 return this._holes[n]
29043 };
29044 Polygon.prototype.interfaces_ = function interfaces_ () {
29045 return [Polygonal]
29046 };
29047 Polygon.prototype.getClass = function getClass () {
29048 return Polygon
29049 };
29050 staticAccessors.serialVersionUID.get = function () { return -3494792200821764533 };
29051
29052 Object.defineProperties( Polygon, staticAccessors );
29053
29054 return Polygon;
29055}(Geometry));
29056
29057var MultiPoint = (function (GeometryCollection$$1) {
29058 function MultiPoint () {
29059 GeometryCollection$$1.apply(this, arguments);
29060 }
29061
29062 if ( GeometryCollection$$1 ) MultiPoint.__proto__ = GeometryCollection$$1;
29063 MultiPoint.prototype = Object.create( GeometryCollection$$1 && GeometryCollection$$1.prototype );
29064 MultiPoint.prototype.constructor = MultiPoint;
29065
29066 var staticAccessors = { serialVersionUID: { configurable: true } };
29067
29068 MultiPoint.prototype.getSortIndex = function getSortIndex () {
29069 return Geometry.SORTINDEX_MULTIPOINT
29070 };
29071 MultiPoint.prototype.isValid = function isValid () {
29072 return true
29073 };
29074 MultiPoint.prototype.equalsExact = function equalsExact () {
29075 if (arguments.length === 2) {
29076 var other = arguments[0];
29077 var tolerance = arguments[1];
29078 if (!this.isEquivalentClass(other)) {
29079 return false
29080 }
29081 return GeometryCollection$$1.prototype.equalsExact.call(this, other, tolerance)
29082 } else { return GeometryCollection$$1.prototype.equalsExact.apply(this, arguments) }
29083 };
29084 MultiPoint.prototype.getCoordinate = function getCoordinate () {
29085 if (arguments.length === 1) {
29086 var n = arguments[0];
29087 return this._geometries[n].getCoordinate()
29088 } else { return GeometryCollection$$1.prototype.getCoordinate.apply(this, arguments) }
29089 };
29090 MultiPoint.prototype.getBoundaryDimension = function getBoundaryDimension () {
29091 return Dimension.FALSE
29092 };
29093 MultiPoint.prototype.getDimension = function getDimension () {
29094 return 0
29095 };
29096 MultiPoint.prototype.getBoundary = function getBoundary () {
29097 return this.getFactory().createGeometryCollection(null)
29098 };
29099 MultiPoint.prototype.getGeometryType = function getGeometryType () {
29100 return 'MultiPoint'
29101 };
29102 MultiPoint.prototype.copy = function copy () {
29103 var this$1 = this;
29104
29105 var points = new Array(this._geometries.length).fill(null);
29106 for (var i = 0; i < points.length; i++) {
29107 points[i] = this$1._geometries[i].copy();
29108 }
29109 return new MultiPoint(points, this._factory)
29110 };
29111 MultiPoint.prototype.interfaces_ = function interfaces_ () {
29112 return [Puntal]
29113 };
29114 MultiPoint.prototype.getClass = function getClass () {
29115 return MultiPoint
29116 };
29117 staticAccessors.serialVersionUID.get = function () { return -8048474874175355449 };
29118
29119 Object.defineProperties( MultiPoint, staticAccessors );
29120
29121 return MultiPoint;
29122}(GeometryCollection));
29123
29124var LinearRing = (function (LineString$$1) {
29125 function LinearRing (points, factory) {
29126 if (points instanceof Coordinate && factory instanceof GeometryFactory) {
29127 points = factory.getCoordinateSequenceFactory().create(points);
29128 }
29129 LineString$$1.call(this, points, factory);
29130 this.validateConstruction();
29131 }
29132
29133 if ( LineString$$1 ) LinearRing.__proto__ = LineString$$1;
29134 LinearRing.prototype = Object.create( LineString$$1 && LineString$$1.prototype );
29135 LinearRing.prototype.constructor = LinearRing;
29136
29137 var staticAccessors = { MINIMUM_VALID_SIZE: { configurable: true },serialVersionUID: { configurable: true } };
29138 LinearRing.prototype.getSortIndex = function getSortIndex () {
29139 return Geometry.SORTINDEX_LINEARRING
29140 };
29141 LinearRing.prototype.getBoundaryDimension = function getBoundaryDimension () {
29142 return Dimension.FALSE
29143 };
29144 LinearRing.prototype.isClosed = function isClosed () {
29145 if (this.isEmpty()) {
29146 return true
29147 }
29148 return LineString$$1.prototype.isClosed.call(this)
29149 };
29150 LinearRing.prototype.reverse = function reverse () {
29151 var seq = this._points.copy();
29152 CoordinateSequences.reverse(seq);
29153 var rev = this.getFactory().createLinearRing(seq);
29154 return rev
29155 };
29156 LinearRing.prototype.validateConstruction = function validateConstruction () {
29157 if (!this.isEmpty() && !LineString$$1.prototype.isClosed.call(this)) {
29158 throw new IllegalArgumentException('Points of LinearRing do not form a closed linestring')
29159 }
29160 if (this.getCoordinateSequence().size() >= 1 && this.getCoordinateSequence().size() < LinearRing.MINIMUM_VALID_SIZE) {
29161 throw new IllegalArgumentException('Invalid number of points in LinearRing (found ' + this.getCoordinateSequence().size() + ' - must be 0 or >= 4)')
29162 }
29163 };
29164 LinearRing.prototype.getGeometryType = function getGeometryType () {
29165 return 'LinearRing'
29166 };
29167 LinearRing.prototype.copy = function copy () {
29168 return new LinearRing(this._points.copy(), this._factory)
29169 };
29170 LinearRing.prototype.interfaces_ = function interfaces_ () {
29171 return []
29172 };
29173 LinearRing.prototype.getClass = function getClass () {
29174 return LinearRing
29175 };
29176 staticAccessors.MINIMUM_VALID_SIZE.get = function () { return 4 };
29177 staticAccessors.serialVersionUID.get = function () { return -4261142084085851829 };
29178
29179 Object.defineProperties( LinearRing, staticAccessors );
29180
29181 return LinearRing;
29182}(LineString$1));
29183
29184var MultiPolygon = (function (GeometryCollection$$1) {
29185 function MultiPolygon () {
29186 GeometryCollection$$1.apply(this, arguments);
29187 }
29188
29189 if ( GeometryCollection$$1 ) MultiPolygon.__proto__ = GeometryCollection$$1;
29190 MultiPolygon.prototype = Object.create( GeometryCollection$$1 && GeometryCollection$$1.prototype );
29191 MultiPolygon.prototype.constructor = MultiPolygon;
29192
29193 var staticAccessors = { serialVersionUID: { configurable: true } };
29194
29195 MultiPolygon.prototype.getSortIndex = function getSortIndex () {
29196 return Geometry.SORTINDEX_MULTIPOLYGON
29197 };
29198 MultiPolygon.prototype.equalsExact = function equalsExact () {
29199 if (arguments.length === 2) {
29200 var other = arguments[0];
29201 var tolerance = arguments[1];
29202 if (!this.isEquivalentClass(other)) {
29203 return false
29204 }
29205 return GeometryCollection$$1.prototype.equalsExact.call(this, other, tolerance)
29206 } else { return GeometryCollection$$1.prototype.equalsExact.apply(this, arguments) }
29207 };
29208 MultiPolygon.prototype.getBoundaryDimension = function getBoundaryDimension () {
29209 return 1
29210 };
29211 MultiPolygon.prototype.getDimension = function getDimension () {
29212 return 2
29213 };
29214 MultiPolygon.prototype.reverse = function reverse () {
29215 var this$1 = this;
29216
29217 var n = this._geometries.length;
29218 var revGeoms = new Array(n).fill(null);
29219 for (var i = 0; i < this._geometries.length; i++) {
29220 revGeoms[i] = this$1._geometries[i].reverse();
29221 }
29222 return this.getFactory().createMultiPolygon(revGeoms)
29223 };
29224 MultiPolygon.prototype.getBoundary = function getBoundary () {
29225 var this$1 = this;
29226
29227 if (this.isEmpty()) {
29228 return this.getFactory().createMultiLineString()
29229 }
29230 var allRings = new ArrayList();
29231 for (var i = 0; i < this._geometries.length; i++) {
29232 var polygon = this$1._geometries[i];
29233 var rings = polygon.getBoundary();
29234 for (var j = 0; j < rings.getNumGeometries(); j++) {
29235 allRings.add(rings.getGeometryN(j));
29236 }
29237 }
29238 var allRingsArray = new Array(allRings.size()).fill(null);
29239 return this.getFactory().createMultiLineString(allRings.toArray(allRingsArray))
29240 };
29241 MultiPolygon.prototype.getGeometryType = function getGeometryType () {
29242 return 'MultiPolygon'
29243 };
29244 MultiPolygon.prototype.copy = function copy () {
29245 var this$1 = this;
29246
29247 var polygons = new Array(this._geometries.length).fill(null);
29248 for (var i = 0; i < polygons.length; i++) {
29249 polygons[i] = this$1._geometries[i].copy();
29250 }
29251 return new MultiPolygon(polygons, this._factory)
29252 };
29253 MultiPolygon.prototype.interfaces_ = function interfaces_ () {
29254 return [Polygonal]
29255 };
29256 MultiPolygon.prototype.getClass = function getClass () {
29257 return MultiPolygon
29258 };
29259 staticAccessors.serialVersionUID.get = function () { return -551033529766975875 };
29260
29261 Object.defineProperties( MultiPolygon, staticAccessors );
29262
29263 return MultiPolygon;
29264}(GeometryCollection));
29265
29266var GeometryEditor = function GeometryEditor (factory) {
29267 this._factory = factory || null;
29268 this._isUserDataCopied = false;
29269};
29270
29271var staticAccessors$16 = { NoOpGeometryOperation: { configurable: true },CoordinateOperation: { configurable: true },CoordinateSequenceOperation: { configurable: true } };
29272GeometryEditor.prototype.setCopyUserData = function setCopyUserData (isUserDataCopied) {
29273 this._isUserDataCopied = isUserDataCopied;
29274};
29275GeometryEditor.prototype.edit = function edit (geometry, operation) {
29276 if (geometry === null) { return null }
29277 var result = this.editInternal(geometry, operation);
29278 if (this._isUserDataCopied) {
29279 result.setUserData(geometry.getUserData());
29280 }
29281 return result
29282};
29283GeometryEditor.prototype.editInternal = function editInternal (geometry, operation) {
29284 if (this._factory === null) { this._factory = geometry.getFactory(); }
29285 if (geometry instanceof GeometryCollection) {
29286 return this.editGeometryCollection(geometry, operation)
29287 }
29288 if (geometry instanceof Polygon) {
29289 return this.editPolygon(geometry, operation)
29290 }
29291 if (geometry instanceof Point) {
29292 return operation.edit(geometry, this._factory)
29293 }
29294 if (geometry instanceof LineString$1) {
29295 return operation.edit(geometry, this._factory)
29296 }
29297 Assert.shouldNeverReachHere('Unsupported Geometry class: ' + geometry.getClass().getName());
29298 return null
29299};
29300GeometryEditor.prototype.editGeometryCollection = function editGeometryCollection (collection, operation) {
29301 var this$1 = this;
29302
29303 var collectionForType = operation.edit(collection, this._factory);
29304 var geometries = new ArrayList();
29305 for (var i = 0; i < collectionForType.getNumGeometries(); i++) {
29306 var geometry = this$1.edit(collectionForType.getGeometryN(i), operation);
29307 if (geometry === null || geometry.isEmpty()) {
29308 continue
29309 }
29310 geometries.add(geometry);
29311 }
29312 if (collectionForType.getClass() === MultiPoint) {
29313 return this._factory.createMultiPoint(geometries.toArray([]))
29314 }
29315 if (collectionForType.getClass() === MultiLineString) {
29316 return this._factory.createMultiLineString(geometries.toArray([]))
29317 }
29318 if (collectionForType.getClass() === MultiPolygon) {
29319 return this._factory.createMultiPolygon(geometries.toArray([]))
29320 }
29321 return this._factory.createGeometryCollection(geometries.toArray([]))
29322};
29323GeometryEditor.prototype.editPolygon = function editPolygon (polygon, operation) {
29324 var this$1 = this;
29325
29326 var newPolygon = operation.edit(polygon, this._factory);
29327 if (newPolygon === null) { newPolygon = this._factory.createPolygon(null); }
29328 if (newPolygon.isEmpty()) {
29329 return newPolygon
29330 }
29331 var shell = this.edit(newPolygon.getExteriorRing(), operation);
29332 if (shell === null || shell.isEmpty()) {
29333 return this._factory.createPolygon()
29334 }
29335 var holes = new ArrayList();
29336 for (var i = 0; i < newPolygon.getNumInteriorRing(); i++) {
29337 var hole = this$1.edit(newPolygon.getInteriorRingN(i), operation);
29338 if (hole === null || hole.isEmpty()) {
29339 continue
29340 }
29341 holes.add(hole);
29342 }
29343 return this._factory.createPolygon(shell, holes.toArray([]))
29344};
29345GeometryEditor.prototype.interfaces_ = function interfaces_ () {
29346 return []
29347};
29348GeometryEditor.prototype.getClass = function getClass () {
29349 return GeometryEditor
29350};
29351GeometryEditor.GeometryEditorOperation = function GeometryEditorOperation () {};
29352staticAccessors$16.NoOpGeometryOperation.get = function () { return NoOpGeometryOperation };
29353staticAccessors$16.CoordinateOperation.get = function () { return CoordinateOperation };
29354staticAccessors$16.CoordinateSequenceOperation.get = function () { return CoordinateSequenceOperation };
29355
29356Object.defineProperties( GeometryEditor, staticAccessors$16 );
29357
29358var NoOpGeometryOperation = function NoOpGeometryOperation () {};
29359
29360NoOpGeometryOperation.prototype.edit = function edit (geometry, factory) {
29361 return geometry
29362};
29363NoOpGeometryOperation.prototype.interfaces_ = function interfaces_ () {
29364 return [GeometryEditor.GeometryEditorOperation]
29365};
29366NoOpGeometryOperation.prototype.getClass = function getClass () {
29367 return NoOpGeometryOperation
29368};
29369
29370var CoordinateOperation = function CoordinateOperation () {};
29371
29372CoordinateOperation.prototype.edit = function edit (geometry, factory) {
29373 var coords = this.editCoordinates(geometry.getCoordinates(), geometry);
29374 if (coords === null) { return geometry }
29375 if (geometry instanceof LinearRing) {
29376 return factory.createLinearRing(coords)
29377 }
29378 if (geometry instanceof LineString$1) {
29379 return factory.createLineString(coords)
29380 }
29381 if (geometry instanceof Point) {
29382 if (coords.length > 0) {
29383 return factory.createPoint(coords[0])
29384 } else {
29385 return factory.createPoint()
29386 }
29387 }
29388 return geometry
29389};
29390CoordinateOperation.prototype.interfaces_ = function interfaces_ () {
29391 return [GeometryEditor.GeometryEditorOperation]
29392};
29393CoordinateOperation.prototype.getClass = function getClass () {
29394 return CoordinateOperation
29395};
29396
29397var CoordinateSequenceOperation = function CoordinateSequenceOperation () {};
29398
29399CoordinateSequenceOperation.prototype.edit = function edit (geometry, factory) {
29400 if (geometry instanceof LinearRing) {
29401 return factory.createLinearRing(this.edit(geometry.getCoordinateSequence(), geometry))
29402 }
29403 if (geometry instanceof LineString$1) {
29404 return factory.createLineString(this.edit(geometry.getCoordinateSequence(), geometry))
29405 }
29406 if (geometry instanceof Point) {
29407 return factory.createPoint(this.edit(geometry.getCoordinateSequence(), geometry))
29408 }
29409 return geometry
29410};
29411CoordinateSequenceOperation.prototype.interfaces_ = function interfaces_ () {
29412 return [GeometryEditor.GeometryEditorOperation]
29413};
29414CoordinateSequenceOperation.prototype.getClass = function getClass () {
29415 return CoordinateSequenceOperation
29416};
29417
29418var CoordinateArraySequence = function CoordinateArraySequence () {
29419 var this$1 = this;
29420
29421 this._dimension = 3;
29422 this._coordinates = null;
29423 if (arguments.length === 1) {
29424 if (arguments[0] instanceof Array) {
29425 this._coordinates = arguments[0];
29426 this._dimension = 3;
29427 } else if (Number.isInteger(arguments[0])) {
29428 var size = arguments[0];
29429 this._coordinates = new Array(size).fill(null);
29430 for (var i = 0; i < size; i++) {
29431 this$1._coordinates[i] = new Coordinate();
29432 }
29433 } else if (hasInterface(arguments[0], CoordinateSequence)) {
29434 var coordSeq = arguments[0];
29435 if (coordSeq === null) {
29436 this._coordinates = new Array(0).fill(null);
29437 return null
29438 }
29439 this._dimension = coordSeq.getDimension();
29440 this._coordinates = new Array(coordSeq.size()).fill(null);
29441 for (var i$1 = 0; i$1 < this._coordinates.length; i$1++) {
29442 this$1._coordinates[i$1] = coordSeq.getCoordinateCopy(i$1);
29443 }
29444 }
29445 } else if (arguments.length === 2) {
29446 if (arguments[0] instanceof Array && Number.isInteger(arguments[1])) {
29447 var coordinates = arguments[0];
29448 var dimension = arguments[1];
29449 this._coordinates = coordinates;
29450 this._dimension = dimension;
29451 if (coordinates === null) { this._coordinates = new Array(0).fill(null); }
29452 } else if (Number.isInteger(arguments[0]) && Number.isInteger(arguments[1])) {
29453 var size$1 = arguments[0];
29454 var dimension$1 = arguments[1];
29455 this._coordinates = new Array(size$1).fill(null);
29456 this._dimension = dimension$1;
29457 for (var i$2 = 0; i$2 < size$1; i$2++) {
29458 this$1._coordinates[i$2] = new Coordinate();
29459 }
29460 }
29461 }
29462};
29463
29464var staticAccessors$18 = { serialVersionUID: { configurable: true } };
29465CoordinateArraySequence.prototype.setOrdinate = function setOrdinate (index, ordinateIndex, value) {
29466 switch (ordinateIndex) {
29467 case CoordinateSequence.X:
29468 this._coordinates[index].x = value;
29469 break
29470 case CoordinateSequence.Y:
29471 this._coordinates[index].y = value;
29472 break
29473 case CoordinateSequence.Z:
29474 this._coordinates[index].z = value;
29475 break
29476 default:
29477 throw new IllegalArgumentException('invalid ordinateIndex')
29478 }
29479};
29480CoordinateArraySequence.prototype.size = function size () {
29481 return this._coordinates.length
29482};
29483CoordinateArraySequence.prototype.getOrdinate = function getOrdinate (index, ordinateIndex) {
29484 switch (ordinateIndex) {
29485 case CoordinateSequence.X:
29486 return this._coordinates[index].x
29487 case CoordinateSequence.Y:
29488 return this._coordinates[index].y
29489 case CoordinateSequence.Z:
29490 return this._coordinates[index].z
29491 default:
29492 }
29493 return Double.NaN
29494};
29495CoordinateArraySequence.prototype.getCoordinate = function getCoordinate () {
29496 if (arguments.length === 1) {
29497 var i = arguments[0];
29498 return this._coordinates[i]
29499 } else if (arguments.length === 2) {
29500 var index = arguments[0];
29501 var coord = arguments[1];
29502 coord.x = this._coordinates[index].x;
29503 coord.y = this._coordinates[index].y;
29504 coord.z = this._coordinates[index].z;
29505 }
29506};
29507CoordinateArraySequence.prototype.getCoordinateCopy = function getCoordinateCopy (i) {
29508 return new Coordinate(this._coordinates[i])
29509};
29510CoordinateArraySequence.prototype.getDimension = function getDimension () {
29511 return this._dimension
29512};
29513CoordinateArraySequence.prototype.getX = function getX (index) {
29514 return this._coordinates[index].x
29515};
29516CoordinateArraySequence.prototype.clone = function clone () {
29517 var this$1 = this;
29518
29519 var cloneCoordinates = new Array(this.size()).fill(null);
29520 for (var i = 0; i < this._coordinates.length; i++) {
29521 cloneCoordinates[i] = this$1._coordinates[i].clone();
29522 }
29523 return new CoordinateArraySequence(cloneCoordinates, this._dimension)
29524};
29525CoordinateArraySequence.prototype.expandEnvelope = function expandEnvelope (env) {
29526 var this$1 = this;
29527
29528 for (var i = 0; i < this._coordinates.length; i++) {
29529 env.expandToInclude(this$1._coordinates[i]);
29530 }
29531 return env
29532};
29533CoordinateArraySequence.prototype.copy = function copy () {
29534 var this$1 = this;
29535
29536 var cloneCoordinates = new Array(this.size()).fill(null);
29537 for (var i = 0; i < this._coordinates.length; i++) {
29538 cloneCoordinates[i] = this$1._coordinates[i].copy();
29539 }
29540 return new CoordinateArraySequence(cloneCoordinates, this._dimension)
29541};
29542CoordinateArraySequence.prototype.toString = function toString () {
29543 var this$1 = this;
29544
29545 if (this._coordinates.length > 0) {
29546 var strBuf = new StringBuffer(17 * this._coordinates.length);
29547 strBuf.append('(');
29548 strBuf.append(this._coordinates[0]);
29549 for (var i = 1; i < this._coordinates.length; i++) {
29550 strBuf.append(', ');
29551 strBuf.append(this$1._coordinates[i]);
29552 }
29553 strBuf.append(')');
29554 return strBuf.toString()
29555 } else {
29556 return '()'
29557 }
29558};
29559CoordinateArraySequence.prototype.getY = function getY (index) {
29560 return this._coordinates[index].y
29561};
29562CoordinateArraySequence.prototype.toCoordinateArray = function toCoordinateArray () {
29563 return this._coordinates
29564};
29565CoordinateArraySequence.prototype.interfaces_ = function interfaces_ () {
29566 return [CoordinateSequence, Serializable]
29567};
29568CoordinateArraySequence.prototype.getClass = function getClass () {
29569 return CoordinateArraySequence
29570};
29571staticAccessors$18.serialVersionUID.get = function () { return -915438501601840650 };
29572
29573Object.defineProperties( CoordinateArraySequence, staticAccessors$18 );
29574
29575var CoordinateArraySequenceFactory = function CoordinateArraySequenceFactory () {};
29576
29577var staticAccessors$17 = { serialVersionUID: { configurable: true },instanceObject: { configurable: true } };
29578
29579CoordinateArraySequenceFactory.prototype.readResolve = function readResolve () {
29580 return CoordinateArraySequenceFactory.instance()
29581};
29582CoordinateArraySequenceFactory.prototype.create = function create () {
29583 if (arguments.length === 1) {
29584 if (arguments[0] instanceof Array) {
29585 var coordinates = arguments[0];
29586 return new CoordinateArraySequence(coordinates)
29587 } else if (hasInterface(arguments[0], CoordinateSequence)) {
29588 var coordSeq = arguments[0];
29589 return new CoordinateArraySequence(coordSeq)
29590 }
29591 } else if (arguments.length === 2) {
29592 var size = arguments[0];
29593 var dimension = arguments[1];
29594 if (dimension > 3) { dimension = 3; }
29595 if (dimension < 2) { return new CoordinateArraySequence(size) }
29596 return new CoordinateArraySequence(size, dimension)
29597 }
29598};
29599CoordinateArraySequenceFactory.prototype.interfaces_ = function interfaces_ () {
29600 return [CoordinateSequenceFactory, Serializable]
29601};
29602CoordinateArraySequenceFactory.prototype.getClass = function getClass () {
29603 return CoordinateArraySequenceFactory
29604};
29605CoordinateArraySequenceFactory.instance = function instance () {
29606 return CoordinateArraySequenceFactory.instanceObject
29607};
29608
29609staticAccessors$17.serialVersionUID.get = function () { return -4099577099607551657 };
29610staticAccessors$17.instanceObject.get = function () { return new CoordinateArraySequenceFactory() };
29611
29612Object.defineProperties( CoordinateArraySequenceFactory, staticAccessors$17 );
29613
29614/**
29615 * @see http://download.oracle.com/javase/6/docs/api/java/util/HashMap.html
29616 *
29617 * @extends {javascript.util.Map}
29618 * @constructor
29619 * @private
29620 */
29621var HashMap = (function (MapInterface) {
29622 function HashMap () {
29623 MapInterface.call(this);
29624 this.map_ = new Map();
29625 }
29626
29627 if ( MapInterface ) HashMap.__proto__ = MapInterface;
29628 HashMap.prototype = Object.create( MapInterface && MapInterface.prototype );
29629 HashMap.prototype.constructor = HashMap;
29630 /**
29631 * @override
29632 */
29633 HashMap.prototype.get = function get (key) {
29634 return this.map_.get(key) || null
29635 };
29636
29637 /**
29638 * @override
29639 */
29640 HashMap.prototype.put = function put (key, value) {
29641 this.map_.set(key, value);
29642 return value
29643 };
29644
29645 /**
29646 * @override
29647 */
29648 HashMap.prototype.values = function values () {
29649 var arrayList = new ArrayList();
29650 var it = this.map_.values();
29651 var o = it.next();
29652 while (!o.done) {
29653 arrayList.add(o.value);
29654 o = it.next();
29655 }
29656 return arrayList
29657 };
29658
29659 /**
29660 * @override
29661 */
29662 HashMap.prototype.entrySet = function entrySet () {
29663 var hashSet = new HashSet();
29664 this.map_.entries().forEach(function (entry) { return hashSet.add(entry); });
29665 return hashSet
29666 };
29667
29668 /**
29669 * @override
29670 */
29671 HashMap.prototype.size = function size () {
29672 return this.map_.size()
29673 };
29674
29675 return HashMap;
29676}(Map$1));
29677
29678var PrecisionModel = function PrecisionModel () {
29679 this._modelType = null;
29680 this._scale = null;
29681 if (arguments.length === 0) {
29682 this._modelType = PrecisionModel.FLOATING;
29683 } else if (arguments.length === 1) {
29684 if (arguments[0] instanceof Type) {
29685 var modelType = arguments[0];
29686 this._modelType = modelType;
29687 if (modelType === PrecisionModel.FIXED) {
29688 this.setScale(1.0);
29689 }
29690 } else if (typeof arguments[0] === 'number') {
29691 var scale = arguments[0];
29692 this._modelType = PrecisionModel.FIXED;
29693 this.setScale(scale);
29694 } else if (arguments[0] instanceof PrecisionModel) {
29695 var pm = arguments[0];
29696 this._modelType = pm._modelType;
29697 this._scale = pm._scale;
29698 }
29699 }
29700};
29701
29702var staticAccessors$19 = { serialVersionUID: { configurable: true },maximumPreciseValue: { configurable: true } };
29703PrecisionModel.prototype.equals = function equals (other) {
29704 if (!(other instanceof PrecisionModel)) {
29705 return false
29706 }
29707 var otherPrecisionModel = other;
29708 return this._modelType === otherPrecisionModel._modelType && this._scale === otherPrecisionModel._scale
29709};
29710PrecisionModel.prototype.compareTo = function compareTo (o) {
29711 var other = o;
29712 var sigDigits = this.getMaximumSignificantDigits();
29713 var otherSigDigits = other.getMaximumSignificantDigits();
29714 return new Integer(sigDigits).compareTo(new Integer(otherSigDigits))
29715};
29716PrecisionModel.prototype.getScale = function getScale () {
29717 return this._scale
29718};
29719PrecisionModel.prototype.isFloating = function isFloating () {
29720 return this._modelType === PrecisionModel.FLOATING || this._modelType === PrecisionModel.FLOATING_SINGLE
29721};
29722PrecisionModel.prototype.getType = function getType () {
29723 return this._modelType
29724};
29725PrecisionModel.prototype.toString = function toString () {
29726 var description = 'UNKNOWN';
29727 if (this._modelType === PrecisionModel.FLOATING) {
29728 description = 'Floating';
29729 } else if (this._modelType === PrecisionModel.FLOATING_SINGLE) {
29730 description = 'Floating-Single';
29731 } else if (this._modelType === PrecisionModel.FIXED) {
29732 description = 'Fixed (Scale=' + this.getScale() + ')';
29733 }
29734 return description
29735};
29736PrecisionModel.prototype.makePrecise = function makePrecise () {
29737 if (typeof arguments[0] === 'number') {
29738 var val = arguments[0];
29739 if (Double.isNaN(val)) { return val }
29740 if (this._modelType === PrecisionModel.FLOATING_SINGLE) {
29741 var floatSingleVal = val;
29742 return floatSingleVal
29743 }
29744 if (this._modelType === PrecisionModel.FIXED) {
29745 return Math.round(val * this._scale) / this._scale
29746 }
29747 return val
29748 } else if (arguments[0] instanceof Coordinate) {
29749 var coord = arguments[0];
29750 if (this._modelType === PrecisionModel.FLOATING) { return null }
29751 coord.x = this.makePrecise(coord.x);
29752 coord.y = this.makePrecise(coord.y);
29753 }
29754};
29755PrecisionModel.prototype.getMaximumSignificantDigits = function getMaximumSignificantDigits () {
29756 var maxSigDigits = 16;
29757 if (this._modelType === PrecisionModel.FLOATING) {
29758 maxSigDigits = 16;
29759 } else if (this._modelType === PrecisionModel.FLOATING_SINGLE) {
29760 maxSigDigits = 6;
29761 } else if (this._modelType === PrecisionModel.FIXED) {
29762 maxSigDigits = 1 + Math.trunc(Math.ceil(Math.log(this.getScale()) / Math.log(10)));
29763 }
29764 return maxSigDigits
29765};
29766PrecisionModel.prototype.setScale = function setScale (scale) {
29767 this._scale = Math.abs(scale);
29768};
29769PrecisionModel.prototype.interfaces_ = function interfaces_ () {
29770 return [Serializable, Comparable]
29771};
29772PrecisionModel.prototype.getClass = function getClass () {
29773 return PrecisionModel
29774};
29775PrecisionModel.mostPrecise = function mostPrecise (pm1, pm2) {
29776 if (pm1.compareTo(pm2) >= 0) { return pm1 }
29777 return pm2
29778};
29779staticAccessors$19.serialVersionUID.get = function () { return 7777263578777803835 };
29780staticAccessors$19.maximumPreciseValue.get = function () { return 9007199254740992.0 };
29781
29782Object.defineProperties( PrecisionModel, staticAccessors$19 );
29783
29784var Type = function Type (name) {
29785 this._name = name || null;
29786 Type.nameToTypeMap.put(name, this);
29787};
29788
29789var staticAccessors$1$1 = { serialVersionUID: { configurable: true },nameToTypeMap: { configurable: true } };
29790Type.prototype.readResolve = function readResolve () {
29791 return Type.nameToTypeMap.get(this._name)
29792};
29793Type.prototype.toString = function toString () {
29794 return this._name
29795};
29796Type.prototype.interfaces_ = function interfaces_ () {
29797 return [Serializable]
29798};
29799Type.prototype.getClass = function getClass () {
29800 return Type
29801};
29802staticAccessors$1$1.serialVersionUID.get = function () { return -5528602631731589822 };
29803staticAccessors$1$1.nameToTypeMap.get = function () { return new HashMap() };
29804
29805Object.defineProperties( Type, staticAccessors$1$1 );
29806
29807PrecisionModel.Type = Type;
29808PrecisionModel.FIXED = new Type('FIXED');
29809PrecisionModel.FLOATING = new Type('FLOATING');
29810PrecisionModel.FLOATING_SINGLE = new Type('FLOATING SINGLE');
29811
29812var GeometryFactory = function GeometryFactory () {
29813 this._precisionModel = new PrecisionModel();
29814 this._SRID = 0;
29815 this._coordinateSequenceFactory = GeometryFactory.getDefaultCoordinateSequenceFactory();
29816
29817 if (arguments.length === 0) {
29818 } else if (arguments.length === 1) {
29819 if (hasInterface(arguments[0], CoordinateSequenceFactory)) {
29820 this._coordinateSequenceFactory = arguments[0];
29821 } else if (arguments[0] instanceof PrecisionModel) {
29822 this._precisionModel = arguments[0];
29823 }
29824 } else if (arguments.length === 2) {
29825 this._precisionModel = arguments[0];
29826 this._SRID = arguments[1];
29827 } else if (arguments.length === 3) {
29828 this._precisionModel = arguments[0];
29829 this._SRID = arguments[1];
29830 this._coordinateSequenceFactory = arguments[2];
29831 }
29832};
29833
29834var staticAccessors$2 = { serialVersionUID: { configurable: true } };
29835GeometryFactory.prototype.toGeometry = function toGeometry (envelope) {
29836 if (envelope.isNull()) {
29837 return this.createPoint(null)
29838 }
29839 if (envelope.getMinX() === envelope.getMaxX() && envelope.getMinY() === envelope.getMaxY()) {
29840 return this.createPoint(new Coordinate(envelope.getMinX(), envelope.getMinY()))
29841 }
29842 if (envelope.getMinX() === envelope.getMaxX() || envelope.getMinY() === envelope.getMaxY()) {
29843 return this.createLineString([new Coordinate(envelope.getMinX(), envelope.getMinY()), new Coordinate(envelope.getMaxX(), envelope.getMaxY())])
29844 }
29845 return this.createPolygon(this.createLinearRing([new Coordinate(envelope.getMinX(), envelope.getMinY()), new Coordinate(envelope.getMinX(), envelope.getMaxY()), new Coordinate(envelope.getMaxX(), envelope.getMaxY()), new Coordinate(envelope.getMaxX(), envelope.getMinY()), new Coordinate(envelope.getMinX(), envelope.getMinY())]), null)
29846};
29847GeometryFactory.prototype.createLineString = function createLineString (coordinates) {
29848 if (!coordinates) { return new LineString$1(this.getCoordinateSequenceFactory().create([]), this) }
29849 else if (coordinates instanceof Array) { return new LineString$1(this.getCoordinateSequenceFactory().create(coordinates), this) }
29850 else if (hasInterface(coordinates, CoordinateSequence)) { return new LineString$1(coordinates, this) }
29851};
29852GeometryFactory.prototype.createMultiLineString = function createMultiLineString () {
29853 if (arguments.length === 0) {
29854 return new MultiLineString(null, this)
29855 } else if (arguments.length === 1) {
29856 var lineStrings = arguments[0];
29857 return new MultiLineString(lineStrings, this)
29858 }
29859};
29860GeometryFactory.prototype.buildGeometry = function buildGeometry (geomList) {
29861 var geomClass = null;
29862 var isHeterogeneous = false;
29863 var hasGeometryCollection = false;
29864 for (var i = geomList.iterator(); i.hasNext();) {
29865 var geom = i.next();
29866 var partClass = geom.getClass();
29867 if (geomClass === null) {
29868 geomClass = partClass;
29869 }
29870 if (partClass !== geomClass) {
29871 isHeterogeneous = true;
29872 }
29873 if (geom.isGeometryCollectionOrDerived()) { hasGeometryCollection = true; }
29874 }
29875 if (geomClass === null) {
29876 return this.createGeometryCollection()
29877 }
29878 if (isHeterogeneous || hasGeometryCollection) {
29879 return this.createGeometryCollection(GeometryFactory.toGeometryArray(geomList))
29880 }
29881 var geom0 = geomList.iterator().next();
29882 var isCollection = geomList.size() > 1;
29883 if (isCollection) {
29884 if (geom0 instanceof Polygon) {
29885 return this.createMultiPolygon(GeometryFactory.toPolygonArray(geomList))
29886 } else if (geom0 instanceof LineString$1) {
29887 return this.createMultiLineString(GeometryFactory.toLineStringArray(geomList))
29888 } else if (geom0 instanceof Point) {
29889 return this.createMultiPoint(GeometryFactory.toPointArray(geomList))
29890 }
29891 Assert.shouldNeverReachHere('Unhandled class: ' + geom0.getClass().getName());
29892 }
29893 return geom0
29894};
29895GeometryFactory.prototype.createMultiPointFromCoords = function createMultiPointFromCoords (coordinates) {
29896 return this.createMultiPoint(coordinates !== null ? this.getCoordinateSequenceFactory().create(coordinates) : null)
29897};
29898GeometryFactory.prototype.createPoint = function createPoint () {
29899 if (arguments.length === 0) {
29900 return this.createPoint(this.getCoordinateSequenceFactory().create([]))
29901 } else if (arguments.length === 1) {
29902 if (arguments[0] instanceof Coordinate) {
29903 var coordinate = arguments[0];
29904 return this.createPoint(coordinate !== null ? this.getCoordinateSequenceFactory().create([coordinate]) : null)
29905 } else if (hasInterface(arguments[0], CoordinateSequence)) {
29906 var coordinates = arguments[0];
29907 return new Point(coordinates, this)
29908 }
29909 }
29910};
29911GeometryFactory.prototype.getCoordinateSequenceFactory = function getCoordinateSequenceFactory () {
29912 return this._coordinateSequenceFactory
29913};
29914GeometryFactory.prototype.createPolygon = function createPolygon () {
29915 if (arguments.length === 0) {
29916 return new Polygon(null, null, this)
29917 } else if (arguments.length === 1) {
29918 if (hasInterface(arguments[0], CoordinateSequence)) {
29919 var coordinates = arguments[0];
29920 return this.createPolygon(this.createLinearRing(coordinates))
29921 } else if (arguments[0] instanceof Array) {
29922 var coordinates$1 = arguments[0];
29923 return this.createPolygon(this.createLinearRing(coordinates$1))
29924 } else if (arguments[0] instanceof LinearRing) {
29925 var shell = arguments[0];
29926 return this.createPolygon(shell, null)
29927 }
29928 } else if (arguments.length === 2) {
29929 var shell$1 = arguments[0];
29930 var holes = arguments[1];
29931 return new Polygon(shell$1, holes, this)
29932 }
29933};
29934GeometryFactory.prototype.getSRID = function getSRID () {
29935 return this._SRID
29936};
29937GeometryFactory.prototype.createGeometryCollection = function createGeometryCollection () {
29938 if (arguments.length === 0) {
29939 return new GeometryCollection(null, this)
29940 } else if (arguments.length === 1) {
29941 var geometries = arguments[0];
29942 return new GeometryCollection(geometries, this)
29943 }
29944};
29945GeometryFactory.prototype.createGeometry = function createGeometry (g) {
29946 var editor = new GeometryEditor(this);
29947 return editor.edit(g, {
29948 edit: function () {
29949 if (arguments.length === 2) {
29950 var coordSeq = arguments[0];
29951 // const geometry = arguments[1]
29952 return this._coordinateSequenceFactory.create(coordSeq)
29953 }
29954 }
29955 })
29956};
29957GeometryFactory.prototype.getPrecisionModel = function getPrecisionModel () {
29958 return this._precisionModel
29959};
29960GeometryFactory.prototype.createLinearRing = function createLinearRing () {
29961 if (arguments.length === 0) {
29962 return this.createLinearRing(this.getCoordinateSequenceFactory().create([]))
29963 } else if (arguments.length === 1) {
29964 if (arguments[0] instanceof Array) {
29965 var coordinates = arguments[0];
29966 return this.createLinearRing(coordinates !== null ? this.getCoordinateSequenceFactory().create(coordinates) : null)
29967 } else if (hasInterface(arguments[0], CoordinateSequence)) {
29968 var coordinates$1 = arguments[0];
29969 return new LinearRing(coordinates$1, this)
29970 }
29971 }
29972};
29973GeometryFactory.prototype.createMultiPolygon = function createMultiPolygon () {
29974 if (arguments.length === 0) {
29975 return new MultiPolygon(null, this)
29976 } else if (arguments.length === 1) {
29977 var polygons = arguments[0];
29978 return new MultiPolygon(polygons, this)
29979 }
29980};
29981GeometryFactory.prototype.createMultiPoint = function createMultiPoint () {
29982 var this$1 = this;
29983
29984 if (arguments.length === 0) {
29985 return new MultiPoint(null, this)
29986 } else if (arguments.length === 1) {
29987 if (arguments[0] instanceof Array) {
29988 var point = arguments[0];
29989 return new MultiPoint(point, this)
29990 } else if (arguments[0] instanceof Array) {
29991 var coordinates = arguments[0];
29992 return this.createMultiPoint(coordinates !== null ? this.getCoordinateSequenceFactory().create(coordinates) : null)
29993 } else if (hasInterface(arguments[0], CoordinateSequence)) {
29994 var coordinates$1 = arguments[0];
29995 if (coordinates$1 === null) {
29996 return this.createMultiPoint(new Array(0).fill(null))
29997 }
29998 var points = new Array(coordinates$1.size()).fill(null);
29999 for (var i = 0; i < coordinates$1.size(); i++) {
30000 var ptSeq = this$1.getCoordinateSequenceFactory().create(1, coordinates$1.getDimension());
30001 CoordinateSequences.copy(coordinates$1, i, ptSeq, 0, 1);
30002 points[i] = this$1.createPoint(ptSeq);
30003 }
30004 return this.createMultiPoint(points)
30005 }
30006 }
30007};
30008GeometryFactory.prototype.interfaces_ = function interfaces_ () {
30009 return [Serializable]
30010};
30011GeometryFactory.prototype.getClass = function getClass () {
30012 return GeometryFactory
30013};
30014GeometryFactory.toMultiPolygonArray = function toMultiPolygonArray (multiPolygons) {
30015 var multiPolygonArray = new Array(multiPolygons.size()).fill(null);
30016 return multiPolygons.toArray(multiPolygonArray)
30017};
30018GeometryFactory.toGeometryArray = function toGeometryArray (geometries) {
30019 if (geometries === null) { return null }
30020 var geometryArray = new Array(geometries.size()).fill(null);
30021 return geometries.toArray(geometryArray)
30022};
30023GeometryFactory.getDefaultCoordinateSequenceFactory = function getDefaultCoordinateSequenceFactory () {
30024 return CoordinateArraySequenceFactory.instance()
30025};
30026GeometryFactory.toMultiLineStringArray = function toMultiLineStringArray (multiLineStrings) {
30027 var multiLineStringArray = new Array(multiLineStrings.size()).fill(null);
30028 return multiLineStrings.toArray(multiLineStringArray)
30029};
30030GeometryFactory.toLineStringArray = function toLineStringArray (lineStrings) {
30031 var lineStringArray = new Array(lineStrings.size()).fill(null);
30032 return lineStrings.toArray(lineStringArray)
30033};
30034GeometryFactory.toMultiPointArray = function toMultiPointArray (multiPoints) {
30035 var multiPointArray = new Array(multiPoints.size()).fill(null);
30036 return multiPoints.toArray(multiPointArray)
30037};
30038GeometryFactory.toLinearRingArray = function toLinearRingArray (linearRings) {
30039 var linearRingArray = new Array(linearRings.size()).fill(null);
30040 return linearRings.toArray(linearRingArray)
30041};
30042GeometryFactory.toPointArray = function toPointArray (points) {
30043 var pointArray = new Array(points.size()).fill(null);
30044 return points.toArray(pointArray)
30045};
30046GeometryFactory.toPolygonArray = function toPolygonArray (polygons) {
30047 var polygonArray = new Array(polygons.size()).fill(null);
30048 return polygons.toArray(polygonArray)
30049};
30050GeometryFactory.createPointFromInternalCoord = function createPointFromInternalCoord (coord, exemplar) {
30051 exemplar.getPrecisionModel().makePrecise(coord);
30052 return exemplar.getFactory().createPoint(coord)
30053};
30054staticAccessors$2.serialVersionUID.get = function () { return -6820524753094095635 };
30055
30056Object.defineProperties( GeometryFactory, staticAccessors$2 );
30057
30058var geometryTypes = ['Point', 'MultiPoint', 'LineString', 'MultiLineString', 'Polygon', 'MultiPolygon'];
30059
30060/**
30061 * Class for reading and writing Well-Known Text.Create a new parser for GeoJSON
30062 * NOTE: Adapted from OpenLayers 2.11 implementation.
30063 */
30064
30065/**
30066 * Create a new parser for GeoJSON
30067 *
30068 * @param {GeometryFactory} geometryFactory
30069 * @return An instance of GeoJsonParser.
30070 * @constructor
30071 * @private
30072 */
30073var GeoJSONParser = function GeoJSONParser (geometryFactory) {
30074 this.geometryFactory = geometryFactory || new GeometryFactory();
30075};
30076/**
30077 * Deserialize a GeoJSON object and return the Geometry or Feature(Collection) with JSTS Geometries
30078 *
30079 * @param {}
30080 * A GeoJSON object.
30081 * @return {} A Geometry instance or object representing a Feature(Collection) with Geometry instances.
30082 * @private
30083 */
30084GeoJSONParser.prototype.read = function read (json) {
30085 var obj;
30086 if (typeof json === 'string') {
30087 obj = JSON.parse(json);
30088 } else {
30089 obj = json;
30090 }
30091
30092 var type = obj.type;
30093
30094 if (!parse[type]) {
30095 throw new Error('Unknown GeoJSON type: ' + obj.type)
30096 }
30097
30098 if (geometryTypes.indexOf(type) !== -1) {
30099 return parse[type].apply(this, [obj.coordinates])
30100 } else if (type === 'GeometryCollection') {
30101 return parse[type].apply(this, [obj.geometries])
30102 }
30103
30104 // feature or feature collection
30105 return parse[type].apply(this, [obj])
30106};
30107
30108/**
30109 * Serialize a Geometry object into GeoJSON
30110 *
30111 * @param {Geometry}
30112 * geometry A Geometry or array of Geometries.
30113 * @return {Object} A GeoJSON object represting the input Geometry/Geometries.
30114 * @private
30115 */
30116GeoJSONParser.prototype.write = function write (geometry) {
30117 var type = geometry.getGeometryType();
30118
30119 if (!extract$1$1[type]) {
30120 throw new Error('Geometry is not supported')
30121 }
30122
30123 return extract$1$1[type].apply(this, [geometry])
30124};
30125
30126var parse = {
30127 /**
30128 * Parse a GeoJSON Feature object
30129 *
30130 * @param {Object}
30131 * obj Object to parse.
30132 *
30133 * @return {Object} Feature with geometry/bbox converted to JSTS Geometries.
30134 */
30135 Feature: function (obj) {
30136 var feature = {};
30137
30138 // copy features
30139 for (var key in obj) {
30140 feature[key] = obj[key];
30141 }
30142
30143 // parse geometry
30144 if (obj.geometry) {
30145 var type = obj.geometry.type;
30146 if (!parse[type]) {
30147 throw new Error('Unknown GeoJSON type: ' + obj.type)
30148 }
30149 feature.geometry = this.read(obj.geometry);
30150 }
30151
30152 // bbox
30153 if (obj.bbox) {
30154 feature.bbox = parse.bbox.apply(this, [obj.bbox]);
30155 }
30156
30157 return feature
30158 },
30159
30160 /**
30161 * Parse a GeoJSON FeatureCollection object
30162 *
30163 * @param {Object}
30164 * obj Object to parse.
30165 *
30166 * @return {Object} FeatureCollection with geometry/bbox converted to JSTS Geometries.
30167 */
30168 FeatureCollection: function (obj) {
30169 var this$1 = this;
30170
30171 var featureCollection = {};
30172
30173 if (obj.features) {
30174 featureCollection.features = [];
30175
30176 for (var i = 0; i < obj.features.length; ++i) {
30177 featureCollection.features.push(this$1.read(obj.features[i]));
30178 }
30179 }
30180
30181 if (obj.bbox) {
30182 featureCollection.bbox = this.parse.bbox.apply(this, [obj.bbox]);
30183 }
30184
30185 return featureCollection
30186 },
30187
30188 /**
30189 * Convert the ordinates in an array to an array of Coordinates
30190 *
30191 * @param {Array}
30192 * array Array with {Number}s.
30193 *
30194 * @return {Array} Array with Coordinates.
30195 */
30196 coordinates: function (array) {
30197 var coordinates = [];
30198 for (var i = 0; i < array.length; ++i) {
30199 var sub = array[i];
30200 coordinates.push(new Coordinate(sub[0], sub[1]));
30201 }
30202 return coordinates
30203 },
30204
30205 /**
30206 * Convert the bbox to a LinearRing
30207 *
30208 * @param {Array}
30209 * array Array with [xMin, yMin, xMax, yMax].
30210 *
30211 * @return {Array} Array with Coordinates.
30212 */
30213 bbox: function (array) {
30214 return this.geometryFactory.createLinearRing([
30215 new Coordinate(array[0], array[1]),
30216 new Coordinate(array[2], array[1]),
30217 new Coordinate(array[2], array[3]),
30218 new Coordinate(array[0], array[3]),
30219 new Coordinate(array[0], array[1])
30220 ])
30221 },
30222
30223 /**
30224 * Convert an Array with ordinates to a Point
30225 *
30226 * @param {Array}
30227 * array Array with ordinates.
30228 *
30229 * @return {Point} Point.
30230 */
30231 Point: function (array) {
30232 var coordinate = new Coordinate(array[0], array[1]);
30233 return this.geometryFactory.createPoint(coordinate)
30234 },
30235
30236 /**
30237 * Convert an Array with coordinates to a MultiPoint
30238 *
30239 * @param {Array}
30240 * array Array with coordinates.
30241 *
30242 * @return {MultiPoint} MultiPoint.
30243 */
30244 MultiPoint: function (array) {
30245 var this$1 = this;
30246
30247 var points = [];
30248 for (var i = 0; i < array.length; ++i) {
30249 points.push(parse.Point.apply(this$1, [array[i]]));
30250 }
30251 return this.geometryFactory.createMultiPoint(points)
30252 },
30253
30254 /**
30255 * Convert an Array with coordinates to a LineString
30256 *
30257 * @param {Array}
30258 * array Array with coordinates.
30259 *
30260 * @return {LineString} LineString.
30261 */
30262 LineString: function (array) {
30263 var coordinates = parse.coordinates.apply(this, [array]);
30264 return this.geometryFactory.createLineString(coordinates)
30265 },
30266
30267 /**
30268 * Convert an Array with coordinates to a MultiLineString
30269 *
30270 * @param {Array}
30271 * array Array with coordinates.
30272 *
30273 * @return {MultiLineString} MultiLineString.
30274 */
30275 MultiLineString: function (array) {
30276 var this$1 = this;
30277
30278 var lineStrings = [];
30279 for (var i = 0; i < array.length; ++i) {
30280 lineStrings.push(parse.LineString.apply(this$1, [array[i]]));
30281 }
30282 return this.geometryFactory.createMultiLineString(lineStrings)
30283 },
30284
30285 /**
30286 * Convert an Array to a Polygon
30287 *
30288 * @param {Array}
30289 * array Array with shell and holes.
30290 *
30291 * @return {Polygon} Polygon.
30292 */
30293 Polygon: function (array) {
30294 var this$1 = this;
30295
30296 var shellCoordinates = parse.coordinates.apply(this, [array[0]]);
30297 var shell = this.geometryFactory.createLinearRing(shellCoordinates);
30298 var holes = [];
30299 for (var i = 1; i < array.length; ++i) {
30300 var hole = array[i];
30301 var coordinates = parse.coordinates.apply(this$1, [hole]);
30302 var linearRing = this$1.geometryFactory.createLinearRing(coordinates);
30303 holes.push(linearRing);
30304 }
30305 return this.geometryFactory.createPolygon(shell, holes)
30306 },
30307
30308 /**
30309 * Convert an Array to a MultiPolygon
30310 *
30311 * @param {Array}
30312 * array Array of arrays with shell and rings.
30313 *
30314 * @return {MultiPolygon} MultiPolygon.
30315 */
30316 MultiPolygon: function (array) {
30317 var this$1 = this;
30318
30319 var polygons = [];
30320 for (var i = 0; i < array.length; ++i) {
30321 var polygon = array[i];
30322 polygons.push(parse.Polygon.apply(this$1, [polygon]));
30323 }
30324 return this.geometryFactory.createMultiPolygon(polygons)
30325 },
30326
30327 /**
30328 * Convert an Array to a GeometryCollection
30329 *
30330 * @param {Array}
30331 * array Array of GeoJSON geometries.
30332 *
30333 * @return {GeometryCollection} GeometryCollection.
30334 */
30335 GeometryCollection: function (array) {
30336 var this$1 = this;
30337
30338 var geometries = [];
30339 for (var i = 0; i < array.length; ++i) {
30340 var geometry = array[i];
30341 geometries.push(this$1.read(geometry));
30342 }
30343 return this.geometryFactory.createGeometryCollection(geometries)
30344 }
30345};
30346
30347var extract$1$1 = {
30348 /**
30349 * Convert a Coordinate to an Array
30350 *
30351 * @param {Coordinate}
30352 * coordinate Coordinate to convert.
30353 *
30354 * @return {Array} Array of ordinates.
30355 */
30356 coordinate: function (coordinate) {
30357 return [coordinate.x, coordinate.y]
30358 },
30359
30360 /**
30361 * Convert a Point to a GeoJSON object
30362 *
30363 * @param {Point}
30364 * point Point to convert.
30365 *
30366 * @return {Array} Array of 2 ordinates (paired to a coordinate).
30367 */
30368 Point: function (point) {
30369 var array = extract$1$1.coordinate.apply(this, [point.getCoordinate()]);
30370 return {
30371 type: 'Point',
30372 coordinates: array
30373 }
30374 },
30375
30376 /**
30377 * Convert a MultiPoint to a GeoJSON object
30378 *
30379 * @param {MultiPoint}
30380 * multipoint MultiPoint to convert.
30381 *
30382 * @return {Array} Array of coordinates.
30383 */
30384 MultiPoint: function (multipoint) {
30385 var this$1 = this;
30386
30387 var array = [];
30388 for (var i = 0; i < multipoint._geometries.length; ++i) {
30389 var point = multipoint._geometries[i];
30390 var geoJson = extract$1$1.Point.apply(this$1, [point]);
30391 array.push(geoJson.coordinates);
30392 }
30393 return {
30394 type: 'MultiPoint',
30395 coordinates: array
30396 }
30397 },
30398
30399 /**
30400 * Convert a LineString to a GeoJSON object
30401 *
30402 * @param {LineString}
30403 * linestring LineString to convert.
30404 *
30405 * @return {Array} Array of coordinates.
30406 */
30407 LineString: function (linestring) {
30408 var this$1 = this;
30409
30410 var array = [];
30411 var coordinates = linestring.getCoordinates();
30412 for (var i = 0; i < coordinates.length; ++i) {
30413 var coordinate = coordinates[i];
30414 array.push(extract$1$1.coordinate.apply(this$1, [coordinate]));
30415 }
30416 return {
30417 type: 'LineString',
30418 coordinates: array
30419 }
30420 },
30421
30422 /**
30423 * Convert a MultiLineString to a GeoJSON object
30424 *
30425 * @param {MultiLineString}
30426 * multilinestring MultiLineString to convert.
30427 *
30428 * @return {Array} Array of Array of coordinates.
30429 */
30430 MultiLineString: function (multilinestring) {
30431 var this$1 = this;
30432
30433 var array = [];
30434 for (var i = 0; i < multilinestring._geometries.length; ++i) {
30435 var linestring = multilinestring._geometries[i];
30436 var geoJson = extract$1$1.LineString.apply(this$1, [linestring]);
30437 array.push(geoJson.coordinates);
30438 }
30439 return {
30440 type: 'MultiLineString',
30441 coordinates: array
30442 }
30443 },
30444
30445 /**
30446 * Convert a Polygon to a GeoJSON object
30447 *
30448 * @param {Polygon}
30449 * polygon Polygon to convert.
30450 *
30451 * @return {Array} Array with shell, holes.
30452 */
30453 Polygon: function (polygon) {
30454 var this$1 = this;
30455
30456 var array = [];
30457 var shellGeoJson = extract$1$1.LineString.apply(this, [polygon._shell]);
30458 array.push(shellGeoJson.coordinates);
30459 for (var i = 0; i < polygon._holes.length; ++i) {
30460 var hole = polygon._holes[i];
30461 var holeGeoJson = extract$1$1.LineString.apply(this$1, [hole]);
30462 array.push(holeGeoJson.coordinates);
30463 }
30464 return {
30465 type: 'Polygon',
30466 coordinates: array
30467 }
30468 },
30469
30470 /**
30471 * Convert a MultiPolygon to a GeoJSON object
30472 *
30473 * @param {MultiPolygon}
30474 * multipolygon MultiPolygon to convert.
30475 *
30476 * @return {Array} Array of polygons.
30477 */
30478 MultiPolygon: function (multipolygon) {
30479 var this$1 = this;
30480
30481 var array = [];
30482 for (var i = 0; i < multipolygon._geometries.length; ++i) {
30483 var polygon = multipolygon._geometries[i];
30484 var geoJson = extract$1$1.Polygon.apply(this$1, [polygon]);
30485 array.push(geoJson.coordinates);
30486 }
30487 return {
30488 type: 'MultiPolygon',
30489 coordinates: array
30490 }
30491 },
30492
30493 /**
30494 * Convert a GeometryCollection to a GeoJSON object
30495 *
30496 * @param {GeometryCollection}
30497 * collection GeometryCollection to convert.
30498 *
30499 * @return {Array} Array of geometries.
30500 */
30501 GeometryCollection: function (collection) {
30502 var this$1 = this;
30503
30504 var array = [];
30505 for (var i = 0; i < collection._geometries.length; ++i) {
30506 var geometry = collection._geometries[i];
30507 var type = geometry.getGeometryType();
30508 array.push(extract$1$1[type].apply(this$1, [geometry]));
30509 }
30510 return {
30511 type: 'GeometryCollection',
30512 geometries: array
30513 }
30514 }
30515};
30516
30517/**
30518 * Converts a geometry in GeoJSON to a {@link Geometry}.
30519 */
30520
30521/**
30522 * A <code>GeoJSONReader</code> is parameterized by a <code>GeometryFactory</code>,
30523 * to allow it to create <code>Geometry</code> objects of the appropriate
30524 * implementation. In particular, the <code>GeometryFactory</code> determines
30525 * the <code>PrecisionModel</code> and <code>SRID</code> that is used.
30526 *
30527 * @param {GeometryFactory} geometryFactory
30528 * @constructor
30529 */
30530var GeoJSONReader = function GeoJSONReader (geometryFactory) {
30531 this.geometryFactory = geometryFactory || new GeometryFactory();
30532 this.precisionModel = this.geometryFactory.getPrecisionModel();
30533 this.parser = new GeoJSONParser(this.geometryFactory);
30534};
30535/**
30536 * Reads a GeoJSON representation of a {@link Geometry}
30537 *
30538 * Will also parse GeoJSON Features/FeatureCollections as custom objects.
30539 *
30540 * @param {Object|String} geoJson a GeoJSON Object or String.
30541 * @return {Geometry|Object} a <code>Geometry or Feature/FeatureCollection representation.</code>
30542 * @memberof GeoJSONReader
30543 */
30544GeoJSONReader.prototype.read = function read (geoJson) {
30545 var geometry = this.parser.read(geoJson);
30546
30547 if (this.precisionModel.getType() === PrecisionModel.FIXED) {
30548 this.reducePrecision(geometry);
30549 }
30550
30551 return geometry
30552};
30553
30554// NOTE: this is a hack
30555GeoJSONReader.prototype.reducePrecision = function reducePrecision (geometry) {
30556 var this$1 = this;
30557
30558 var i, len;
30559
30560 if (geometry.coordinate) {
30561 this.precisionModel.makePrecise(geometry.coordinate);
30562 } else if (geometry.points) {
30563 for (i = 0, len = geometry.points.length; i < len; i++) {
30564 this$1.precisionModel.makePrecise(geometry.points[i]);
30565 }
30566 } else if (geometry.geometries) {
30567 for (i = 0, len = geometry.geometries.length; i < len; i++) {
30568 this$1.reducePrecision(geometry.geometries[i]);
30569 }
30570 }
30571};
30572
30573/**
30574 * @module GeoJSONWriter
30575 */
30576
30577/**
30578 * Writes the GeoJSON representation of a {@link Geometry}. The
30579 * The GeoJSON format is defined <A
30580 * HREF="http://geojson.org/geojson-spec.html">here</A>.
30581 */
30582
30583/**
30584 * The <code>GeoJSONWriter</code> outputs coordinates rounded to the precision
30585 * model. Only the maximum number of decimal places necessary to represent the
30586 * ordinates to the required precision will be output.
30587 *
30588 * @param {GeometryFactory} geometryFactory
30589 * @constructor
30590 */
30591var GeoJSONWriter = function GeoJSONWriter () {
30592 this.parser = new GeoJSONParser(this.geometryFactory);
30593};
30594/**
30595 * Converts a <code>Geometry</code> to its GeoJSON representation.
30596 *
30597 * @param {Geometry}
30598 * geometry a <code>Geometry</code> to process.
30599 * @return {Object} The GeoJSON representation of the Geometry.
30600 * @memberof GeoJSONWriter
30601 */
30602GeoJSONWriter.prototype.write = function write (geometry) {
30603 return this.parser.write(geometry)
30604};
30605
30606/* eslint-disable no-undef */
30607
30608// io
30609
30610var Position = function Position () {};
30611
30612var staticAccessors$20 = { ON: { configurable: true },LEFT: { configurable: true },RIGHT: { configurable: true } };
30613
30614Position.prototype.interfaces_ = function interfaces_ () {
30615 return []
30616};
30617Position.prototype.getClass = function getClass () {
30618 return Position
30619};
30620Position.opposite = function opposite (position) {
30621 if (position === Position.LEFT) { return Position.RIGHT }
30622 if (position === Position.RIGHT) { return Position.LEFT }
30623 return position
30624};
30625staticAccessors$20.ON.get = function () { return 0 };
30626staticAccessors$20.LEFT.get = function () { return 1 };
30627staticAccessors$20.RIGHT.get = function () { return 2 };
30628
30629Object.defineProperties( Position, staticAccessors$20 );
30630
30631/**
30632 * @param {string=} message Optional message
30633 * @extends {Error}
30634 * @constructor
30635 * @private
30636 */
30637function EmptyStackException (message) {
30638 this.message = message || '';
30639}
30640EmptyStackException.prototype = new Error();
30641
30642/**
30643 * @type {string}
30644 */
30645EmptyStackException.prototype.name = 'EmptyStackException';
30646
30647/**
30648 * @see http://download.oracle.com/javase/6/docs/api/java/util/Stack.html
30649 *
30650 * @extends {List}
30651 * @constructor
30652 * @private
30653 */
30654function Stack () {
30655 /**
30656 * @type {Array}
30657 * @private
30658 */
30659 this.array_ = [];
30660}
30661Stack.prototype = new List();
30662
30663/**
30664 * @override
30665 */
30666Stack.prototype.add = function (e) {
30667 this.array_.push(e);
30668 return true
30669};
30670
30671/**
30672 * @override
30673 */
30674Stack.prototype.get = function (index) {
30675 if (index < 0 || index >= this.size()) {
30676 throw new Error()
30677 }
30678
30679 return this.array_[index]
30680};
30681
30682/**
30683 * Pushes an item onto the top of this stack.
30684 * @param {Object} e
30685 * @return {Object}
30686 */
30687Stack.prototype.push = function (e) {
30688 this.array_.push(e);
30689 return e
30690};
30691
30692/**
30693 * Pushes an item onto the top of this stack.
30694 * @param {Object} e
30695 * @return {Object}
30696 */
30697Stack.prototype.pop = function (e) {
30698 if (this.array_.length === 0) {
30699 throw new EmptyStackException()
30700 }
30701
30702 return this.array_.pop()
30703};
30704
30705/**
30706 * Looks at the object at the top of this stack without removing it from the
30707 * stack.
30708 * @return {Object}
30709 */
30710Stack.prototype.peek = function () {
30711 if (this.array_.length === 0) {
30712 throw new EmptyStackException()
30713 }
30714
30715 return this.array_[this.array_.length - 1]
30716};
30717
30718/**
30719 * Tests if this stack is empty.
30720 * @return {boolean} true if and only if this stack contains no items; false
30721 * otherwise.
30722 */
30723Stack.prototype.empty = function () {
30724 if (this.array_.length === 0) {
30725 return true
30726 } else {
30727 return false
30728 }
30729};
30730
30731/**
30732 * @return {boolean}
30733 */
30734Stack.prototype.isEmpty = function () {
30735 return this.empty()
30736};
30737
30738/**
30739 * Returns the 1-based position where an object is on this stack. If the object
30740 * o occurs as an item in this stack, this method returns the distance from the
30741 * top of the stack of the occurrence nearest the top of the stack; the topmost
30742 * item on the stack is considered to be at distance 1. The equals method is
30743 * used to compare o to the items in this stack.
30744 *
30745 * NOTE: does not currently actually use equals. (=== is used)
30746 *
30747 * @param {Object} o
30748 * @return {number} the 1-based position from the top of the stack where the
30749 * object is located; the return value -1 indicates that the object is
30750 * not on the stack.
30751 */
30752Stack.prototype.search = function (o) {
30753 return this.array_.indexOf(o)
30754};
30755
30756/**
30757 * @return {number}
30758 * @export
30759 */
30760Stack.prototype.size = function () {
30761 return this.array_.length
30762};
30763
30764/**
30765 * @return {Array}
30766 */
30767Stack.prototype.toArray = function () {
30768 var this$1 = this;
30769
30770 var array = [];
30771
30772 for (var i = 0, len = this.array_.length; i < len; i++) {
30773 array.push(this$1.array_[i]);
30774 }
30775
30776 return array
30777};
30778
30779var RightmostEdgeFinder = function RightmostEdgeFinder () {
30780 this._minIndex = -1;
30781 this._minCoord = null;
30782 this._minDe = null;
30783 this._orientedDe = null;
30784};
30785RightmostEdgeFinder.prototype.getCoordinate = function getCoordinate () {
30786 return this._minCoord
30787};
30788RightmostEdgeFinder.prototype.getRightmostSide = function getRightmostSide (de, index) {
30789 var side = this.getRightmostSideOfSegment(de, index);
30790 if (side < 0) { side = this.getRightmostSideOfSegment(de, index - 1); }
30791 if (side < 0) {
30792 this._minCoord = null;
30793 this.checkForRightmostCoordinate(de);
30794 }
30795 return side
30796};
30797RightmostEdgeFinder.prototype.findRightmostEdgeAtVertex = function findRightmostEdgeAtVertex () {
30798 var pts = this._minDe.getEdge().getCoordinates();
30799 Assert.isTrue(this._minIndex > 0 && this._minIndex < pts.length, 'rightmost point expected to be interior vertex of edge');
30800 var pPrev = pts[this._minIndex - 1];
30801 var pNext = pts[this._minIndex + 1];
30802 var orientation = CGAlgorithms.computeOrientation(this._minCoord, pNext, pPrev);
30803 var usePrev = false;
30804 if (pPrev.y < this._minCoord.y && pNext.y < this._minCoord.y && orientation === CGAlgorithms.COUNTERCLOCKWISE) {
30805 usePrev = true;
30806 } else if (pPrev.y > this._minCoord.y && pNext.y > this._minCoord.y && orientation === CGAlgorithms.CLOCKWISE) {
30807 usePrev = true;
30808 }
30809 if (usePrev) {
30810 this._minIndex = this._minIndex - 1;
30811 }
30812};
30813RightmostEdgeFinder.prototype.getRightmostSideOfSegment = function getRightmostSideOfSegment (de, i) {
30814 var e = de.getEdge();
30815 var coord = e.getCoordinates();
30816 if (i < 0 || i + 1 >= coord.length) { return -1 }
30817 if (coord[i].y === coord[i + 1].y) { return -1 }
30818 var pos = Position.LEFT;
30819 if (coord[i].y < coord[i + 1].y) { pos = Position.RIGHT; }
30820 return pos
30821};
30822RightmostEdgeFinder.prototype.getEdge = function getEdge () {
30823 return this._orientedDe
30824};
30825RightmostEdgeFinder.prototype.checkForRightmostCoordinate = function checkForRightmostCoordinate (de) {
30826 var this$1 = this;
30827
30828 var coord = de.getEdge().getCoordinates();
30829 for (var i = 0; i < coord.length - 1; i++) {
30830 if (this$1._minCoord === null || coord[i].x > this$1._minCoord.x) {
30831 this$1._minDe = de;
30832 this$1._minIndex = i;
30833 this$1._minCoord = coord[i];
30834 }
30835 }
30836};
30837RightmostEdgeFinder.prototype.findRightmostEdgeAtNode = function findRightmostEdgeAtNode () {
30838 var node = this._minDe.getNode();
30839 var star = node.getEdges();
30840 this._minDe = star.getRightmostEdge();
30841 if (!this._minDe.isForward()) {
30842 this._minDe = this._minDe.getSym();
30843 this._minIndex = this._minDe.getEdge().getCoordinates().length - 1;
30844 }
30845};
30846RightmostEdgeFinder.prototype.findEdge = function findEdge (dirEdgeList) {
30847 var this$1 = this;
30848
30849 for (var i = dirEdgeList.iterator(); i.hasNext();) {
30850 var de = i.next();
30851 if (!de.isForward()) { continue }
30852 this$1.checkForRightmostCoordinate(de);
30853 }
30854 Assert.isTrue(this._minIndex !== 0 || this._minCoord.equals(this._minDe.getCoordinate()), 'inconsistency in rightmost processing');
30855 if (this._minIndex === 0) {
30856 this.findRightmostEdgeAtNode();
30857 } else {
30858 this.findRightmostEdgeAtVertex();
30859 }
30860 this._orientedDe = this._minDe;
30861 var rightmostSide = this.getRightmostSide(this._minDe, this._minIndex);
30862 if (rightmostSide === Position.LEFT) {
30863 this._orientedDe = this._minDe.getSym();
30864 }
30865};
30866RightmostEdgeFinder.prototype.interfaces_ = function interfaces_ () {
30867 return []
30868};
30869RightmostEdgeFinder.prototype.getClass = function getClass () {
30870 return RightmostEdgeFinder
30871};
30872
30873var TopologyException = (function (RuntimeException$$1) {
30874 function TopologyException (msg, pt) {
30875 RuntimeException$$1.call(this, TopologyException.msgWithCoord(msg, pt));
30876 this.pt = pt ? new Coordinate(pt) : null;
30877 this.name = 'TopologyException';
30878 }
30879
30880 if ( RuntimeException$$1 ) TopologyException.__proto__ = RuntimeException$$1;
30881 TopologyException.prototype = Object.create( RuntimeException$$1 && RuntimeException$$1.prototype );
30882 TopologyException.prototype.constructor = TopologyException;
30883 TopologyException.prototype.getCoordinate = function getCoordinate () {
30884 return this.pt
30885 };
30886 TopologyException.prototype.interfaces_ = function interfaces_ () {
30887 return []
30888 };
30889 TopologyException.prototype.getClass = function getClass () {
30890 return TopologyException
30891 };
30892 TopologyException.msgWithCoord = function msgWithCoord (msg, pt) {
30893 if (!pt) { return msg + ' [ ' + pt + ' ]' }
30894 return msg
30895 };
30896
30897 return TopologyException;
30898}(RuntimeException));
30899
30900var LinkedList = function LinkedList () {
30901 this.array_ = [];
30902};
30903LinkedList.prototype.addLast = function addLast (e) {
30904 this.array_.push(e);
30905};
30906LinkedList.prototype.removeFirst = function removeFirst () {
30907 return this.array_.shift()
30908};
30909LinkedList.prototype.isEmpty = function isEmpty () {
30910 return this.array_.length === 0
30911};
30912
30913var BufferSubgraph = function BufferSubgraph () {
30914 this._finder = null;
30915 this._dirEdgeList = new ArrayList();
30916 this._nodes = new ArrayList();
30917 this._rightMostCoord = null;
30918 this._env = null;
30919 this._finder = new RightmostEdgeFinder();
30920};
30921BufferSubgraph.prototype.clearVisitedEdges = function clearVisitedEdges () {
30922 for (var it = this._dirEdgeList.iterator(); it.hasNext();) {
30923 var de = it.next();
30924 de.setVisited(false);
30925 }
30926};
30927BufferSubgraph.prototype.getRightmostCoordinate = function getRightmostCoordinate () {
30928 return this._rightMostCoord
30929};
30930BufferSubgraph.prototype.computeNodeDepth = function computeNodeDepth (n) {
30931 var this$1 = this;
30932
30933 var startEdge = null;
30934 for (var i = n.getEdges().iterator(); i.hasNext();) {
30935 var de = i.next();
30936 if (de.isVisited() || de.getSym().isVisited()) {
30937 startEdge = de;
30938 break
30939 }
30940 }
30941 if (startEdge === null) { throw new TopologyException('unable to find edge to compute depths at ' + n.getCoordinate()) }
30942 n.getEdges().computeDepths(startEdge);
30943 for (var i$1 = n.getEdges().iterator(); i$1.hasNext();) {
30944 var de$1 = i$1.next();
30945 de$1.setVisited(true);
30946 this$1.copySymDepths(de$1);
30947 }
30948};
30949BufferSubgraph.prototype.computeDepth = function computeDepth (outsideDepth) {
30950 this.clearVisitedEdges();
30951 var de = this._finder.getEdge();
30952 // const n = de.getNode()
30953 // const label = de.getLabel()
30954 de.setEdgeDepths(Position.RIGHT, outsideDepth);
30955 this.copySymDepths(de);
30956 this.computeDepths(de);
30957};
30958BufferSubgraph.prototype.create = function create (node) {
30959 this.addReachable(node);
30960 this._finder.findEdge(this._dirEdgeList);
30961 this._rightMostCoord = this._finder.getCoordinate();
30962};
30963BufferSubgraph.prototype.findResultEdges = function findResultEdges () {
30964 for (var it = this._dirEdgeList.iterator(); it.hasNext();) {
30965 var de = it.next();
30966 if (de.getDepth(Position.RIGHT) >= 1 && de.getDepth(Position.LEFT) <= 0 && !de.isInteriorAreaEdge()) {
30967 de.setInResult(true);
30968 }
30969 }
30970};
30971BufferSubgraph.prototype.computeDepths = function computeDepths (startEdge) {
30972 var this$1 = this;
30973
30974 var nodesVisited = new HashSet();
30975 var nodeQueue = new LinkedList();
30976 var startNode = startEdge.getNode();
30977 nodeQueue.addLast(startNode);
30978 nodesVisited.add(startNode);
30979 startEdge.setVisited(true);
30980 while (!nodeQueue.isEmpty()) {
30981 var n = nodeQueue.removeFirst();
30982 nodesVisited.add(n);
30983 this$1.computeNodeDepth(n);
30984 for (var i = n.getEdges().iterator(); i.hasNext();) {
30985 var de = i.next();
30986 var sym = de.getSym();
30987 if (sym.isVisited()) { continue }
30988 var adjNode = sym.getNode();
30989 if (!nodesVisited.contains(adjNode)) {
30990 nodeQueue.addLast(adjNode);
30991 nodesVisited.add(adjNode);
30992 }
30993 }
30994 }
30995};
30996BufferSubgraph.prototype.compareTo = function compareTo (o) {
30997 var graph = o;
30998 if (this._rightMostCoord.x < graph._rightMostCoord.x) {
30999 return -1
31000 }
31001 if (this._rightMostCoord.x > graph._rightMostCoord.x) {
31002 return 1
31003 }
31004 return 0
31005};
31006BufferSubgraph.prototype.getEnvelope = function getEnvelope () {
31007 if (this._env === null) {
31008 var edgeEnv = new Envelope();
31009 for (var it = this._dirEdgeList.iterator(); it.hasNext();) {
31010 var dirEdge = it.next();
31011 var pts = dirEdge.getEdge().getCoordinates();
31012 for (var i = 0; i < pts.length - 1; i++) {
31013 edgeEnv.expandToInclude(pts[i]);
31014 }
31015 }
31016 this._env = edgeEnv;
31017 }
31018 return this._env
31019};
31020BufferSubgraph.prototype.addReachable = function addReachable (startNode) {
31021 var this$1 = this;
31022
31023 var nodeStack = new Stack();
31024 nodeStack.add(startNode);
31025 while (!nodeStack.empty()) {
31026 var node = nodeStack.pop();
31027 this$1.add(node, nodeStack);
31028 }
31029};
31030BufferSubgraph.prototype.copySymDepths = function copySymDepths (de) {
31031 var sym = de.getSym();
31032 sym.setDepth(Position.LEFT, de.getDepth(Position.RIGHT));
31033 sym.setDepth(Position.RIGHT, de.getDepth(Position.LEFT));
31034};
31035BufferSubgraph.prototype.add = function add (node, nodeStack) {
31036 var this$1 = this;
31037
31038 node.setVisited(true);
31039 this._nodes.add(node);
31040 for (var i = node.getEdges().iterator(); i.hasNext();) {
31041 var de = i.next();
31042 this$1._dirEdgeList.add(de);
31043 var sym = de.getSym();
31044 var symNode = sym.getNode();
31045 if (!symNode.isVisited()) { nodeStack.push(symNode); }
31046 }
31047};
31048BufferSubgraph.prototype.getNodes = function getNodes () {
31049 return this._nodes
31050};
31051BufferSubgraph.prototype.getDirectedEdges = function getDirectedEdges () {
31052 return this._dirEdgeList
31053};
31054BufferSubgraph.prototype.interfaces_ = function interfaces_ () {
31055 return [Comparable]
31056};
31057BufferSubgraph.prototype.getClass = function getClass () {
31058 return BufferSubgraph
31059};
31060
31061var TopologyLocation = function TopologyLocation () {
31062 var this$1 = this;
31063
31064 this.location = null;
31065 if (arguments.length === 1) {
31066 if (arguments[0] instanceof Array) {
31067 var location = arguments[0];
31068 this.init(location.length);
31069 } else if (Number.isInteger(arguments[0])) {
31070 var on = arguments[0];
31071 this.init(1);
31072 this.location[Position.ON] = on;
31073 } else if (arguments[0] instanceof TopologyLocation) {
31074 var gl = arguments[0];
31075 this.init(gl.location.length);
31076 if (gl !== null) {
31077 for (var i = 0; i < this.location.length; i++) {
31078 this$1.location[i] = gl.location[i];
31079 }
31080 }
31081 }
31082 } else if (arguments.length === 3) {
31083 var on$1 = arguments[0];
31084 var left = arguments[1];
31085 var right = arguments[2];
31086 this.init(3);
31087 this.location[Position.ON] = on$1;
31088 this.location[Position.LEFT] = left;
31089 this.location[Position.RIGHT] = right;
31090 }
31091};
31092TopologyLocation.prototype.setAllLocations = function setAllLocations (locValue) {
31093 var this$1 = this;
31094
31095 for (var i = 0; i < this.location.length; i++) {
31096 this$1.location[i] = locValue;
31097 }
31098};
31099TopologyLocation.prototype.isNull = function isNull () {
31100 var this$1 = this;
31101
31102 for (var i = 0; i < this.location.length; i++) {
31103 if (this$1.location[i] !== Location.NONE) { return false }
31104 }
31105 return true
31106};
31107TopologyLocation.prototype.setAllLocationsIfNull = function setAllLocationsIfNull (locValue) {
31108 var this$1 = this;
31109
31110 for (var i = 0; i < this.location.length; i++) {
31111 if (this$1.location[i] === Location.NONE) { this$1.location[i] = locValue; }
31112 }
31113};
31114TopologyLocation.prototype.isLine = function isLine () {
31115 return this.location.length === 1
31116};
31117TopologyLocation.prototype.merge = function merge (gl) {
31118 var this$1 = this;
31119
31120 if (gl.location.length > this.location.length) {
31121 var newLoc = new Array(3).fill(null);
31122 newLoc[Position.ON] = this.location[Position.ON];
31123 newLoc[Position.LEFT] = Location.NONE;
31124 newLoc[Position.RIGHT] = Location.NONE;
31125 this.location = newLoc;
31126 }
31127 for (var i = 0; i < this.location.length; i++) {
31128 if (this$1.location[i] === Location.NONE && i < gl.location.length) { this$1.location[i] = gl.location[i]; }
31129 }
31130};
31131TopologyLocation.prototype.getLocations = function getLocations () {
31132 return this.location
31133};
31134TopologyLocation.prototype.flip = function flip () {
31135 if (this.location.length <= 1) { return null }
31136 var temp = this.location[Position.LEFT];
31137 this.location[Position.LEFT] = this.location[Position.RIGHT];
31138 this.location[Position.RIGHT] = temp;
31139};
31140TopologyLocation.prototype.toString = function toString () {
31141 var buf = new StringBuffer();
31142 if (this.location.length > 1) { buf.append(Location.toLocationSymbol(this.location[Position.LEFT])); }
31143 buf.append(Location.toLocationSymbol(this.location[Position.ON]));
31144 if (this.location.length > 1) { buf.append(Location.toLocationSymbol(this.location[Position.RIGHT])); }
31145 return buf.toString()
31146};
31147TopologyLocation.prototype.setLocations = function setLocations (on, left, right) {
31148 this.location[Position.ON] = on;
31149 this.location[Position.LEFT] = left;
31150 this.location[Position.RIGHT] = right;
31151};
31152TopologyLocation.prototype.get = function get (posIndex) {
31153 if (posIndex < this.location.length) { return this.location[posIndex] }
31154 return Location.NONE
31155};
31156TopologyLocation.prototype.isArea = function isArea () {
31157 return this.location.length > 1
31158};
31159TopologyLocation.prototype.isAnyNull = function isAnyNull () {
31160 var this$1 = this;
31161
31162 for (var i = 0; i < this.location.length; i++) {
31163 if (this$1.location[i] === Location.NONE) { return true }
31164 }
31165 return false
31166};
31167TopologyLocation.prototype.setLocation = function setLocation () {
31168 if (arguments.length === 1) {
31169 var locValue = arguments[0];
31170 this.setLocation(Position.ON, locValue);
31171 } else if (arguments.length === 2) {
31172 var locIndex = arguments[0];
31173 var locValue$1 = arguments[1];
31174 this.location[locIndex] = locValue$1;
31175 }
31176};
31177TopologyLocation.prototype.init = function init (size) {
31178 this.location = new Array(size).fill(null);
31179 this.setAllLocations(Location.NONE);
31180};
31181TopologyLocation.prototype.isEqualOnSide = function isEqualOnSide (le, locIndex) {
31182 return this.location[locIndex] === le.location[locIndex]
31183};
31184TopologyLocation.prototype.allPositionsEqual = function allPositionsEqual (loc) {
31185 var this$1 = this;
31186
31187 for (var i = 0; i < this.location.length; i++) {
31188 if (this$1.location[i] !== loc) { return false }
31189 }
31190 return true
31191};
31192TopologyLocation.prototype.interfaces_ = function interfaces_ () {
31193 return []
31194};
31195TopologyLocation.prototype.getClass = function getClass () {
31196 return TopologyLocation
31197};
31198
31199var Label = function Label () {
31200 this.elt = new Array(2).fill(null);
31201 if (arguments.length === 1) {
31202 if (Number.isInteger(arguments[0])) {
31203 var onLoc = arguments[0];
31204 this.elt[0] = new TopologyLocation(onLoc);
31205 this.elt[1] = new TopologyLocation(onLoc);
31206 } else if (arguments[0] instanceof Label) {
31207 var lbl = arguments[0];
31208 this.elt[0] = new TopologyLocation(lbl.elt[0]);
31209 this.elt[1] = new TopologyLocation(lbl.elt[1]);
31210 }
31211 } else if (arguments.length === 2) {
31212 var geomIndex = arguments[0];
31213 var onLoc$1 = arguments[1];
31214 this.elt[0] = new TopologyLocation(Location.NONE);
31215 this.elt[1] = new TopologyLocation(Location.NONE);
31216 this.elt[geomIndex].setLocation(onLoc$1);
31217 } else if (arguments.length === 3) {
31218 var onLoc$2 = arguments[0];
31219 var leftLoc = arguments[1];
31220 var rightLoc = arguments[2];
31221 this.elt[0] = new TopologyLocation(onLoc$2, leftLoc, rightLoc);
31222 this.elt[1] = new TopologyLocation(onLoc$2, leftLoc, rightLoc);
31223 } else if (arguments.length === 4) {
31224 var geomIndex$1 = arguments[0];
31225 var onLoc$3 = arguments[1];
31226 var leftLoc$1 = arguments[2];
31227 var rightLoc$1 = arguments[3];
31228 this.elt[0] = new TopologyLocation(Location.NONE, Location.NONE, Location.NONE);
31229 this.elt[1] = new TopologyLocation(Location.NONE, Location.NONE, Location.NONE);
31230 this.elt[geomIndex$1].setLocations(onLoc$3, leftLoc$1, rightLoc$1);
31231 }
31232};
31233Label.prototype.getGeometryCount = function getGeometryCount () {
31234 var count = 0;
31235 if (!this.elt[0].isNull()) { count++; }
31236 if (!this.elt[1].isNull()) { count++; }
31237 return count
31238};
31239Label.prototype.setAllLocations = function setAllLocations (geomIndex, location) {
31240 this.elt[geomIndex].setAllLocations(location);
31241};
31242Label.prototype.isNull = function isNull (geomIndex) {
31243 return this.elt[geomIndex].isNull()
31244};
31245Label.prototype.setAllLocationsIfNull = function setAllLocationsIfNull () {
31246 if (arguments.length === 1) {
31247 var location = arguments[0];
31248 this.setAllLocationsIfNull(0, location);
31249 this.setAllLocationsIfNull(1, location);
31250 } else if (arguments.length === 2) {
31251 var geomIndex = arguments[0];
31252 var location$1 = arguments[1];
31253 this.elt[geomIndex].setAllLocationsIfNull(location$1);
31254 }
31255};
31256Label.prototype.isLine = function isLine (geomIndex) {
31257 return this.elt[geomIndex].isLine()
31258};
31259Label.prototype.merge = function merge (lbl) {
31260 var this$1 = this;
31261
31262 for (var i = 0; i < 2; i++) {
31263 if (this$1.elt[i] === null && lbl.elt[i] !== null) {
31264 this$1.elt[i] = new TopologyLocation(lbl.elt[i]);
31265 } else {
31266 this$1.elt[i].merge(lbl.elt[i]);
31267 }
31268 }
31269};
31270Label.prototype.flip = function flip () {
31271 this.elt[0].flip();
31272 this.elt[1].flip();
31273};
31274Label.prototype.getLocation = function getLocation () {
31275 if (arguments.length === 1) {
31276 var geomIndex = arguments[0];
31277 return this.elt[geomIndex].get(Position.ON)
31278 } else if (arguments.length === 2) {
31279 var geomIndex$1 = arguments[0];
31280 var posIndex = arguments[1];
31281 return this.elt[geomIndex$1].get(posIndex)
31282 }
31283};
31284Label.prototype.toString = function toString () {
31285 var buf = new StringBuffer();
31286 if (this.elt[0] !== null) {
31287 buf.append('A:');
31288 buf.append(this.elt[0].toString());
31289 }
31290 if (this.elt[1] !== null) {
31291 buf.append(' B:');
31292 buf.append(this.elt[1].toString());
31293 }
31294 return buf.toString()
31295};
31296Label.prototype.isArea = function isArea () {
31297 if (arguments.length === 0) {
31298 return this.elt[0].isArea() || this.elt[1].isArea()
31299 } else if (arguments.length === 1) {
31300 var geomIndex = arguments[0];
31301 return this.elt[geomIndex].isArea()
31302 }
31303};
31304Label.prototype.isAnyNull = function isAnyNull (geomIndex) {
31305 return this.elt[geomIndex].isAnyNull()
31306};
31307Label.prototype.setLocation = function setLocation () {
31308 if (arguments.length === 2) {
31309 var geomIndex = arguments[0];
31310 var location = arguments[1];
31311 this.elt[geomIndex].setLocation(Position.ON, location);
31312 } else if (arguments.length === 3) {
31313 var geomIndex$1 = arguments[0];
31314 var posIndex = arguments[1];
31315 var location$1 = arguments[2];
31316 this.elt[geomIndex$1].setLocation(posIndex, location$1);
31317 }
31318};
31319Label.prototype.isEqualOnSide = function isEqualOnSide (lbl, side) {
31320 return this.elt[0].isEqualOnSide(lbl.elt[0], side) && this.elt[1].isEqualOnSide(lbl.elt[1], side)
31321};
31322Label.prototype.allPositionsEqual = function allPositionsEqual (geomIndex, loc) {
31323 return this.elt[geomIndex].allPositionsEqual(loc)
31324};
31325Label.prototype.toLine = function toLine (geomIndex) {
31326 if (this.elt[geomIndex].isArea()) { this.elt[geomIndex] = new TopologyLocation(this.elt[geomIndex].location[0]); }
31327};
31328Label.prototype.interfaces_ = function interfaces_ () {
31329 return []
31330};
31331Label.prototype.getClass = function getClass () {
31332 return Label
31333};
31334Label.toLineLabel = function toLineLabel (label) {
31335 var lineLabel = new Label(Location.NONE);
31336 for (var i = 0; i < 2; i++) {
31337 lineLabel.setLocation(i, label.getLocation(i));
31338 }
31339 return lineLabel
31340};
31341
31342var EdgeRing$1 = function EdgeRing () {
31343 this._startDe = null;
31344 this._maxNodeDegree = -1;
31345 this._edges = new ArrayList();
31346 this._pts = new ArrayList();
31347 this._label = new Label(Location.NONE);
31348 this._ring = null;
31349 this._isHole = null;
31350 this._shell = null;
31351 this._holes = new ArrayList();
31352 this._geometryFactory = null;
31353 var start = arguments[0];
31354 var geometryFactory = arguments[1];
31355 this._geometryFactory = geometryFactory;
31356 this.computePoints(start);
31357 this.computeRing();
31358};
31359EdgeRing$1.prototype.computeRing = function computeRing () {
31360 var this$1 = this;
31361
31362 if (this._ring !== null) { return null }
31363 var coord = new Array(this._pts.size()).fill(null);
31364 for (var i = 0; i < this._pts.size(); i++) {
31365 coord[i] = this$1._pts.get(i);
31366 }
31367 this._ring = this._geometryFactory.createLinearRing(coord);
31368 this._isHole = CGAlgorithms.isCCW(this._ring.getCoordinates());
31369};
31370EdgeRing$1.prototype.isIsolated = function isIsolated () {
31371 return this._label.getGeometryCount() === 1
31372};
31373EdgeRing$1.prototype.computePoints = function computePoints (start) {
31374 var this$1 = this;
31375
31376 this._startDe = start;
31377 var de = start;
31378 var isFirstEdge = true;
31379 do {
31380 if (de === null) { throw new TopologyException('Found null DirectedEdge') }
31381 if (de.getEdgeRing() === this$1) { throw new TopologyException('Directed Edge visited twice during ring-building at ' + de.getCoordinate()) }
31382 this$1._edges.add(de);
31383 var label = de.getLabel();
31384 Assert.isTrue(label.isArea());
31385 this$1.mergeLabel(label);
31386 this$1.addPoints(de.getEdge(), de.isForward(), isFirstEdge);
31387 isFirstEdge = false;
31388 this$1.setEdgeRing(de, this$1);
31389 de = this$1.getNext(de);
31390 } while (de !== this._startDe)
31391};
31392EdgeRing$1.prototype.getLinearRing = function getLinearRing () {
31393 return this._ring
31394};
31395EdgeRing$1.prototype.getCoordinate = function getCoordinate (i) {
31396 return this._pts.get(i)
31397};
31398EdgeRing$1.prototype.computeMaxNodeDegree = function computeMaxNodeDegree () {
31399 var this$1 = this;
31400
31401 this._maxNodeDegree = 0;
31402 var de = this._startDe;
31403 do {
31404 var node = de.getNode();
31405 var degree = node.getEdges().getOutgoingDegree(this$1);
31406 if (degree > this$1._maxNodeDegree) { this$1._maxNodeDegree = degree; }
31407 de = this$1.getNext(de);
31408 } while (de !== this._startDe)
31409 this._maxNodeDegree *= 2;
31410};
31411EdgeRing$1.prototype.addPoints = function addPoints (edge, isForward, isFirstEdge) {
31412 var this$1 = this;
31413
31414 var edgePts = edge.getCoordinates();
31415 if (isForward) {
31416 var startIndex = 1;
31417 if (isFirstEdge) { startIndex = 0; }
31418 for (var i = startIndex; i < edgePts.length; i++) {
31419 this$1._pts.add(edgePts[i]);
31420 }
31421 } else {
31422 var startIndex$1 = edgePts.length - 2;
31423 if (isFirstEdge) { startIndex$1 = edgePts.length - 1; }
31424 for (var i$1 = startIndex$1; i$1 >= 0; i$1--) {
31425 this$1._pts.add(edgePts[i$1]);
31426 }
31427 }
31428};
31429EdgeRing$1.prototype.isHole = function isHole () {
31430 return this._isHole
31431};
31432EdgeRing$1.prototype.setInResult = function setInResult () {
31433 var de = this._startDe;
31434 do {
31435 de.getEdge().setInResult(true);
31436 de = de.getNext();
31437 } while (de !== this._startDe)
31438};
31439EdgeRing$1.prototype.containsPoint = function containsPoint (p) {
31440 var shell = this.getLinearRing();
31441 var env = shell.getEnvelopeInternal();
31442 if (!env.contains(p)) { return false }
31443 if (!CGAlgorithms.isPointInRing(p, shell.getCoordinates())) { return false }
31444 for (var i = this._holes.iterator(); i.hasNext();) {
31445 var hole = i.next();
31446 if (hole.containsPoint(p)) { return false }
31447 }
31448 return true
31449};
31450EdgeRing$1.prototype.addHole = function addHole (ring) {
31451 this._holes.add(ring);
31452};
31453EdgeRing$1.prototype.isShell = function isShell () {
31454 return this._shell === null
31455};
31456EdgeRing$1.prototype.getLabel = function getLabel () {
31457 return this._label
31458};
31459EdgeRing$1.prototype.getEdges = function getEdges () {
31460 return this._edges
31461};
31462EdgeRing$1.prototype.getMaxNodeDegree = function getMaxNodeDegree () {
31463 if (this._maxNodeDegree < 0) { this.computeMaxNodeDegree(); }
31464 return this._maxNodeDegree
31465};
31466EdgeRing$1.prototype.getShell = function getShell () {
31467 return this._shell
31468};
31469EdgeRing$1.prototype.mergeLabel = function mergeLabel () {
31470 if (arguments.length === 1) {
31471 var deLabel = arguments[0];
31472 this.mergeLabel(deLabel, 0);
31473 this.mergeLabel(deLabel, 1);
31474 } else if (arguments.length === 2) {
31475 var deLabel$1 = arguments[0];
31476 var geomIndex = arguments[1];
31477 var loc = deLabel$1.getLocation(geomIndex, Position.RIGHT);
31478 if (loc === Location.NONE) { return null }
31479 if (this._label.getLocation(geomIndex) === Location.NONE) {
31480 this._label.setLocation(geomIndex, loc);
31481 return null
31482 }
31483 }
31484};
31485EdgeRing$1.prototype.setShell = function setShell (shell) {
31486 this._shell = shell;
31487 if (shell !== null) { shell.addHole(this); }
31488};
31489EdgeRing$1.prototype.toPolygon = function toPolygon (geometryFactory) {
31490 var this$1 = this;
31491
31492 var holeLR = new Array(this._holes.size()).fill(null);
31493 for (var i = 0; i < this._holes.size(); i++) {
31494 holeLR[i] = this$1._holes.get(i).getLinearRing();
31495 }
31496 var poly = geometryFactory.createPolygon(this.getLinearRing(), holeLR);
31497 return poly
31498};
31499EdgeRing$1.prototype.interfaces_ = function interfaces_ () {
31500 return []
31501};
31502EdgeRing$1.prototype.getClass = function getClass () {
31503 return EdgeRing$1
31504};
31505
31506var MinimalEdgeRing = (function (EdgeRing$$1) {
31507 function MinimalEdgeRing () {
31508 var start = arguments[0];
31509 var geometryFactory = arguments[1];
31510 EdgeRing$$1.call(this, start, geometryFactory);
31511 }
31512
31513 if ( EdgeRing$$1 ) MinimalEdgeRing.__proto__ = EdgeRing$$1;
31514 MinimalEdgeRing.prototype = Object.create( EdgeRing$$1 && EdgeRing$$1.prototype );
31515 MinimalEdgeRing.prototype.constructor = MinimalEdgeRing;
31516 MinimalEdgeRing.prototype.setEdgeRing = function setEdgeRing (de, er) {
31517 de.setMinEdgeRing(er);
31518 };
31519 MinimalEdgeRing.prototype.getNext = function getNext (de) {
31520 return de.getNextMin()
31521 };
31522 MinimalEdgeRing.prototype.interfaces_ = function interfaces_ () {
31523 return []
31524 };
31525 MinimalEdgeRing.prototype.getClass = function getClass () {
31526 return MinimalEdgeRing
31527 };
31528
31529 return MinimalEdgeRing;
31530}(EdgeRing$1));
31531
31532var MaximalEdgeRing = (function (EdgeRing$$1) {
31533 function MaximalEdgeRing () {
31534 var start = arguments[0];
31535 var geometryFactory = arguments[1];
31536 EdgeRing$$1.call(this, start, geometryFactory);
31537 }
31538
31539 if ( EdgeRing$$1 ) MaximalEdgeRing.__proto__ = EdgeRing$$1;
31540 MaximalEdgeRing.prototype = Object.create( EdgeRing$$1 && EdgeRing$$1.prototype );
31541 MaximalEdgeRing.prototype.constructor = MaximalEdgeRing;
31542 MaximalEdgeRing.prototype.buildMinimalRings = function buildMinimalRings () {
31543 var this$1 = this;
31544
31545 var minEdgeRings = new ArrayList();
31546 var de = this._startDe;
31547 do {
31548 if (de.getMinEdgeRing() === null) {
31549 var minEr = new MinimalEdgeRing(de, this$1._geometryFactory);
31550 minEdgeRings.add(minEr);
31551 }
31552 de = de.getNext();
31553 } while (de !== this._startDe)
31554 return minEdgeRings
31555 };
31556 MaximalEdgeRing.prototype.setEdgeRing = function setEdgeRing (de, er) {
31557 de.setEdgeRing(er);
31558 };
31559 MaximalEdgeRing.prototype.linkDirectedEdgesForMinimalEdgeRings = function linkDirectedEdgesForMinimalEdgeRings () {
31560 var this$1 = this;
31561
31562 var de = this._startDe;
31563 do {
31564 var node = de.getNode();
31565 node.getEdges().linkMinimalDirectedEdges(this$1);
31566 de = de.getNext();
31567 } while (de !== this._startDe)
31568 };
31569 MaximalEdgeRing.prototype.getNext = function getNext (de) {
31570 return de.getNext()
31571 };
31572 MaximalEdgeRing.prototype.interfaces_ = function interfaces_ () {
31573 return []
31574 };
31575 MaximalEdgeRing.prototype.getClass = function getClass () {
31576 return MaximalEdgeRing
31577 };
31578
31579 return MaximalEdgeRing;
31580}(EdgeRing$1));
31581
31582var GraphComponent = function GraphComponent () {
31583 this._label = null;
31584 this._isInResult = false;
31585 this._isCovered = false;
31586 this._isCoveredSet = false;
31587 this._isVisited = false;
31588 if (arguments.length === 0) {} else if (arguments.length === 1) {
31589 var label = arguments[0];
31590 this._label = label;
31591 }
31592};
31593GraphComponent.prototype.setVisited = function setVisited (isVisited) {
31594 this._isVisited = isVisited;
31595};
31596GraphComponent.prototype.setInResult = function setInResult (isInResult) {
31597 this._isInResult = isInResult;
31598};
31599GraphComponent.prototype.isCovered = function isCovered () {
31600 return this._isCovered
31601};
31602GraphComponent.prototype.isCoveredSet = function isCoveredSet () {
31603 return this._isCoveredSet
31604};
31605GraphComponent.prototype.setLabel = function setLabel (label) {
31606 this._label = label;
31607};
31608GraphComponent.prototype.getLabel = function getLabel () {
31609 return this._label
31610};
31611GraphComponent.prototype.setCovered = function setCovered (isCovered) {
31612 this._isCovered = isCovered;
31613 this._isCoveredSet = true;
31614};
31615GraphComponent.prototype.updateIM = function updateIM (im) {
31616 Assert.isTrue(this._label.getGeometryCount() >= 2, 'found partial label');
31617 this.computeIM(im);
31618};
31619GraphComponent.prototype.isInResult = function isInResult () {
31620 return this._isInResult
31621};
31622GraphComponent.prototype.isVisited = function isVisited () {
31623 return this._isVisited
31624};
31625GraphComponent.prototype.interfaces_ = function interfaces_ () {
31626 return []
31627};
31628GraphComponent.prototype.getClass = function getClass () {
31629 return GraphComponent
31630};
31631
31632var Node$2 = (function (GraphComponent$$1) {
31633 function Node () {
31634 GraphComponent$$1.call(this);
31635 this._coord = null;
31636 this._edges = null;
31637 var coord = arguments[0];
31638 var edges = arguments[1];
31639 this._coord = coord;
31640 this._edges = edges;
31641 this._label = new Label(0, Location.NONE);
31642 }
31643
31644 if ( GraphComponent$$1 ) Node.__proto__ = GraphComponent$$1;
31645 Node.prototype = Object.create( GraphComponent$$1 && GraphComponent$$1.prototype );
31646 Node.prototype.constructor = Node;
31647 Node.prototype.isIncidentEdgeInResult = function isIncidentEdgeInResult () {
31648 for (var it = this.getEdges().getEdges().iterator(); it.hasNext();) {
31649 var de = it.next();
31650 if (de.getEdge().isInResult()) { return true }
31651 }
31652 return false
31653 };
31654 Node.prototype.isIsolated = function isIsolated () {
31655 return this._label.getGeometryCount() === 1
31656 };
31657 Node.prototype.getCoordinate = function getCoordinate () {
31658 return this._coord
31659 };
31660 Node.prototype.print = function print (out) {
31661 out.println('node ' + this._coord + ' lbl: ' + this._label);
31662 };
31663 Node.prototype.computeIM = function computeIM (im) {};
31664 Node.prototype.computeMergedLocation = function computeMergedLocation (label2, eltIndex) {
31665 var loc = Location.NONE;
31666 loc = this._label.getLocation(eltIndex);
31667 if (!label2.isNull(eltIndex)) {
31668 var nLoc = label2.getLocation(eltIndex);
31669 if (loc !== Location.BOUNDARY) { loc = nLoc; }
31670 }
31671 return loc
31672 };
31673 Node.prototype.setLabel = function setLabel () {
31674 if (arguments.length === 2) {
31675 var argIndex = arguments[0];
31676 var onLocation = arguments[1];
31677 if (this._label === null) {
31678 this._label = new Label(argIndex, onLocation);
31679 } else { this._label.setLocation(argIndex, onLocation); }
31680 } else { return GraphComponent$$1.prototype.setLabel.apply(this, arguments) }
31681 };
31682 Node.prototype.getEdges = function getEdges () {
31683 return this._edges
31684 };
31685 Node.prototype.mergeLabel = function mergeLabel () {
31686 var this$1 = this;
31687
31688 if (arguments[0] instanceof Node) {
31689 var n = arguments[0];
31690 this.mergeLabel(n._label);
31691 } else if (arguments[0] instanceof Label) {
31692 var label2 = arguments[0];
31693 for (var i = 0; i < 2; i++) {
31694 var loc = this$1.computeMergedLocation(label2, i);
31695 var thisLoc = this$1._label.getLocation(i);
31696 if (thisLoc === Location.NONE) { this$1._label.setLocation(i, loc); }
31697 }
31698 }
31699 };
31700 Node.prototype.add = function add (e) {
31701 this._edges.insert(e);
31702 e.setNode(this);
31703 };
31704 Node.prototype.setLabelBoundary = function setLabelBoundary (argIndex) {
31705 if (this._label === null) { return null }
31706 var loc = Location.NONE;
31707 if (this._label !== null) { loc = this._label.getLocation(argIndex); }
31708 var newLoc = null;
31709 switch (loc) {
31710 case Location.BOUNDARY:
31711 newLoc = Location.INTERIOR;
31712 break
31713 case Location.INTERIOR:
31714 newLoc = Location.BOUNDARY;
31715 break
31716 default:
31717 newLoc = Location.BOUNDARY;
31718 break
31719 }
31720 this._label.setLocation(argIndex, newLoc);
31721 };
31722 Node.prototype.interfaces_ = function interfaces_ () {
31723 return []
31724 };
31725 Node.prototype.getClass = function getClass () {
31726 return Node
31727 };
31728
31729 return Node;
31730}(GraphComponent));
31731
31732var NodeMap = function NodeMap () {
31733 this.nodeMap = new TreeMap();
31734 this.nodeFact = null;
31735 var nodeFact = arguments[0];
31736 this.nodeFact = nodeFact;
31737};
31738NodeMap.prototype.find = function find (coord) {
31739 return this.nodeMap.get(coord)
31740};
31741NodeMap.prototype.addNode = function addNode () {
31742 if (arguments[0] instanceof Coordinate) {
31743 var coord = arguments[0];
31744 var node = this.nodeMap.get(coord);
31745 if (node === null) {
31746 node = this.nodeFact.createNode(coord);
31747 this.nodeMap.put(coord, node);
31748 }
31749 return node
31750 } else if (arguments[0] instanceof Node$2) {
31751 var n = arguments[0];
31752 var node$1 = this.nodeMap.get(n.getCoordinate());
31753 if (node$1 === null) {
31754 this.nodeMap.put(n.getCoordinate(), n);
31755 return n
31756 }
31757 node$1.mergeLabel(n);
31758 return node$1
31759 }
31760};
31761NodeMap.prototype.print = function print (out) {
31762 for (var it = this.iterator(); it.hasNext();) {
31763 var n = it.next();
31764 n.print(out);
31765 }
31766};
31767NodeMap.prototype.iterator = function iterator () {
31768 return this.nodeMap.values().iterator()
31769};
31770NodeMap.prototype.values = function values () {
31771 return this.nodeMap.values()
31772};
31773NodeMap.prototype.getBoundaryNodes = function getBoundaryNodes (geomIndex) {
31774 var bdyNodes = new ArrayList();
31775 for (var i = this.iterator(); i.hasNext();) {
31776 var node = i.next();
31777 if (node.getLabel().getLocation(geomIndex) === Location.BOUNDARY) { bdyNodes.add(node); }
31778 }
31779 return bdyNodes
31780};
31781NodeMap.prototype.add = function add (e) {
31782 var p = e.getCoordinate();
31783 var n = this.addNode(p);
31784 n.add(e);
31785};
31786NodeMap.prototype.interfaces_ = function interfaces_ () {
31787 return []
31788};
31789NodeMap.prototype.getClass = function getClass () {
31790 return NodeMap
31791};
31792
31793var Quadrant = function Quadrant () {};
31794
31795var staticAccessors$21 = { NE: { configurable: true },NW: { configurable: true },SW: { configurable: true },SE: { configurable: true } };
31796
31797Quadrant.prototype.interfaces_ = function interfaces_ () {
31798 return []
31799};
31800Quadrant.prototype.getClass = function getClass () {
31801 return Quadrant
31802};
31803Quadrant.isNorthern = function isNorthern (quad) {
31804 return quad === Quadrant.NE || quad === Quadrant.NW
31805};
31806Quadrant.isOpposite = function isOpposite (quad1, quad2) {
31807 if (quad1 === quad2) { return false }
31808 var diff = (quad1 - quad2 + 4) % 4;
31809 if (diff === 2) { return true }
31810 return false
31811};
31812Quadrant.commonHalfPlane = function commonHalfPlane (quad1, quad2) {
31813 if (quad1 === quad2) { return quad1 }
31814 var diff = (quad1 - quad2 + 4) % 4;
31815 if (diff === 2) { return -1 }
31816 var min = quad1 < quad2 ? quad1 : quad2;
31817 var max = quad1 > quad2 ? quad1 : quad2;
31818 if (min === 0 && max === 3) { return 3 }
31819 return min
31820};
31821Quadrant.isInHalfPlane = function isInHalfPlane (quad, halfPlane) {
31822 if (halfPlane === Quadrant.SE) {
31823 return quad === Quadrant.SE || quad === Quadrant.SW
31824 }
31825 return quad === halfPlane || quad === halfPlane + 1
31826};
31827Quadrant.quadrant = function quadrant () {
31828 if (typeof arguments[0] === 'number' && typeof arguments[1] === 'number') {
31829 var dx = arguments[0];
31830 var dy = arguments[1];
31831 if (dx === 0.0 && dy === 0.0) { throw new IllegalArgumentException('Cannot compute the quadrant for point ( ' + dx + ', ' + dy + ' )') }
31832 if (dx >= 0.0) {
31833 if (dy >= 0.0) { return Quadrant.NE; } else { return Quadrant.SE }
31834 } else {
31835 if (dy >= 0.0) { return Quadrant.NW; } else { return Quadrant.SW }
31836 }
31837 } else if (arguments[0] instanceof Coordinate && arguments[1] instanceof Coordinate) {
31838 var p0 = arguments[0];
31839 var p1 = arguments[1];
31840 if (p1.x === p0.x && p1.y === p0.y) { throw new IllegalArgumentException('Cannot compute the quadrant for two identical points ' + p0) }
31841 if (p1.x >= p0.x) {
31842 if (p1.y >= p0.y) { return Quadrant.NE; } else { return Quadrant.SE }
31843 } else {
31844 if (p1.y >= p0.y) { return Quadrant.NW; } else { return Quadrant.SW }
31845 }
31846 }
31847};
31848staticAccessors$21.NE.get = function () { return 0 };
31849staticAccessors$21.NW.get = function () { return 1 };
31850staticAccessors$21.SW.get = function () { return 2 };
31851staticAccessors$21.SE.get = function () { return 3 };
31852
31853Object.defineProperties( Quadrant, staticAccessors$21 );
31854
31855var EdgeEnd = function EdgeEnd () {
31856 this._edge = null;
31857 this._label = null;
31858 this._node = null;
31859 this._p0 = null;
31860 this._p1 = null;
31861 this._dx = null;
31862 this._dy = null;
31863 this._quadrant = null;
31864 if (arguments.length === 1) {
31865 var edge = arguments[0];
31866 this._edge = edge;
31867 } else if (arguments.length === 3) {
31868 var edge$1 = arguments[0];
31869 var p0 = arguments[1];
31870 var p1 = arguments[2];
31871 var label = null;
31872 this._edge = edge$1;
31873 this.init(p0, p1);
31874 this._label = label;
31875 } else if (arguments.length === 4) {
31876 var edge$2 = arguments[0];
31877 var p0$1 = arguments[1];
31878 var p1$1 = arguments[2];
31879 var label$1 = arguments[3];
31880 this._edge = edge$2;
31881 this.init(p0$1, p1$1);
31882 this._label = label$1;
31883 }
31884};
31885EdgeEnd.prototype.compareDirection = function compareDirection (e) {
31886 if (this._dx === e._dx && this._dy === e._dy) { return 0 }
31887 if (this._quadrant > e._quadrant) { return 1 }
31888 if (this._quadrant < e._quadrant) { return -1 }
31889 return CGAlgorithms.computeOrientation(e._p0, e._p1, this._p1)
31890};
31891EdgeEnd.prototype.getDy = function getDy () {
31892 return this._dy
31893};
31894EdgeEnd.prototype.getCoordinate = function getCoordinate () {
31895 return this._p0
31896};
31897EdgeEnd.prototype.setNode = function setNode (node) {
31898 this._node = node;
31899};
31900EdgeEnd.prototype.print = function print (out) {
31901 var angle = Math.atan2(this._dy, this._dx);
31902 var className = this.getClass().getName();
31903 var lastDotPos = className.lastIndexOf('.');
31904 var name = className.substring(lastDotPos + 1);
31905 out.print(' ' + name + ': ' + this._p0 + ' - ' + this._p1 + ' ' + this._quadrant + ':' + angle + ' ' + this._label);
31906};
31907EdgeEnd.prototype.compareTo = function compareTo (obj) {
31908 var e = obj;
31909 return this.compareDirection(e)
31910};
31911EdgeEnd.prototype.getDirectedCoordinate = function getDirectedCoordinate () {
31912 return this._p1
31913};
31914EdgeEnd.prototype.getDx = function getDx () {
31915 return this._dx
31916};
31917EdgeEnd.prototype.getLabel = function getLabel () {
31918 return this._label
31919};
31920EdgeEnd.prototype.getEdge = function getEdge () {
31921 return this._edge
31922};
31923EdgeEnd.prototype.getQuadrant = function getQuadrant () {
31924 return this._quadrant
31925};
31926EdgeEnd.prototype.getNode = function getNode () {
31927 return this._node
31928};
31929EdgeEnd.prototype.toString = function toString () {
31930 var angle = Math.atan2(this._dy, this._dx);
31931 var className = this.getClass().getName();
31932 var lastDotPos = className.lastIndexOf('.');
31933 var name = className.substring(lastDotPos + 1);
31934 return ' ' + name + ': ' + this._p0 + ' - ' + this._p1 + ' ' + this._quadrant + ':' + angle + ' ' + this._label
31935};
31936EdgeEnd.prototype.computeLabel = function computeLabel (boundaryNodeRule) {};
31937EdgeEnd.prototype.init = function init (p0, p1) {
31938 this._p0 = p0;
31939 this._p1 = p1;
31940 this._dx = p1.x - p0.x;
31941 this._dy = p1.y - p0.y;
31942 this._quadrant = Quadrant.quadrant(this._dx, this._dy);
31943 Assert.isTrue(!(this._dx === 0 && this._dy === 0), 'EdgeEnd with identical endpoints found');
31944};
31945EdgeEnd.prototype.interfaces_ = function interfaces_ () {
31946 return [Comparable]
31947};
31948EdgeEnd.prototype.getClass = function getClass () {
31949 return EdgeEnd
31950};
31951
31952var DirectedEdge = (function (EdgeEnd$$1) {
31953 function DirectedEdge () {
31954 var edge = arguments[0];
31955 var isForward = arguments[1];
31956 EdgeEnd$$1.call(this, edge);
31957 this._isForward = null;
31958 this._isInResult = false;
31959 this._isVisited = false;
31960 this._sym = null;
31961 this._next = null;
31962 this._nextMin = null;
31963 this._edgeRing = null;
31964 this._minEdgeRing = null;
31965 this._depth = [0, -999, -999];
31966 this._isForward = isForward;
31967 if (isForward) {
31968 this.init(edge.getCoordinate(0), edge.getCoordinate(1));
31969 } else {
31970 var n = edge.getNumPoints() - 1;
31971 this.init(edge.getCoordinate(n), edge.getCoordinate(n - 1));
31972 }
31973 this.computeDirectedLabel();
31974 }
31975
31976 if ( EdgeEnd$$1 ) DirectedEdge.__proto__ = EdgeEnd$$1;
31977 DirectedEdge.prototype = Object.create( EdgeEnd$$1 && EdgeEnd$$1.prototype );
31978 DirectedEdge.prototype.constructor = DirectedEdge;
31979 DirectedEdge.prototype.getNextMin = function getNextMin () {
31980 return this._nextMin
31981 };
31982 DirectedEdge.prototype.getDepth = function getDepth (position) {
31983 return this._depth[position]
31984 };
31985 DirectedEdge.prototype.setVisited = function setVisited (isVisited) {
31986 this._isVisited = isVisited;
31987 };
31988 DirectedEdge.prototype.computeDirectedLabel = function computeDirectedLabel () {
31989 this._label = new Label(this._edge.getLabel());
31990 if (!this._isForward) { this._label.flip(); }
31991 };
31992 DirectedEdge.prototype.getNext = function getNext () {
31993 return this._next
31994 };
31995 DirectedEdge.prototype.setDepth = function setDepth (position, depthVal) {
31996 if (this._depth[position] !== -999) {
31997 if (this._depth[position] !== depthVal) { throw new TopologyException('assigned depths do not match', this.getCoordinate()) }
31998 }
31999 this._depth[position] = depthVal;
32000 };
32001 DirectedEdge.prototype.isInteriorAreaEdge = function isInteriorAreaEdge () {
32002 var this$1 = this;
32003
32004 var isInteriorAreaEdge = true;
32005 for (var i = 0; i < 2; i++) {
32006 if (!(this$1._label.isArea(i) && this$1._label.getLocation(i, Position.LEFT) === Location.INTERIOR && this$1._label.getLocation(i, Position.RIGHT) === Location.INTERIOR)) {
32007 isInteriorAreaEdge = false;
32008 }
32009 }
32010 return isInteriorAreaEdge
32011 };
32012 DirectedEdge.prototype.setNextMin = function setNextMin (nextMin) {
32013 this._nextMin = nextMin;
32014 };
32015 DirectedEdge.prototype.print = function print (out) {
32016 EdgeEnd$$1.prototype.print.call(this, out);
32017 out.print(' ' + this._depth[Position.LEFT] + '/' + this._depth[Position.RIGHT]);
32018 out.print(' (' + this.getDepthDelta() + ')');
32019 if (this._isInResult) { out.print(' inResult'); }
32020 };
32021 DirectedEdge.prototype.setMinEdgeRing = function setMinEdgeRing (minEdgeRing) {
32022 this._minEdgeRing = minEdgeRing;
32023 };
32024 DirectedEdge.prototype.isLineEdge = function isLineEdge () {
32025 var isLine = this._label.isLine(0) || this._label.isLine(1);
32026 var isExteriorIfArea0 = !this._label.isArea(0) || this._label.allPositionsEqual(0, Location.EXTERIOR);
32027 var isExteriorIfArea1 = !this._label.isArea(1) || this._label.allPositionsEqual(1, Location.EXTERIOR);
32028 return isLine && isExteriorIfArea0 && isExteriorIfArea1
32029 };
32030 DirectedEdge.prototype.setEdgeRing = function setEdgeRing (edgeRing) {
32031 this._edgeRing = edgeRing;
32032 };
32033 DirectedEdge.prototype.getMinEdgeRing = function getMinEdgeRing () {
32034 return this._minEdgeRing
32035 };
32036 DirectedEdge.prototype.getDepthDelta = function getDepthDelta () {
32037 var depthDelta = this._edge.getDepthDelta();
32038 if (!this._isForward) { depthDelta = -depthDelta; }
32039 return depthDelta
32040 };
32041 DirectedEdge.prototype.setInResult = function setInResult (isInResult) {
32042 this._isInResult = isInResult;
32043 };
32044 DirectedEdge.prototype.getSym = function getSym () {
32045 return this._sym
32046 };
32047 DirectedEdge.prototype.isForward = function isForward () {
32048 return this._isForward
32049 };
32050 DirectedEdge.prototype.getEdge = function getEdge () {
32051 return this._edge
32052 };
32053 DirectedEdge.prototype.printEdge = function printEdge (out) {
32054 this.print(out);
32055 out.print(' ');
32056 if (this._isForward) { this._edge.print(out); } else { this._edge.printReverse(out); }
32057 };
32058 DirectedEdge.prototype.setSym = function setSym (de) {
32059 this._sym = de;
32060 };
32061 DirectedEdge.prototype.setVisitedEdge = function setVisitedEdge (isVisited) {
32062 this.setVisited(isVisited);
32063 this._sym.setVisited(isVisited);
32064 };
32065 DirectedEdge.prototype.setEdgeDepths = function setEdgeDepths (position, depth) {
32066 var depthDelta = this.getEdge().getDepthDelta();
32067 if (!this._isForward) { depthDelta = -depthDelta; }
32068 var directionFactor = 1;
32069 if (position === Position.LEFT) { directionFactor = -1; }
32070 var oppositePos = Position.opposite(position);
32071 var delta = depthDelta * directionFactor;
32072 var oppositeDepth = depth + delta;
32073 this.setDepth(position, depth);
32074 this.setDepth(oppositePos, oppositeDepth);
32075 };
32076 DirectedEdge.prototype.getEdgeRing = function getEdgeRing () {
32077 return this._edgeRing
32078 };
32079 DirectedEdge.prototype.isInResult = function isInResult () {
32080 return this._isInResult
32081 };
32082 DirectedEdge.prototype.setNext = function setNext (next) {
32083 this._next = next;
32084 };
32085 DirectedEdge.prototype.isVisited = function isVisited () {
32086 return this._isVisited
32087 };
32088 DirectedEdge.prototype.interfaces_ = function interfaces_ () {
32089 return []
32090 };
32091 DirectedEdge.prototype.getClass = function getClass () {
32092 return DirectedEdge
32093 };
32094 DirectedEdge.depthFactor = function depthFactor (currLocation, nextLocation) {
32095 if (currLocation === Location.EXTERIOR && nextLocation === Location.INTERIOR) { return 1; } else if (currLocation === Location.INTERIOR && nextLocation === Location.EXTERIOR) { return -1 }
32096 return 0
32097 };
32098
32099 return DirectedEdge;
32100}(EdgeEnd));
32101
32102var NodeFactory = function NodeFactory () {};
32103
32104NodeFactory.prototype.createNode = function createNode (coord) {
32105 return new Node$2(coord, null)
32106};
32107NodeFactory.prototype.interfaces_ = function interfaces_ () {
32108 return []
32109};
32110NodeFactory.prototype.getClass = function getClass () {
32111 return NodeFactory
32112};
32113
32114var PlanarGraph = function PlanarGraph () {
32115 this._edges = new ArrayList();
32116 this._nodes = null;
32117 this._edgeEndList = new ArrayList();
32118 if (arguments.length === 0) {
32119 this._nodes = new NodeMap(new NodeFactory());
32120 } else if (arguments.length === 1) {
32121 var nodeFact = arguments[0];
32122 this._nodes = new NodeMap(nodeFact);
32123 }
32124};
32125PlanarGraph.prototype.printEdges = function printEdges (out) {
32126 var this$1 = this;
32127
32128 out.println('Edges:');
32129 for (var i = 0; i < this._edges.size(); i++) {
32130 out.println('edge ' + i + ':');
32131 var e = this$1._edges.get(i);
32132 e.print(out);
32133 e.eiList.print(out);
32134 }
32135};
32136PlanarGraph.prototype.find = function find (coord) {
32137 return this._nodes.find(coord)
32138};
32139PlanarGraph.prototype.addNode = function addNode () {
32140 if (arguments[0] instanceof Node$2) {
32141 var node = arguments[0];
32142 return this._nodes.addNode(node)
32143 } else if (arguments[0] instanceof Coordinate) {
32144 var coord = arguments[0];
32145 return this._nodes.addNode(coord)
32146 }
32147};
32148PlanarGraph.prototype.getNodeIterator = function getNodeIterator () {
32149 return this._nodes.iterator()
32150};
32151PlanarGraph.prototype.linkResultDirectedEdges = function linkResultDirectedEdges () {
32152 for (var nodeit = this._nodes.iterator(); nodeit.hasNext();) {
32153 var node = nodeit.next();
32154 node.getEdges().linkResultDirectedEdges();
32155 }
32156};
32157PlanarGraph.prototype.debugPrintln = function debugPrintln (o) {
32158 System.out.println(o);
32159};
32160PlanarGraph.prototype.isBoundaryNode = function isBoundaryNode (geomIndex, coord) {
32161 var node = this._nodes.find(coord);
32162 if (node === null) { return false }
32163 var label = node.getLabel();
32164 if (label !== null && label.getLocation(geomIndex) === Location.BOUNDARY) { return true }
32165 return false
32166};
32167PlanarGraph.prototype.linkAllDirectedEdges = function linkAllDirectedEdges () {
32168 for (var nodeit = this._nodes.iterator(); nodeit.hasNext();) {
32169 var node = nodeit.next();
32170 node.getEdges().linkAllDirectedEdges();
32171 }
32172};
32173PlanarGraph.prototype.matchInSameDirection = function matchInSameDirection (p0, p1, ep0, ep1) {
32174 if (!p0.equals(ep0)) { return false }
32175 if (CGAlgorithms.computeOrientation(p0, p1, ep1) === CGAlgorithms.COLLINEAR && Quadrant.quadrant(p0, p1) === Quadrant.quadrant(ep0, ep1)) { return true }
32176 return false
32177};
32178PlanarGraph.prototype.getEdgeEnds = function getEdgeEnds () {
32179 return this._edgeEndList
32180};
32181PlanarGraph.prototype.debugPrint = function debugPrint (o) {
32182 System.out.print(o);
32183};
32184PlanarGraph.prototype.getEdgeIterator = function getEdgeIterator () {
32185 return this._edges.iterator()
32186};
32187PlanarGraph.prototype.findEdgeInSameDirection = function findEdgeInSameDirection (p0, p1) {
32188 var this$1 = this;
32189
32190 for (var i = 0; i < this._edges.size(); i++) {
32191 var e = this$1._edges.get(i);
32192 var eCoord = e.getCoordinates();
32193 if (this$1.matchInSameDirection(p0, p1, eCoord[0], eCoord[1])) { return e }
32194 if (this$1.matchInSameDirection(p0, p1, eCoord[eCoord.length - 1], eCoord[eCoord.length - 2])) { return e }
32195 }
32196 return null
32197};
32198PlanarGraph.prototype.insertEdge = function insertEdge (e) {
32199 this._edges.add(e);
32200};
32201PlanarGraph.prototype.findEdgeEnd = function findEdgeEnd (e) {
32202 for (var i = this.getEdgeEnds().iterator(); i.hasNext();) {
32203 var ee = i.next();
32204 if (ee.getEdge() === e) { return ee }
32205 }
32206 return null
32207};
32208PlanarGraph.prototype.addEdges = function addEdges (edgesToAdd) {
32209 var this$1 = this;
32210
32211 for (var it = edgesToAdd.iterator(); it.hasNext();) {
32212 var e = it.next();
32213 this$1._edges.add(e);
32214 var de1 = new DirectedEdge(e, true);
32215 var de2 = new DirectedEdge(e, false);
32216 de1.setSym(de2);
32217 de2.setSym(de1);
32218 this$1.add(de1);
32219 this$1.add(de2);
32220 }
32221};
32222PlanarGraph.prototype.add = function add (e) {
32223 this._nodes.add(e);
32224 this._edgeEndList.add(e);
32225};
32226PlanarGraph.prototype.getNodes = function getNodes () {
32227 return this._nodes.values()
32228};
32229PlanarGraph.prototype.findEdge = function findEdge (p0, p1) {
32230 var this$1 = this;
32231
32232 for (var i = 0; i < this._edges.size(); i++) {
32233 var e = this$1._edges.get(i);
32234 var eCoord = e.getCoordinates();
32235 if (p0.equals(eCoord[0]) && p1.equals(eCoord[1])) { return e }
32236 }
32237 return null
32238};
32239PlanarGraph.prototype.interfaces_ = function interfaces_ () {
32240 return []
32241};
32242PlanarGraph.prototype.getClass = function getClass () {
32243 return PlanarGraph
32244};
32245PlanarGraph.linkResultDirectedEdges = function linkResultDirectedEdges (nodes) {
32246 for (var nodeit = nodes.iterator(); nodeit.hasNext();) {
32247 var node = nodeit.next();
32248 node.getEdges().linkResultDirectedEdges();
32249 }
32250};
32251
32252var PolygonBuilder = function PolygonBuilder () {
32253 this._geometryFactory = null;
32254 this._shellList = new ArrayList();
32255 var geometryFactory = arguments[0];
32256 this._geometryFactory = geometryFactory;
32257};
32258PolygonBuilder.prototype.sortShellsAndHoles = function sortShellsAndHoles (edgeRings, shellList, freeHoleList) {
32259 for (var it = edgeRings.iterator(); it.hasNext();) {
32260 var er = it.next();
32261 if (er.isHole()) {
32262 freeHoleList.add(er);
32263 } else {
32264 shellList.add(er);
32265 }
32266 }
32267};
32268PolygonBuilder.prototype.computePolygons = function computePolygons (shellList) {
32269 var this$1 = this;
32270
32271 var resultPolyList = new ArrayList();
32272 for (var it = shellList.iterator(); it.hasNext();) {
32273 var er = it.next();
32274 var poly = er.toPolygon(this$1._geometryFactory);
32275 resultPolyList.add(poly);
32276 }
32277 return resultPolyList
32278};
32279PolygonBuilder.prototype.placeFreeHoles = function placeFreeHoles (shellList, freeHoleList) {
32280 var this$1 = this;
32281
32282 for (var it = freeHoleList.iterator(); it.hasNext();) {
32283 var hole = it.next();
32284 if (hole.getShell() === null) {
32285 var shell = this$1.findEdgeRingContaining(hole, shellList);
32286 if (shell === null) { throw new TopologyException('unable to assign hole to a shell', hole.getCoordinate(0)) }
32287 hole.setShell(shell);
32288 }
32289 }
32290};
32291PolygonBuilder.prototype.buildMinimalEdgeRings = function buildMinimalEdgeRings (maxEdgeRings, shellList, freeHoleList) {
32292 var this$1 = this;
32293
32294 var edgeRings = new ArrayList();
32295 for (var it = maxEdgeRings.iterator(); it.hasNext();) {
32296 var er = it.next();
32297 if (er.getMaxNodeDegree() > 2) {
32298 er.linkDirectedEdgesForMinimalEdgeRings();
32299 var minEdgeRings = er.buildMinimalRings();
32300 var shell = this$1.findShell(minEdgeRings);
32301 if (shell !== null) {
32302 this$1.placePolygonHoles(shell, minEdgeRings);
32303 shellList.add(shell);
32304 } else {
32305 freeHoleList.addAll(minEdgeRings);
32306 }
32307 } else {
32308 edgeRings.add(er);
32309 }
32310 }
32311 return edgeRings
32312};
32313PolygonBuilder.prototype.containsPoint = function containsPoint (p) {
32314 for (var it = this._shellList.iterator(); it.hasNext();) {
32315 var er = it.next();
32316 if (er.containsPoint(p)) { return true }
32317 }
32318 return false
32319};
32320PolygonBuilder.prototype.buildMaximalEdgeRings = function buildMaximalEdgeRings (dirEdges) {
32321 var this$1 = this;
32322
32323 var maxEdgeRings = new ArrayList();
32324 for (var it = dirEdges.iterator(); it.hasNext();) {
32325 var de = it.next();
32326 if (de.isInResult() && de.getLabel().isArea()) {
32327 if (de.getEdgeRing() === null) {
32328 var er = new MaximalEdgeRing(de, this$1._geometryFactory);
32329 maxEdgeRings.add(er);
32330 er.setInResult();
32331 }
32332 }
32333 }
32334 return maxEdgeRings
32335};
32336PolygonBuilder.prototype.placePolygonHoles = function placePolygonHoles (shell, minEdgeRings) {
32337 for (var it = minEdgeRings.iterator(); it.hasNext();) {
32338 var er = it.next();
32339 if (er.isHole()) {
32340 er.setShell(shell);
32341 }
32342 }
32343};
32344PolygonBuilder.prototype.getPolygons = function getPolygons () {
32345 var resultPolyList = this.computePolygons(this._shellList);
32346 return resultPolyList
32347};
32348PolygonBuilder.prototype.findEdgeRingContaining = function findEdgeRingContaining (testEr, shellList) {
32349 var testRing = testEr.getLinearRing();
32350 var testEnv = testRing.getEnvelopeInternal();
32351 var testPt = testRing.getCoordinateN(0);
32352 var minShell = null;
32353 var minEnv = null;
32354 for (var it = shellList.iterator(); it.hasNext();) {
32355 var tryShell = it.next();
32356 var tryRing = tryShell.getLinearRing();
32357 var tryEnv = tryRing.getEnvelopeInternal();
32358 if (minShell !== null) { minEnv = minShell.getLinearRing().getEnvelopeInternal(); }
32359 var isContained = false;
32360 if (tryEnv.contains(testEnv) && CGAlgorithms.isPointInRing(testPt, tryRing.getCoordinates())) { isContained = true; }
32361 if (isContained) {
32362 if (minShell === null || minEnv.contains(tryEnv)) {
32363 minShell = tryShell;
32364 }
32365 }
32366 }
32367 return minShell
32368};
32369PolygonBuilder.prototype.findShell = function findShell (minEdgeRings) {
32370 var shellCount = 0;
32371 var shell = null;
32372 for (var it = minEdgeRings.iterator(); it.hasNext();) {
32373 var er = it.next();
32374 if (!er.isHole()) {
32375 shell = er;
32376 shellCount++;
32377 }
32378 }
32379 Assert.isTrue(shellCount <= 1, 'found two shells in MinimalEdgeRing list');
32380 return shell
32381};
32382PolygonBuilder.prototype.add = function add () {
32383 if (arguments.length === 1) {
32384 var graph = arguments[0];
32385 this.add(graph.getEdgeEnds(), graph.getNodes());
32386 } else if (arguments.length === 2) {
32387 var dirEdges = arguments[0];
32388 var nodes = arguments[1];
32389 PlanarGraph.linkResultDirectedEdges(nodes);
32390 var maxEdgeRings = this.buildMaximalEdgeRings(dirEdges);
32391 var freeHoleList = new ArrayList();
32392 var edgeRings = this.buildMinimalEdgeRings(maxEdgeRings, this._shellList, freeHoleList);
32393 this.sortShellsAndHoles(edgeRings, this._shellList, freeHoleList);
32394 this.placeFreeHoles(this._shellList, freeHoleList);
32395 }
32396};
32397PolygonBuilder.prototype.interfaces_ = function interfaces_ () {
32398 return []
32399};
32400PolygonBuilder.prototype.getClass = function getClass () {
32401 return PolygonBuilder
32402};
32403
32404var Boundable = function Boundable () {};
32405
32406Boundable.prototype.getBounds = function getBounds () {};
32407Boundable.prototype.interfaces_ = function interfaces_ () {
32408 return []
32409};
32410Boundable.prototype.getClass = function getClass () {
32411 return Boundable
32412};
32413
32414var ItemBoundable = function ItemBoundable () {
32415 this._bounds = null;
32416 this._item = null;
32417 var bounds = arguments[0];
32418 var item = arguments[1];
32419 this._bounds = bounds;
32420 this._item = item;
32421};
32422ItemBoundable.prototype.getItem = function getItem () {
32423 return this._item
32424};
32425ItemBoundable.prototype.getBounds = function getBounds () {
32426 return this._bounds
32427};
32428ItemBoundable.prototype.interfaces_ = function interfaces_ () {
32429 return [Boundable, Serializable]
32430};
32431ItemBoundable.prototype.getClass = function getClass () {
32432 return ItemBoundable
32433};
32434
32435var PriorityQueue = function PriorityQueue () {
32436 this._size = null;
32437 this._items = null;
32438 this._size = 0;
32439 this._items = new ArrayList();
32440 this._items.add(null);
32441};
32442PriorityQueue.prototype.poll = function poll () {
32443 if (this.isEmpty()) { return null }
32444 var minItem = this._items.get(1);
32445 this._items.set(1, this._items.get(this._size));
32446 this._size -= 1;
32447 this.reorder(1);
32448 return minItem
32449};
32450PriorityQueue.prototype.size = function size () {
32451 return this._size
32452};
32453PriorityQueue.prototype.reorder = function reorder (hole) {
32454 var this$1 = this;
32455
32456 var child = null;
32457 var tmp = this._items.get(hole);
32458 for (; hole * 2 <= this._size; hole = child) {
32459 child = hole * 2;
32460 if (child !== this$1._size && this$1._items.get(child + 1).compareTo(this$1._items.get(child)) < 0) { child++; }
32461 if (this$1._items.get(child).compareTo(tmp) < 0) { this$1._items.set(hole, this$1._items.get(child)); } else { break }
32462 }
32463 this._items.set(hole, tmp);
32464};
32465PriorityQueue.prototype.clear = function clear () {
32466 this._size = 0;
32467 this._items.clear();
32468};
32469PriorityQueue.prototype.isEmpty = function isEmpty () {
32470 return this._size === 0
32471};
32472PriorityQueue.prototype.add = function add (x) {
32473 var this$1 = this;
32474
32475 this._items.add(null);
32476 this._size += 1;
32477 var hole = this._size;
32478 this._items.set(0, x);
32479 for (; x.compareTo(this._items.get(Math.trunc(hole / 2))) < 0; hole /= 2) {
32480 this$1._items.set(hole, this$1._items.get(Math.trunc(hole / 2)));
32481 }
32482 this._items.set(hole, x);
32483};
32484PriorityQueue.prototype.interfaces_ = function interfaces_ () {
32485 return []
32486};
32487PriorityQueue.prototype.getClass = function getClass () {
32488 return PriorityQueue
32489};
32490
32491var ItemVisitor = function ItemVisitor () {};
32492
32493ItemVisitor.prototype.visitItem = function visitItem (item) {};
32494ItemVisitor.prototype.interfaces_ = function interfaces_ () {
32495 return []
32496};
32497ItemVisitor.prototype.getClass = function getClass () {
32498 return ItemVisitor
32499};
32500
32501var SpatialIndex = function SpatialIndex () {};
32502
32503SpatialIndex.prototype.insert = function insert (itemEnv, item) {};
32504SpatialIndex.prototype.remove = function remove (itemEnv, item) {};
32505SpatialIndex.prototype.query = function query () {
32506 // if (arguments.length === 1) {
32507 // const searchEnv = arguments[0]
32508 // } else if (arguments.length === 2) {
32509 // const searchEnv = arguments[0]
32510 // const visitor = arguments[1]
32511 // }
32512};
32513SpatialIndex.prototype.interfaces_ = function interfaces_ () {
32514 return []
32515};
32516SpatialIndex.prototype.getClass = function getClass () {
32517 return SpatialIndex
32518};
32519
32520var AbstractNode = function AbstractNode () {
32521 this._childBoundables = new ArrayList();
32522 this._bounds = null;
32523 this._level = null;
32524 if (arguments.length === 0) {} else if (arguments.length === 1) {
32525 var level = arguments[0];
32526 this._level = level;
32527 }
32528};
32529
32530var staticAccessors$22 = { serialVersionUID: { configurable: true } };
32531AbstractNode.prototype.getLevel = function getLevel () {
32532 return this._level
32533};
32534AbstractNode.prototype.size = function size () {
32535 return this._childBoundables.size()
32536};
32537AbstractNode.prototype.getChildBoundables = function getChildBoundables () {
32538 return this._childBoundables
32539};
32540AbstractNode.prototype.addChildBoundable = function addChildBoundable (childBoundable) {
32541 Assert.isTrue(this._bounds === null);
32542 this._childBoundables.add(childBoundable);
32543};
32544AbstractNode.prototype.isEmpty = function isEmpty () {
32545 return this._childBoundables.isEmpty()
32546};
32547AbstractNode.prototype.getBounds = function getBounds () {
32548 if (this._bounds === null) {
32549 this._bounds = this.computeBounds();
32550 }
32551 return this._bounds
32552};
32553AbstractNode.prototype.interfaces_ = function interfaces_ () {
32554 return [Boundable, Serializable]
32555};
32556AbstractNode.prototype.getClass = function getClass () {
32557 return AbstractNode
32558};
32559staticAccessors$22.serialVersionUID.get = function () { return 6493722185909573708 };
32560
32561Object.defineProperties( AbstractNode, staticAccessors$22 );
32562
32563var Collections = function Collections () {};
32564
32565Collections.reverseOrder = function reverseOrder () {
32566 return {
32567 compare: function compare (a, b) {
32568 return b.compareTo(a)
32569 }
32570 }
32571};
32572Collections.min = function min (l) {
32573 Collections.sort(l);
32574 return l.get(0)
32575};
32576Collections.sort = function sort (l, c) {
32577 var a = l.toArray();
32578 if (c) {
32579 Arrays.sort(a, c);
32580 } else {
32581 Arrays.sort(a);
32582 }
32583 var i = l.iterator();
32584 for (var pos = 0, alen = a.length; pos < alen; pos++) {
32585 i.next();
32586 i.set(a[pos]);
32587 }
32588};
32589Collections.singletonList = function singletonList (o) {
32590 var arrayList = new ArrayList();
32591 arrayList.add(o);
32592 return arrayList
32593};
32594
32595var BoundablePair = function BoundablePair () {
32596 this._boundable1 = null;
32597 this._boundable2 = null;
32598 this._distance = null;
32599 this._itemDistance = null;
32600 var boundable1 = arguments[0];
32601 var boundable2 = arguments[1];
32602 var itemDistance = arguments[2];
32603 this._boundable1 = boundable1;
32604 this._boundable2 = boundable2;
32605 this._itemDistance = itemDistance;
32606 this._distance = this.distance();
32607};
32608BoundablePair.prototype.expandToQueue = function expandToQueue (priQ, minDistance) {
32609 var isComp1 = BoundablePair.isComposite(this._boundable1);
32610 var isComp2 = BoundablePair.isComposite(this._boundable2);
32611 if (isComp1 && isComp2) {
32612 if (BoundablePair.area(this._boundable1) > BoundablePair.area(this._boundable2)) {
32613 this.expand(this._boundable1, this._boundable2, priQ, minDistance);
32614 return null
32615 } else {
32616 this.expand(this._boundable2, this._boundable1, priQ, minDistance);
32617 return null
32618 }
32619 } else if (isComp1) {
32620 this.expand(this._boundable1, this._boundable2, priQ, minDistance);
32621 return null
32622 } else if (isComp2) {
32623 this.expand(this._boundable2, this._boundable1, priQ, minDistance);
32624 return null
32625 }
32626 throw new IllegalArgumentException('neither boundable is composite')
32627};
32628BoundablePair.prototype.isLeaves = function isLeaves () {
32629 return !(BoundablePair.isComposite(this._boundable1) || BoundablePair.isComposite(this._boundable2))
32630};
32631BoundablePair.prototype.compareTo = function compareTo (o) {
32632 var nd = o;
32633 if (this._distance < nd._distance) { return -1 }
32634 if (this._distance > nd._distance) { return 1 }
32635 return 0
32636};
32637BoundablePair.prototype.expand = function expand (bndComposite, bndOther, priQ, minDistance) {
32638 var this$1 = this;
32639
32640 var children = bndComposite.getChildBoundables();
32641 for (var i = children.iterator(); i.hasNext();) {
32642 var child = i.next();
32643 var bp = new BoundablePair(child, bndOther, this$1._itemDistance);
32644 if (bp.getDistance() < minDistance) {
32645 priQ.add(bp);
32646 }
32647 }
32648};
32649BoundablePair.prototype.getBoundable = function getBoundable (i) {
32650 if (i === 0) { return this._boundable1 }
32651 return this._boundable2
32652};
32653BoundablePair.prototype.getDistance = function getDistance () {
32654 return this._distance
32655};
32656BoundablePair.prototype.distance = function distance () {
32657 if (this.isLeaves()) {
32658 return this._itemDistance.distance(this._boundable1, this._boundable2)
32659 }
32660 return this._boundable1.getBounds().distance(this._boundable2.getBounds())
32661};
32662BoundablePair.prototype.interfaces_ = function interfaces_ () {
32663 return [Comparable]
32664};
32665BoundablePair.prototype.getClass = function getClass () {
32666 return BoundablePair
32667};
32668BoundablePair.area = function area (b) {
32669 return b.getBounds().getArea()
32670};
32671BoundablePair.isComposite = function isComposite (item) {
32672 return item instanceof AbstractNode
32673};
32674
32675var AbstractSTRtree = function AbstractSTRtree () {
32676 this._root = null;
32677 this._built = false;
32678 this._itemBoundables = new ArrayList();
32679 this._nodeCapacity = null;
32680 if (arguments.length === 0) {
32681 var nodeCapacity = AbstractSTRtree.DEFAULT_NODE_CAPACITY;
32682 this._nodeCapacity = nodeCapacity;
32683 } else if (arguments.length === 1) {
32684 var nodeCapacity$1 = arguments[0];
32685 Assert.isTrue(nodeCapacity$1 > 1, 'Node capacity must be greater than 1');
32686 this._nodeCapacity = nodeCapacity$1;
32687 }
32688};
32689
32690var staticAccessors$23 = { IntersectsOp: { configurable: true },serialVersionUID: { configurable: true },DEFAULT_NODE_CAPACITY: { configurable: true } };
32691AbstractSTRtree.prototype.getNodeCapacity = function getNodeCapacity () {
32692 return this._nodeCapacity
32693};
32694AbstractSTRtree.prototype.lastNode = function lastNode (nodes) {
32695 return nodes.get(nodes.size() - 1)
32696};
32697AbstractSTRtree.prototype.size = function size () {
32698 var this$1 = this;
32699
32700 if (arguments.length === 0) {
32701 if (this.isEmpty()) {
32702 return 0
32703 }
32704 this.build();
32705 return this.size(this._root)
32706 } else if (arguments.length === 1) {
32707 var node = arguments[0];
32708 var size = 0;
32709 for (var i = node.getChildBoundables().iterator(); i.hasNext();) {
32710 var childBoundable = i.next();
32711 if (childBoundable instanceof AbstractNode) {
32712 size += this$1.size(childBoundable);
32713 } else if (childBoundable instanceof ItemBoundable) {
32714 size += 1;
32715 }
32716 }
32717 return size
32718 }
32719};
32720AbstractSTRtree.prototype.removeItem = function removeItem (node, item) {
32721 var childToRemove = null;
32722 for (var i = node.getChildBoundables().iterator(); i.hasNext();) {
32723 var childBoundable = i.next();
32724 if (childBoundable instanceof ItemBoundable) {
32725 if (childBoundable.getItem() === item) { childToRemove = childBoundable; }
32726 }
32727 }
32728 if (childToRemove !== null) {
32729 node.getChildBoundables().remove(childToRemove);
32730 return true
32731 }
32732 return false
32733};
32734AbstractSTRtree.prototype.itemsTree = function itemsTree () {
32735 var this$1 = this;
32736
32737 if (arguments.length === 0) {
32738 this.build();
32739 var valuesTree = this.itemsTree(this._root);
32740 if (valuesTree === null) { return new ArrayList() }
32741 return valuesTree
32742 } else if (arguments.length === 1) {
32743 var node = arguments[0];
32744 var valuesTreeForNode = new ArrayList();
32745 for (var i = node.getChildBoundables().iterator(); i.hasNext();) {
32746 var childBoundable = i.next();
32747 if (childBoundable instanceof AbstractNode) {
32748 var valuesTreeForChild = this$1.itemsTree(childBoundable);
32749 if (valuesTreeForChild !== null) { valuesTreeForNode.add(valuesTreeForChild); }
32750 } else if (childBoundable instanceof ItemBoundable) {
32751 valuesTreeForNode.add(childBoundable.getItem());
32752 } else {
32753 Assert.shouldNeverReachHere();
32754 }
32755 }
32756 if (valuesTreeForNode.size() <= 0) { return null }
32757 return valuesTreeForNode
32758 }
32759};
32760AbstractSTRtree.prototype.insert = function insert (bounds, item) {
32761 Assert.isTrue(!this._built, 'Cannot insert items into an STR packed R-tree after it has been built.');
32762 this._itemBoundables.add(new ItemBoundable(bounds, item));
32763};
32764AbstractSTRtree.prototype.boundablesAtLevel = function boundablesAtLevel () {
32765 var this$1 = this;
32766
32767 if (arguments.length === 1) {
32768 var level = arguments[0];
32769 var boundables = new ArrayList();
32770 this.boundablesAtLevel(level, this._root, boundables);
32771 return boundables
32772 } else if (arguments.length === 3) {
32773 var level$1 = arguments[0];
32774 var top = arguments[1];
32775 var boundables$1 = arguments[2];
32776 Assert.isTrue(level$1 > -2);
32777 if (top.getLevel() === level$1) {
32778 boundables$1.add(top);
32779 return null
32780 }
32781 for (var i = top.getChildBoundables().iterator(); i.hasNext();) {
32782 var boundable = i.next();
32783 if (boundable instanceof AbstractNode) {
32784 this$1.boundablesAtLevel(level$1, boundable, boundables$1);
32785 } else {
32786 Assert.isTrue(boundable instanceof ItemBoundable);
32787 if (level$1 === -1) {
32788 boundables$1.add(boundable);
32789 }
32790 }
32791 }
32792 return null
32793 }
32794};
32795AbstractSTRtree.prototype.query = function query () {
32796 var this$1 = this;
32797
32798 if (arguments.length === 1) {
32799 var searchBounds = arguments[0];
32800 this.build();
32801 var matches = new ArrayList();
32802 if (this.isEmpty()) {
32803 return matches
32804 }
32805 if (this.getIntersectsOp().intersects(this._root.getBounds(), searchBounds)) {
32806 this.query(searchBounds, this._root, matches);
32807 }
32808 return matches
32809 } else if (arguments.length === 2) {
32810 var searchBounds$1 = arguments[0];
32811 var visitor = arguments[1];
32812 this.build();
32813 if (this.isEmpty()) {
32814 return null
32815 }
32816 if (this.getIntersectsOp().intersects(this._root.getBounds(), searchBounds$1)) {
32817 this.query(searchBounds$1, this._root, visitor);
32818 }
32819 } else if (arguments.length === 3) {
32820 if (hasInterface(arguments[2], ItemVisitor) && (arguments[0] instanceof Object && arguments[1] instanceof AbstractNode)) {
32821 var searchBounds$2 = arguments[0];
32822 var node = arguments[1];
32823 var visitor$1 = arguments[2];
32824 var childBoundables = node.getChildBoundables();
32825 for (var i = 0; i < childBoundables.size(); i++) {
32826 var childBoundable = childBoundables.get(i);
32827 if (!this$1.getIntersectsOp().intersects(childBoundable.getBounds(), searchBounds$2)) {
32828 continue
32829 }
32830 if (childBoundable instanceof AbstractNode) {
32831 this$1.query(searchBounds$2, childBoundable, visitor$1);
32832 } else if (childBoundable instanceof ItemBoundable) {
32833 visitor$1.visitItem(childBoundable.getItem());
32834 } else {
32835 Assert.shouldNeverReachHere();
32836 }
32837 }
32838 } else if (hasInterface(arguments[2], List) && (arguments[0] instanceof Object && arguments[1] instanceof AbstractNode)) {
32839 var searchBounds$3 = arguments[0];
32840 var node$1 = arguments[1];
32841 var matches$1 = arguments[2];
32842 var childBoundables$1 = node$1.getChildBoundables();
32843 for (var i$1 = 0; i$1 < childBoundables$1.size(); i$1++) {
32844 var childBoundable$1 = childBoundables$1.get(i$1);
32845 if (!this$1.getIntersectsOp().intersects(childBoundable$1.getBounds(), searchBounds$3)) {
32846 continue
32847 }
32848 if (childBoundable$1 instanceof AbstractNode) {
32849 this$1.query(searchBounds$3, childBoundable$1, matches$1);
32850 } else if (childBoundable$1 instanceof ItemBoundable) {
32851 matches$1.add(childBoundable$1.getItem());
32852 } else {
32853 Assert.shouldNeverReachHere();
32854 }
32855 }
32856 }
32857 }
32858};
32859AbstractSTRtree.prototype.build = function build () {
32860 if (this._built) { return null }
32861 this._root = this._itemBoundables.isEmpty() ? this.createNode(0) : this.createHigherLevels(this._itemBoundables, -1);
32862 this._itemBoundables = null;
32863 this._built = true;
32864};
32865AbstractSTRtree.prototype.getRoot = function getRoot () {
32866 this.build();
32867 return this._root
32868};
32869AbstractSTRtree.prototype.remove = function remove () {
32870 var this$1 = this;
32871
32872 if (arguments.length === 2) {
32873 var searchBounds = arguments[0];
32874 var item = arguments[1];
32875 this.build();
32876 if (this.getIntersectsOp().intersects(this._root.getBounds(), searchBounds)) {
32877 return this.remove(searchBounds, this._root, item)
32878 }
32879 return false
32880 } else if (arguments.length === 3) {
32881 var searchBounds$1 = arguments[0];
32882 var node = arguments[1];
32883 var item$1 = arguments[2];
32884 var found = this.removeItem(node, item$1);
32885 if (found) { return true }
32886 var childToPrune = null;
32887 for (var i = node.getChildBoundables().iterator(); i.hasNext();) {
32888 var childBoundable = i.next();
32889 if (!this$1.getIntersectsOp().intersects(childBoundable.getBounds(), searchBounds$1)) {
32890 continue
32891 }
32892 if (childBoundable instanceof AbstractNode) {
32893 found = this$1.remove(searchBounds$1, childBoundable, item$1);
32894 if (found) {
32895 childToPrune = childBoundable;
32896 break
32897 }
32898 }
32899 }
32900 if (childToPrune !== null) {
32901 if (childToPrune.getChildBoundables().isEmpty()) {
32902 node.getChildBoundables().remove(childToPrune);
32903 }
32904 }
32905 return found
32906 }
32907};
32908AbstractSTRtree.prototype.createHigherLevels = function createHigherLevels (boundablesOfALevel, level) {
32909 Assert.isTrue(!boundablesOfALevel.isEmpty());
32910 var parentBoundables = this.createParentBoundables(boundablesOfALevel, level + 1);
32911 if (parentBoundables.size() === 1) {
32912 return parentBoundables.get(0)
32913 }
32914 return this.createHigherLevels(parentBoundables, level + 1)
32915};
32916AbstractSTRtree.prototype.depth = function depth () {
32917 var this$1 = this;
32918
32919 if (arguments.length === 0) {
32920 if (this.isEmpty()) {
32921 return 0
32922 }
32923 this.build();
32924 return this.depth(this._root)
32925 } else if (arguments.length === 1) {
32926 var node = arguments[0];
32927 var maxChildDepth = 0;
32928 for (var i = node.getChildBoundables().iterator(); i.hasNext();) {
32929 var childBoundable = i.next();
32930 if (childBoundable instanceof AbstractNode) {
32931 var childDepth = this$1.depth(childBoundable);
32932 if (childDepth > maxChildDepth) { maxChildDepth = childDepth; }
32933 }
32934 }
32935 return maxChildDepth + 1
32936 }
32937};
32938AbstractSTRtree.prototype.createParentBoundables = function createParentBoundables (childBoundables, newLevel) {
32939 var this$1 = this;
32940
32941 Assert.isTrue(!childBoundables.isEmpty());
32942 var parentBoundables = new ArrayList();
32943 parentBoundables.add(this.createNode(newLevel));
32944 var sortedChildBoundables = new ArrayList(childBoundables);
32945 Collections.sort(sortedChildBoundables, this.getComparator());
32946 for (var i = sortedChildBoundables.iterator(); i.hasNext();) {
32947 var childBoundable = i.next();
32948 if (this$1.lastNode(parentBoundables).getChildBoundables().size() === this$1.getNodeCapacity()) {
32949 parentBoundables.add(this$1.createNode(newLevel));
32950 }
32951 this$1.lastNode(parentBoundables).addChildBoundable(childBoundable);
32952 }
32953 return parentBoundables
32954};
32955AbstractSTRtree.prototype.isEmpty = function isEmpty () {
32956 if (!this._built) { return this._itemBoundables.isEmpty() }
32957 return this._root.isEmpty()
32958};
32959AbstractSTRtree.prototype.interfaces_ = function interfaces_ () {
32960 return [Serializable]
32961};
32962AbstractSTRtree.prototype.getClass = function getClass () {
32963 return AbstractSTRtree
32964};
32965AbstractSTRtree.compareDoubles = function compareDoubles (a, b) {
32966 return a > b ? 1 : a < b ? -1 : 0
32967};
32968staticAccessors$23.IntersectsOp.get = function () { return IntersectsOp };
32969staticAccessors$23.serialVersionUID.get = function () { return -3886435814360241337 };
32970staticAccessors$23.DEFAULT_NODE_CAPACITY.get = function () { return 10 };
32971
32972Object.defineProperties( AbstractSTRtree, staticAccessors$23 );
32973
32974var IntersectsOp = function IntersectsOp () {};
32975
32976var ItemDistance = function ItemDistance () {};
32977
32978ItemDistance.prototype.distance = function distance (item1, item2) {};
32979ItemDistance.prototype.interfaces_ = function interfaces_ () {
32980 return []
32981};
32982ItemDistance.prototype.getClass = function getClass () {
32983 return ItemDistance
32984};
32985
32986var STRtree = (function (AbstractSTRtree$$1) {
32987 function STRtree (nodeCapacity) {
32988 nodeCapacity = nodeCapacity || STRtree.DEFAULT_NODE_CAPACITY;
32989 AbstractSTRtree$$1.call(this, nodeCapacity);
32990 }
32991
32992 if ( AbstractSTRtree$$1 ) STRtree.__proto__ = AbstractSTRtree$$1;
32993 STRtree.prototype = Object.create( AbstractSTRtree$$1 && AbstractSTRtree$$1.prototype );
32994 STRtree.prototype.constructor = STRtree;
32995
32996 var staticAccessors = { STRtreeNode: { configurable: true },serialVersionUID: { configurable: true },xComparator: { configurable: true },yComparator: { configurable: true },intersectsOp: { configurable: true },DEFAULT_NODE_CAPACITY: { configurable: true } };
32997 STRtree.prototype.createParentBoundablesFromVerticalSlices = function createParentBoundablesFromVerticalSlices (verticalSlices, newLevel) {
32998 var this$1 = this;
32999
33000 Assert.isTrue(verticalSlices.length > 0);
33001 var parentBoundables = new ArrayList();
33002 for (var i = 0; i < verticalSlices.length; i++) {
33003 parentBoundables.addAll(this$1.createParentBoundablesFromVerticalSlice(verticalSlices[i], newLevel));
33004 }
33005 return parentBoundables
33006 };
33007 STRtree.prototype.createNode = function createNode (level) {
33008 return new STRtreeNode(level)
33009 };
33010 STRtree.prototype.size = function size () {
33011 if (arguments.length === 0) {
33012 return AbstractSTRtree$$1.prototype.size.call(this)
33013 } else { return AbstractSTRtree$$1.prototype.size.apply(this, arguments) }
33014 };
33015 STRtree.prototype.insert = function insert () {
33016 if (arguments.length === 2) {
33017 var itemEnv = arguments[0];
33018 var item = arguments[1];
33019 if (itemEnv.isNull()) {
33020 return null
33021 }
33022 AbstractSTRtree$$1.prototype.insert.call(this, itemEnv, item);
33023 } else { return AbstractSTRtree$$1.prototype.insert.apply(this, arguments) }
33024 };
33025 STRtree.prototype.getIntersectsOp = function getIntersectsOp () {
33026 return STRtree.intersectsOp
33027 };
33028 STRtree.prototype.verticalSlices = function verticalSlices (childBoundables, sliceCount) {
33029 var sliceCapacity = Math.trunc(Math.ceil(childBoundables.size() / sliceCount));
33030 var slices = new Array(sliceCount).fill(null);
33031 var i = childBoundables.iterator();
33032 for (var j = 0; j < sliceCount; j++) {
33033 slices[j] = new ArrayList();
33034 var boundablesAddedToSlice = 0;
33035 while (i.hasNext() && boundablesAddedToSlice < sliceCapacity) {
33036 var childBoundable = i.next();
33037 slices[j].add(childBoundable);
33038 boundablesAddedToSlice++;
33039 }
33040 }
33041 return slices
33042 };
33043 STRtree.prototype.query = function query () {
33044 if (arguments.length === 1) {
33045 var searchEnv = arguments[0];
33046 return AbstractSTRtree$$1.prototype.query.call(this, searchEnv)
33047 } else if (arguments.length === 2) {
33048 var searchEnv$1 = arguments[0];
33049 var visitor = arguments[1];
33050 AbstractSTRtree$$1.prototype.query.call(this, searchEnv$1, visitor);
33051 } else if (arguments.length === 3) {
33052 if (hasInterface(arguments[2], ItemVisitor) && (arguments[0] instanceof Object && arguments[1] instanceof AbstractNode)) {
33053 var searchBounds = arguments[0];
33054 var node = arguments[1];
33055 var visitor$1 = arguments[2];
33056 AbstractSTRtree$$1.prototype.query.call(this, searchBounds, node, visitor$1);
33057 } else if (hasInterface(arguments[2], List) && (arguments[0] instanceof Object && arguments[1] instanceof AbstractNode)) {
33058 var searchBounds$1 = arguments[0];
33059 var node$1 = arguments[1];
33060 var matches = arguments[2];
33061 AbstractSTRtree$$1.prototype.query.call(this, searchBounds$1, node$1, matches);
33062 }
33063 }
33064 };
33065 STRtree.prototype.getComparator = function getComparator () {
33066 return STRtree.yComparator
33067 };
33068 STRtree.prototype.createParentBoundablesFromVerticalSlice = function createParentBoundablesFromVerticalSlice (childBoundables, newLevel) {
33069 return AbstractSTRtree$$1.prototype.createParentBoundables.call(this, childBoundables, newLevel)
33070 };
33071 STRtree.prototype.remove = function remove () {
33072 if (arguments.length === 2) {
33073 var itemEnv = arguments[0];
33074 var item = arguments[1];
33075 return AbstractSTRtree$$1.prototype.remove.call(this, itemEnv, item)
33076 } else { return AbstractSTRtree$$1.prototype.remove.apply(this, arguments) }
33077 };
33078 STRtree.prototype.depth = function depth () {
33079 if (arguments.length === 0) {
33080 return AbstractSTRtree$$1.prototype.depth.call(this)
33081 } else { return AbstractSTRtree$$1.prototype.depth.apply(this, arguments) }
33082 };
33083 STRtree.prototype.createParentBoundables = function createParentBoundables (childBoundables, newLevel) {
33084 Assert.isTrue(!childBoundables.isEmpty());
33085 var minLeafCount = Math.trunc(Math.ceil(childBoundables.size() / this.getNodeCapacity()));
33086 var sortedChildBoundables = new ArrayList(childBoundables);
33087 Collections.sort(sortedChildBoundables, STRtree.xComparator);
33088 var verticalSlices = this.verticalSlices(sortedChildBoundables, Math.trunc(Math.ceil(Math.sqrt(minLeafCount))));
33089 return this.createParentBoundablesFromVerticalSlices(verticalSlices, newLevel)
33090 };
33091 STRtree.prototype.nearestNeighbour = function nearestNeighbour () {
33092 if (arguments.length === 1) {
33093 if (hasInterface(arguments[0], ItemDistance)) {
33094 var itemDist = arguments[0];
33095 var bp = new BoundablePair(this.getRoot(), this.getRoot(), itemDist);
33096 return this.nearestNeighbour(bp)
33097 } else if (arguments[0] instanceof BoundablePair) {
33098 var initBndPair = arguments[0];
33099 return this.nearestNeighbour(initBndPair, Double.POSITIVE_INFINITY)
33100 }
33101 } else if (arguments.length === 2) {
33102 if (arguments[0] instanceof STRtree && hasInterface(arguments[1], ItemDistance)) {
33103 var tree = arguments[0];
33104 var itemDist$1 = arguments[1];
33105 var bp$1 = new BoundablePair(this.getRoot(), tree.getRoot(), itemDist$1);
33106 return this.nearestNeighbour(bp$1)
33107 } else if (arguments[0] instanceof BoundablePair && typeof arguments[1] === 'number') {
33108 var initBndPair$1 = arguments[0];
33109 var maxDistance = arguments[1];
33110 var distanceLowerBound = maxDistance;
33111 var minPair = null;
33112 var priQ = new PriorityQueue();
33113 priQ.add(initBndPair$1);
33114 while (!priQ.isEmpty() && distanceLowerBound > 0.0) {
33115 var bndPair = priQ.poll();
33116 var currentDistance = bndPair.getDistance();
33117 if (currentDistance >= distanceLowerBound) { break }
33118 if (bndPair.isLeaves()) {
33119 distanceLowerBound = currentDistance;
33120 minPair = bndPair;
33121 } else {
33122 bndPair.expandToQueue(priQ, distanceLowerBound);
33123 }
33124 }
33125 return [minPair.getBoundable(0).getItem(), minPair.getBoundable(1).getItem()]
33126 }
33127 } else if (arguments.length === 3) {
33128 var env = arguments[0];
33129 var item = arguments[1];
33130 var itemDist$2 = arguments[2];
33131 var bnd = new ItemBoundable(env, item);
33132 var bp$2 = new BoundablePair(this.getRoot(), bnd, itemDist$2);
33133 return this.nearestNeighbour(bp$2)[0]
33134 }
33135 };
33136 STRtree.prototype.interfaces_ = function interfaces_ () {
33137 return [SpatialIndex, Serializable]
33138 };
33139 STRtree.prototype.getClass = function getClass () {
33140 return STRtree
33141 };
33142 STRtree.centreX = function centreX (e) {
33143 return STRtree.avg(e.getMinX(), e.getMaxX())
33144 };
33145 STRtree.avg = function avg (a, b) {
33146 return (a + b) / 2
33147 };
33148 STRtree.centreY = function centreY (e) {
33149 return STRtree.avg(e.getMinY(), e.getMaxY())
33150 };
33151 staticAccessors.STRtreeNode.get = function () { return STRtreeNode };
33152 staticAccessors.serialVersionUID.get = function () { return 259274702368956900 };
33153 staticAccessors.xComparator.get = function () {
33154 return {
33155 interfaces_: function () {
33156 return [Comparator]
33157 },
33158 compare: function (o1, o2) {
33159 return AbstractSTRtree$$1.compareDoubles(STRtree.centreX(o1.getBounds()), STRtree.centreX(o2.getBounds()))
33160 }
33161 }
33162 };
33163 staticAccessors.yComparator.get = function () {
33164 return {
33165 interfaces_: function () {
33166 return [Comparator]
33167 },
33168 compare: function (o1, o2) {
33169 return AbstractSTRtree$$1.compareDoubles(STRtree.centreY(o1.getBounds()), STRtree.centreY(o2.getBounds()))
33170 }
33171 }
33172 };
33173 staticAccessors.intersectsOp.get = function () {
33174 return {
33175 interfaces_: function () {
33176 return [AbstractSTRtree$$1.IntersectsOp]
33177 },
33178 intersects: function (aBounds, bBounds) {
33179 return aBounds.intersects(bBounds)
33180 }
33181 }
33182 };
33183 staticAccessors.DEFAULT_NODE_CAPACITY.get = function () { return 10 };
33184
33185 Object.defineProperties( STRtree, staticAccessors );
33186
33187 return STRtree;
33188}(AbstractSTRtree));
33189
33190var STRtreeNode = (function (AbstractNode$$1) {
33191 function STRtreeNode () {
33192 var level = arguments[0];
33193 AbstractNode$$1.call(this, level);
33194 }
33195
33196 if ( AbstractNode$$1 ) STRtreeNode.__proto__ = AbstractNode$$1;
33197 STRtreeNode.prototype = Object.create( AbstractNode$$1 && AbstractNode$$1.prototype );
33198 STRtreeNode.prototype.constructor = STRtreeNode;
33199 STRtreeNode.prototype.computeBounds = function computeBounds () {
33200 var bounds = null;
33201 for (var i = this.getChildBoundables().iterator(); i.hasNext();) {
33202 var childBoundable = i.next();
33203 if (bounds === null) {
33204 bounds = new Envelope(childBoundable.getBounds());
33205 } else {
33206 bounds.expandToInclude(childBoundable.getBounds());
33207 }
33208 }
33209 return bounds
33210 };
33211 STRtreeNode.prototype.interfaces_ = function interfaces_ () {
33212 return []
33213 };
33214 STRtreeNode.prototype.getClass = function getClass () {
33215 return STRtreeNode
33216 };
33217
33218 return STRtreeNode;
33219}(AbstractNode));
33220
33221var SegmentPointComparator = function SegmentPointComparator () {};
33222
33223SegmentPointComparator.prototype.interfaces_ = function interfaces_ () {
33224 return []
33225};
33226SegmentPointComparator.prototype.getClass = function getClass () {
33227 return SegmentPointComparator
33228};
33229SegmentPointComparator.relativeSign = function relativeSign (x0, x1) {
33230 if (x0 < x1) { return -1 }
33231 if (x0 > x1) { return 1 }
33232 return 0
33233};
33234SegmentPointComparator.compare = function compare (octant, p0, p1) {
33235 if (p0.equals2D(p1)) { return 0 }
33236 var xSign = SegmentPointComparator.relativeSign(p0.x, p1.x);
33237 var ySign = SegmentPointComparator.relativeSign(p0.y, p1.y);
33238 switch (octant) {
33239 case 0:
33240 return SegmentPointComparator.compareValue(xSign, ySign)
33241 case 1:
33242 return SegmentPointComparator.compareValue(ySign, xSign)
33243 case 2:
33244 return SegmentPointComparator.compareValue(ySign, -xSign)
33245 case 3:
33246 return SegmentPointComparator.compareValue(-xSign, ySign)
33247 case 4:
33248 return SegmentPointComparator.compareValue(-xSign, -ySign)
33249 case 5:
33250 return SegmentPointComparator.compareValue(-ySign, -xSign)
33251 case 6:
33252 return SegmentPointComparator.compareValue(-ySign, xSign)
33253 case 7:
33254 return SegmentPointComparator.compareValue(xSign, -ySign)
33255 default:
33256 }
33257 Assert.shouldNeverReachHere('invalid octant value');
33258 return 0
33259};
33260SegmentPointComparator.compareValue = function compareValue (compareSign0, compareSign1) {
33261 if (compareSign0 < 0) { return -1 }
33262 if (compareSign0 > 0) { return 1 }
33263 if (compareSign1 < 0) { return -1 }
33264 if (compareSign1 > 0) { return 1 }
33265 return 0
33266};
33267
33268var SegmentNode = function SegmentNode () {
33269 this._segString = null;
33270 this.coord = null;
33271 this.segmentIndex = null;
33272 this._segmentOctant = null;
33273 this._isInterior = null;
33274 var segString = arguments[0];
33275 var coord = arguments[1];
33276 var segmentIndex = arguments[2];
33277 var segmentOctant = arguments[3];
33278 this._segString = segString;
33279 this.coord = new Coordinate(coord);
33280 this.segmentIndex = segmentIndex;
33281 this._segmentOctant = segmentOctant;
33282 this._isInterior = !coord.equals2D(segString.getCoordinate(segmentIndex));
33283};
33284SegmentNode.prototype.getCoordinate = function getCoordinate () {
33285 return this.coord
33286};
33287SegmentNode.prototype.print = function print (out) {
33288 out.print(this.coord);
33289 out.print(' seg # = ' + this.segmentIndex);
33290};
33291SegmentNode.prototype.compareTo = function compareTo (obj) {
33292 var other = obj;
33293 if (this.segmentIndex < other.segmentIndex) { return -1 }
33294 if (this.segmentIndex > other.segmentIndex) { return 1 }
33295 if (this.coord.equals2D(other.coord)) { return 0 }
33296 return SegmentPointComparator.compare(this._segmentOctant, this.coord, other.coord)
33297};
33298SegmentNode.prototype.isEndPoint = function isEndPoint (maxSegmentIndex) {
33299 if (this.segmentIndex === 0 && !this._isInterior) { return true }
33300 if (this.segmentIndex === maxSegmentIndex) { return true }
33301 return false
33302};
33303SegmentNode.prototype.isInterior = function isInterior () {
33304 return this._isInterior
33305};
33306SegmentNode.prototype.interfaces_ = function interfaces_ () {
33307 return [Comparable]
33308};
33309SegmentNode.prototype.getClass = function getClass () {
33310 return SegmentNode
33311};
33312
33313// import Iterator from '../../../../java/util/Iterator'
33314var SegmentNodeList = function SegmentNodeList () {
33315 this._nodeMap = new TreeMap();
33316 this._edge = null;
33317 var edge = arguments[0];
33318 this._edge = edge;
33319};
33320SegmentNodeList.prototype.getSplitCoordinates = function getSplitCoordinates () {
33321 var this$1 = this;
33322
33323 var coordList = new CoordinateList();
33324 this.addEndpoints();
33325 var it = this.iterator();
33326 var eiPrev = it.next();
33327 while (it.hasNext()) {
33328 var ei = it.next();
33329 this$1.addEdgeCoordinates(eiPrev, ei, coordList);
33330 eiPrev = ei;
33331 }
33332 return coordList.toCoordinateArray()
33333};
33334SegmentNodeList.prototype.addCollapsedNodes = function addCollapsedNodes () {
33335 var this$1 = this;
33336
33337 var collapsedVertexIndexes = new ArrayList();
33338 this.findCollapsesFromInsertedNodes(collapsedVertexIndexes);
33339 this.findCollapsesFromExistingVertices(collapsedVertexIndexes);
33340 for (var it = collapsedVertexIndexes.iterator(); it.hasNext();) {
33341 var vertexIndex = it.next().intValue();
33342 this$1.add(this$1._edge.getCoordinate(vertexIndex), vertexIndex);
33343 }
33344};
33345SegmentNodeList.prototype.print = function print (out) {
33346 out.println('Intersections:');
33347 for (var it = this.iterator(); it.hasNext();) {
33348 var ei = it.next();
33349 ei.print(out);
33350 }
33351};
33352SegmentNodeList.prototype.findCollapsesFromExistingVertices = function findCollapsesFromExistingVertices (collapsedVertexIndexes) {
33353 var this$1 = this;
33354
33355 for (var i = 0; i < this._edge.size() - 2; i++) {
33356 var p0 = this$1._edge.getCoordinate(i);
33357 // const p1 = this._edge.getCoordinate(i + 1)
33358 var p2 = this$1._edge.getCoordinate(i + 2);
33359 if (p0.equals2D(p2)) {
33360 collapsedVertexIndexes.add(new Integer(i + 1));
33361 }
33362 }
33363};
33364SegmentNodeList.prototype.addEdgeCoordinates = function addEdgeCoordinates (ei0, ei1, coordList) {
33365 var this$1 = this;
33366
33367 // let npts = ei1.segmentIndex - ei0.segmentIndex + 2
33368 var lastSegStartPt = this._edge.getCoordinate(ei1.segmentIndex);
33369 var useIntPt1 = ei1.isInterior() || !ei1.coord.equals2D(lastSegStartPt);
33370 // if (!useIntPt1) {
33371 // npts--
33372 // }
33373 // const ipt = 0
33374 coordList.add(new Coordinate(ei0.coord), false);
33375 for (var i = ei0.segmentIndex + 1; i <= ei1.segmentIndex; i++) {
33376 coordList.add(this$1._edge.getCoordinate(i));
33377 }
33378 if (useIntPt1) {
33379 coordList.add(new Coordinate(ei1.coord));
33380 }
33381};
33382SegmentNodeList.prototype.iterator = function iterator () {
33383 return this._nodeMap.values().iterator()
33384};
33385SegmentNodeList.prototype.addSplitEdges = function addSplitEdges (edgeList) {
33386 var this$1 = this;
33387
33388 this.addEndpoints();
33389 this.addCollapsedNodes();
33390 var it = this.iterator();
33391 var eiPrev = it.next();
33392 while (it.hasNext()) {
33393 var ei = it.next();
33394 var newEdge = this$1.createSplitEdge(eiPrev, ei);
33395 edgeList.add(newEdge);
33396 eiPrev = ei;
33397 }
33398};
33399SegmentNodeList.prototype.findCollapseIndex = function findCollapseIndex (ei0, ei1, collapsedVertexIndex) {
33400 if (!ei0.coord.equals2D(ei1.coord)) { return false }
33401 var numVerticesBetween = ei1.segmentIndex - ei0.segmentIndex;
33402 if (!ei1.isInterior()) {
33403 numVerticesBetween--;
33404 }
33405 if (numVerticesBetween === 1) {
33406 collapsedVertexIndex[0] = ei0.segmentIndex + 1;
33407 return true
33408 }
33409 return false
33410};
33411SegmentNodeList.prototype.findCollapsesFromInsertedNodes = function findCollapsesFromInsertedNodes (collapsedVertexIndexes) {
33412 var this$1 = this;
33413
33414 var collapsedVertexIndex = new Array(1).fill(null);
33415 var it = this.iterator();
33416 var eiPrev = it.next();
33417 while (it.hasNext()) {
33418 var ei = it.next();
33419 var isCollapsed = this$1.findCollapseIndex(eiPrev, ei, collapsedVertexIndex);
33420 if (isCollapsed) { collapsedVertexIndexes.add(new Integer(collapsedVertexIndex[0])); }
33421 eiPrev = ei;
33422 }
33423};
33424SegmentNodeList.prototype.getEdge = function getEdge () {
33425 return this._edge
33426};
33427SegmentNodeList.prototype.addEndpoints = function addEndpoints () {
33428 var maxSegIndex = this._edge.size() - 1;
33429 this.add(this._edge.getCoordinate(0), 0);
33430 this.add(this._edge.getCoordinate(maxSegIndex), maxSegIndex);
33431};
33432SegmentNodeList.prototype.createSplitEdge = function createSplitEdge (ei0, ei1) {
33433 var this$1 = this;
33434
33435 var npts = ei1.segmentIndex - ei0.segmentIndex + 2;
33436 var lastSegStartPt = this._edge.getCoordinate(ei1.segmentIndex);
33437 var useIntPt1 = ei1.isInterior() || !ei1.coord.equals2D(lastSegStartPt);
33438 if (!useIntPt1) {
33439 npts--;
33440 }
33441 var pts = new Array(npts).fill(null);
33442 var ipt = 0;
33443 pts[ipt++] = new Coordinate(ei0.coord);
33444 for (var i = ei0.segmentIndex + 1; i <= ei1.segmentIndex; i++) {
33445 pts[ipt++] = this$1._edge.getCoordinate(i);
33446 }
33447 if (useIntPt1) { pts[ipt] = new Coordinate(ei1.coord); }
33448 return new NodedSegmentString(pts, this._edge.getData())
33449};
33450SegmentNodeList.prototype.add = function add (intPt, segmentIndex) {
33451 var eiNew = new SegmentNode(this._edge, intPt, segmentIndex, this._edge.getSegmentOctant(segmentIndex));
33452 var ei = this._nodeMap.get(eiNew);
33453 if (ei !== null) {
33454 Assert.isTrue(ei.coord.equals2D(intPt), 'Found equal nodes with different coordinates');
33455 return ei
33456 }
33457 this._nodeMap.put(eiNew, eiNew);
33458 return eiNew
33459};
33460SegmentNodeList.prototype.checkSplitEdgesCorrectness = function checkSplitEdgesCorrectness (splitEdges) {
33461 var edgePts = this._edge.getCoordinates();
33462 var split0 = splitEdges.get(0);
33463 var pt0 = split0.getCoordinate(0);
33464 if (!pt0.equals2D(edgePts[0])) { throw new RuntimeException('bad split edge start point at ' + pt0) }
33465 var splitn = splitEdges.get(splitEdges.size() - 1);
33466 var splitnPts = splitn.getCoordinates();
33467 var ptn = splitnPts[splitnPts.length - 1];
33468 if (!ptn.equals2D(edgePts[edgePts.length - 1])) { throw new RuntimeException('bad split edge end point at ' + ptn) }
33469};
33470SegmentNodeList.prototype.interfaces_ = function interfaces_ () {
33471 return []
33472};
33473SegmentNodeList.prototype.getClass = function getClass () {
33474 return SegmentNodeList
33475};
33476
33477
33478
33479// class NodeVertexIterator {
33480// constructor () {
33481// this._nodeList = null
33482// this._edge = null
33483// this._nodeIt = null
33484// this._currNode = null
33485// this._nextNode = null
33486// this._currSegIndex = 0
33487// let nodeList = arguments[0]
33488// this._nodeList = nodeList
33489// this._edge = nodeList.getEdge()
33490// this._nodeIt = nodeList.iterator()
33491// this.readNextNode()
33492// }
33493// next () {
33494// if (this._currNode === null) {
33495// this._currNode = this._nextNode
33496// this._currSegIndex = this._currNode.segmentIndex
33497// this.readNextNode()
33498// return this._currNode
33499// }
33500// if (this._nextNode === null) return null
33501// if (this._nextNode.segmentIndex === this._currNode.segmentIndex) {
33502// this._currNode = this._nextNode
33503// this._currSegIndex = this._currNode.segmentIndex
33504// this.readNextNode()
33505// return this._currNode
33506// }
33507// if (this._nextNode.segmentIndex > this._currNode.segmentIndex) {}
33508// return null
33509// }
33510// remove () {
33511// // throw new UnsupportedOperationException(this.getClass().getName())
33512// }
33513// hasNext () {
33514// if (this._nextNode === null) return false
33515// return true
33516// }
33517// readNextNode () {
33518// if (this._nodeIt.hasNext()) this._nextNode = this._nodeIt.next(); else this._nextNode = null
33519// }
33520// interfaces_ () {
33521// return [Iterator]
33522// }
33523// getClass () {
33524// return NodeVertexIterator
33525// }
33526// }
33527
33528var Octant = function Octant () {};
33529
33530Octant.prototype.interfaces_ = function interfaces_ () {
33531 return []
33532};
33533Octant.prototype.getClass = function getClass () {
33534 return Octant
33535};
33536Octant.octant = function octant () {
33537 if (typeof arguments[0] === 'number' && typeof arguments[1] === 'number') {
33538 var dx = arguments[0];
33539 var dy = arguments[1];
33540 if (dx === 0.0 && dy === 0.0) { throw new IllegalArgumentException('Cannot compute the octant for point ( ' + dx + ', ' + dy + ' )') }
33541 var adx = Math.abs(dx);
33542 var ady = Math.abs(dy);
33543 if (dx >= 0) {
33544 if (dy >= 0) {
33545 if (adx >= ady) { return 0; } else { return 1 }
33546 } else {
33547 if (adx >= ady) { return 7; } else { return 6 }
33548 }
33549 } else {
33550 if (dy >= 0) {
33551 if (adx >= ady) { return 3; } else { return 2 }
33552 } else {
33553 if (adx >= ady) { return 4; } else { return 5 }
33554 }
33555 }
33556 } else if (arguments[0] instanceof Coordinate && arguments[1] instanceof Coordinate) {
33557 var p0 = arguments[0];
33558 var p1 = arguments[1];
33559 var dx$1 = p1.x - p0.x;
33560 var dy$1 = p1.y - p0.y;
33561 if (dx$1 === 0.0 && dy$1 === 0.0) { throw new IllegalArgumentException('Cannot compute the octant for two identical points ' + p0) }
33562 return Octant.octant(dx$1, dy$1)
33563 }
33564};
33565
33566var SegmentString = function SegmentString () {};
33567
33568SegmentString.prototype.getCoordinates = function getCoordinates () {};
33569SegmentString.prototype.size = function size () {};
33570SegmentString.prototype.getCoordinate = function getCoordinate (i) {};
33571SegmentString.prototype.isClosed = function isClosed () {};
33572SegmentString.prototype.setData = function setData (data) {};
33573SegmentString.prototype.getData = function getData () {};
33574SegmentString.prototype.interfaces_ = function interfaces_ () {
33575 return []
33576};
33577SegmentString.prototype.getClass = function getClass () {
33578 return SegmentString
33579};
33580
33581var NodableSegmentString = function NodableSegmentString () {};
33582
33583NodableSegmentString.prototype.addIntersection = function addIntersection (intPt, segmentIndex) {};
33584NodableSegmentString.prototype.interfaces_ = function interfaces_ () {
33585 return [SegmentString]
33586};
33587NodableSegmentString.prototype.getClass = function getClass () {
33588 return NodableSegmentString
33589};
33590
33591var NodedSegmentString = function NodedSegmentString () {
33592 this._nodeList = new SegmentNodeList(this);
33593 this._pts = null;
33594 this._data = null;
33595 var pts = arguments[0];
33596 var data = arguments[1];
33597 this._pts = pts;
33598 this._data = data;
33599};
33600NodedSegmentString.prototype.getCoordinates = function getCoordinates () {
33601 return this._pts
33602};
33603NodedSegmentString.prototype.size = function size () {
33604 return this._pts.length
33605};
33606NodedSegmentString.prototype.getCoordinate = function getCoordinate (i) {
33607 return this._pts[i]
33608};
33609NodedSegmentString.prototype.isClosed = function isClosed () {
33610 return this._pts[0].equals(this._pts[this._pts.length - 1])
33611};
33612NodedSegmentString.prototype.getSegmentOctant = function getSegmentOctant (index) {
33613 if (index === this._pts.length - 1) { return -1 }
33614 return this.safeOctant(this.getCoordinate(index), this.getCoordinate(index + 1))
33615};
33616NodedSegmentString.prototype.setData = function setData (data) {
33617 this._data = data;
33618};
33619NodedSegmentString.prototype.safeOctant = function safeOctant (p0, p1) {
33620 if (p0.equals2D(p1)) { return 0 }
33621 return Octant.octant(p0, p1)
33622};
33623NodedSegmentString.prototype.getData = function getData () {
33624 return this._data
33625};
33626NodedSegmentString.prototype.addIntersection = function addIntersection () {
33627 if (arguments.length === 2) {
33628 var intPt$1 = arguments[0];
33629 var segmentIndex = arguments[1];
33630 this.addIntersectionNode(intPt$1, segmentIndex);
33631 } else if (arguments.length === 4) {
33632 var li = arguments[0];
33633 var segmentIndex$1 = arguments[1];
33634 // const geomIndex = arguments[2]
33635 var intIndex = arguments[3];
33636 var intPt = new Coordinate(li.getIntersection(intIndex));
33637 this.addIntersection(intPt, segmentIndex$1);
33638 }
33639};
33640NodedSegmentString.prototype.toString = function toString () {
33641 return WKTWriter.toLineString(new CoordinateArraySequence(this._pts))
33642};
33643NodedSegmentString.prototype.getNodeList = function getNodeList () {
33644 return this._nodeList
33645};
33646NodedSegmentString.prototype.addIntersectionNode = function addIntersectionNode (intPt, segmentIndex) {
33647 var normalizedSegmentIndex = segmentIndex;
33648 var nextSegIndex = normalizedSegmentIndex + 1;
33649 if (nextSegIndex < this._pts.length) {
33650 var nextPt = this._pts[nextSegIndex];
33651 if (intPt.equals2D(nextPt)) {
33652 normalizedSegmentIndex = nextSegIndex;
33653 }
33654 }
33655 var ei = this._nodeList.add(intPt, normalizedSegmentIndex);
33656 return ei
33657};
33658NodedSegmentString.prototype.addIntersections = function addIntersections (li, segmentIndex, geomIndex) {
33659 var this$1 = this;
33660
33661 for (var i = 0; i < li.getIntersectionNum(); i++) {
33662 this$1.addIntersection(li, segmentIndex, geomIndex, i);
33663 }
33664};
33665NodedSegmentString.prototype.interfaces_ = function interfaces_ () {
33666 return [NodableSegmentString]
33667};
33668NodedSegmentString.prototype.getClass = function getClass () {
33669 return NodedSegmentString
33670};
33671NodedSegmentString.getNodedSubstrings = function getNodedSubstrings () {
33672 if (arguments.length === 1) {
33673 var segStrings = arguments[0];
33674 var resultEdgelist = new ArrayList();
33675 NodedSegmentString.getNodedSubstrings(segStrings, resultEdgelist);
33676 return resultEdgelist
33677 } else if (arguments.length === 2) {
33678 var segStrings$1 = arguments[0];
33679 var resultEdgelist$1 = arguments[1];
33680 for (var i = segStrings$1.iterator(); i.hasNext();) {
33681 var ss = i.next();
33682 ss.getNodeList().addSplitEdges(resultEdgelist$1);
33683 }
33684 }
33685};
33686
33687var LineSegment = function LineSegment () {
33688 this.p0 = null;
33689 this.p1 = null;
33690 if (arguments.length === 0) {
33691 this.p0 = new Coordinate();
33692 this.p1 = new Coordinate();
33693 } else if (arguments.length === 1) {
33694 var ls = arguments[0];
33695 this.p0 = new Coordinate(ls.p0);
33696 this.p1 = new Coordinate(ls.p1);
33697 } else if (arguments.length === 2) {
33698 this.p0 = arguments[0];
33699 this.p1 = arguments[1];
33700 } else if (arguments.length === 4) {
33701 var x0 = arguments[0];
33702 var y0 = arguments[1];
33703 var x1 = arguments[2];
33704 var y1 = arguments[3];
33705 this.p0 = new Coordinate(x0, y0);
33706 this.p1 = new Coordinate(x1, y1);
33707 }
33708};
33709
33710var staticAccessors$24 = { serialVersionUID: { configurable: true } };
33711LineSegment.prototype.minX = function minX () {
33712 return Math.min(this.p0.x, this.p1.x)
33713};
33714LineSegment.prototype.orientationIndex = function orientationIndex () {
33715 if (arguments[0] instanceof LineSegment) {
33716 var seg = arguments[0];
33717 var orient0 = CGAlgorithms.orientationIndex(this.p0, this.p1, seg.p0);
33718 var orient1 = CGAlgorithms.orientationIndex(this.p0, this.p1, seg.p1);
33719 if (orient0 >= 0 && orient1 >= 0) { return Math.max(orient0, orient1) }
33720 if (orient0 <= 0 && orient1 <= 0) { return Math.max(orient0, orient1) }
33721 return 0
33722 } else if (arguments[0] instanceof Coordinate) {
33723 var p = arguments[0];
33724 return CGAlgorithms.orientationIndex(this.p0, this.p1, p)
33725 }
33726};
33727LineSegment.prototype.toGeometry = function toGeometry (geomFactory) {
33728 return geomFactory.createLineString([this.p0, this.p1])
33729};
33730LineSegment.prototype.isVertical = function isVertical () {
33731 return this.p0.x === this.p1.x
33732};
33733LineSegment.prototype.equals = function equals (o) {
33734 if (!(o instanceof LineSegment)) {
33735 return false
33736 }
33737 var other = o;
33738 return this.p0.equals(other.p0) && this.p1.equals(other.p1)
33739};
33740LineSegment.prototype.intersection = function intersection (line) {
33741 var li = new RobustLineIntersector();
33742 li.computeIntersection(this.p0, this.p1, line.p0, line.p1);
33743 if (li.hasIntersection()) { return li.getIntersection(0) }
33744 return null
33745};
33746LineSegment.prototype.project = function project () {
33747 if (arguments[0] instanceof Coordinate) {
33748 var p = arguments[0];
33749 if (p.equals(this.p0) || p.equals(this.p1)) { return new Coordinate(p) }
33750 var r = this.projectionFactor(p);
33751 var coord = new Coordinate();
33752 coord.x = this.p0.x + r * (this.p1.x - this.p0.x);
33753 coord.y = this.p0.y + r * (this.p1.y - this.p0.y);
33754 return coord
33755 } else if (arguments[0] instanceof LineSegment) {
33756 var seg = arguments[0];
33757 var pf0 = this.projectionFactor(seg.p0);
33758 var pf1 = this.projectionFactor(seg.p1);
33759 if (pf0 >= 1.0 && pf1 >= 1.0) { return null }
33760 if (pf0 <= 0.0 && pf1 <= 0.0) { return null }
33761 var newp0 = this.project(seg.p0);
33762 if (pf0 < 0.0) { newp0 = this.p0; }
33763 if (pf0 > 1.0) { newp0 = this.p1; }
33764 var newp1 = this.project(seg.p1);
33765 if (pf1 < 0.0) { newp1 = this.p0; }
33766 if (pf1 > 1.0) { newp1 = this.p1; }
33767 return new LineSegment(newp0, newp1)
33768 }
33769};
33770LineSegment.prototype.normalize = function normalize () {
33771 if (this.p1.compareTo(this.p0) < 0) { this.reverse(); }
33772};
33773LineSegment.prototype.angle = function angle () {
33774 return Math.atan2(this.p1.y - this.p0.y, this.p1.x - this.p0.x)
33775};
33776LineSegment.prototype.getCoordinate = function getCoordinate (i) {
33777 if (i === 0) { return this.p0 }
33778 return this.p1
33779};
33780LineSegment.prototype.distancePerpendicular = function distancePerpendicular (p) {
33781 return CGAlgorithms.distancePointLinePerpendicular(p, this.p0, this.p1)
33782};
33783LineSegment.prototype.minY = function minY () {
33784 return Math.min(this.p0.y, this.p1.y)
33785};
33786LineSegment.prototype.midPoint = function midPoint () {
33787 return LineSegment.midPoint(this.p0, this.p1)
33788};
33789LineSegment.prototype.projectionFactor = function projectionFactor (p) {
33790 if (p.equals(this.p0)) { return 0.0 }
33791 if (p.equals(this.p1)) { return 1.0 }
33792 var dx = this.p1.x - this.p0.x;
33793 var dy = this.p1.y - this.p0.y;
33794 var len = dx * dx + dy * dy;
33795 if (len <= 0.0) { return Double.NaN }
33796 var r = ((p.x - this.p0.x) * dx + (p.y - this.p0.y) * dy) / len;
33797 return r
33798};
33799LineSegment.prototype.closestPoints = function closestPoints (line) {
33800 var intPt = this.intersection(line);
33801 if (intPt !== null) {
33802 return [intPt, intPt]
33803 }
33804 var closestPt = new Array(2).fill(null);
33805 var minDistance = Double.MAX_VALUE;
33806 var dist = null;
33807 var close00 = this.closestPoint(line.p0);
33808 minDistance = close00.distance(line.p0);
33809 closestPt[0] = close00;
33810 closestPt[1] = line.p0;
33811 var close01 = this.closestPoint(line.p1);
33812 dist = close01.distance(line.p1);
33813 if (dist < minDistance) {
33814 minDistance = dist;
33815 closestPt[0] = close01;
33816 closestPt[1] = line.p1;
33817 }
33818 var close10 = line.closestPoint(this.p0);
33819 dist = close10.distance(this.p0);
33820 if (dist < minDistance) {
33821 minDistance = dist;
33822 closestPt[0] = this.p0;
33823 closestPt[1] = close10;
33824 }
33825 var close11 = line.closestPoint(this.p1);
33826 dist = close11.distance(this.p1);
33827 if (dist < minDistance) {
33828 minDistance = dist;
33829 closestPt[0] = this.p1;
33830 closestPt[1] = close11;
33831 }
33832 return closestPt
33833};
33834LineSegment.prototype.closestPoint = function closestPoint (p) {
33835 var factor = this.projectionFactor(p);
33836 if (factor > 0 && factor < 1) {
33837 return this.project(p)
33838 }
33839 var dist0 = this.p0.distance(p);
33840 var dist1 = this.p1.distance(p);
33841 if (dist0 < dist1) { return this.p0 }
33842 return this.p1
33843};
33844LineSegment.prototype.maxX = function maxX () {
33845 return Math.max(this.p0.x, this.p1.x)
33846};
33847LineSegment.prototype.getLength = function getLength () {
33848 return this.p0.distance(this.p1)
33849};
33850LineSegment.prototype.compareTo = function compareTo (o) {
33851 var other = o;
33852 var comp0 = this.p0.compareTo(other.p0);
33853 if (comp0 !== 0) { return comp0 }
33854 return this.p1.compareTo(other.p1)
33855};
33856LineSegment.prototype.reverse = function reverse () {
33857 var temp = this.p0;
33858 this.p0 = this.p1;
33859 this.p1 = temp;
33860};
33861LineSegment.prototype.equalsTopo = function equalsTopo (other) {
33862 return this.p0.equals(other.p0) &&
33863 (this.p1.equals(other.p1) || this.p0.equals(other.p1)) &&
33864 this.p1.equals(other.p0)
33865};
33866LineSegment.prototype.lineIntersection = function lineIntersection (line) {
33867 try {
33868 var intPt = HCoordinate.intersection(this.p0, this.p1, line.p0, line.p1);
33869 return intPt
33870 } catch (ex) {
33871 if (ex instanceof NotRepresentableException) {} else { throw ex }
33872 } finally {}
33873 return null
33874};
33875LineSegment.prototype.maxY = function maxY () {
33876 return Math.max(this.p0.y, this.p1.y)
33877};
33878LineSegment.prototype.pointAlongOffset = function pointAlongOffset (segmentLengthFraction, offsetDistance) {
33879 var segx = this.p0.x + segmentLengthFraction * (this.p1.x - this.p0.x);
33880 var segy = this.p0.y + segmentLengthFraction * (this.p1.y - this.p0.y);
33881 var dx = this.p1.x - this.p0.x;
33882 var dy = this.p1.y - this.p0.y;
33883 var len = Math.sqrt(dx * dx + dy * dy);
33884 var ux = 0.0;
33885 var uy = 0.0;
33886 if (offsetDistance !== 0.0) {
33887 if (len <= 0.0) { throw new Error('Cannot compute offset from zero-length line segment') }
33888 ux = offsetDistance * dx / len;
33889 uy = offsetDistance * dy / len;
33890 }
33891 var offsetx = segx - uy;
33892 var offsety = segy + ux;
33893 var coord = new Coordinate(offsetx, offsety);
33894 return coord
33895};
33896LineSegment.prototype.setCoordinates = function setCoordinates () {
33897 if (arguments.length === 1) {
33898 var ls = arguments[0];
33899 this.setCoordinates(ls.p0, ls.p1);
33900 } else if (arguments.length === 2) {
33901 var p0 = arguments[0];
33902 var p1 = arguments[1];
33903 this.p0.x = p0.x;
33904 this.p0.y = p0.y;
33905 this.p1.x = p1.x;
33906 this.p1.y = p1.y;
33907 }
33908};
33909LineSegment.prototype.segmentFraction = function segmentFraction (inputPt) {
33910 var segFrac = this.projectionFactor(inputPt);
33911 if (segFrac < 0.0) { segFrac = 0.0; } else if (segFrac > 1.0 || Double.isNaN(segFrac)) { segFrac = 1.0; }
33912 return segFrac
33913};
33914LineSegment.prototype.toString = function toString () {
33915 return 'LINESTRING( ' + this.p0.x + ' ' + this.p0.y + ', ' + this.p1.x + ' ' + this.p1.y + ')'
33916};
33917LineSegment.prototype.isHorizontal = function isHorizontal () {
33918 return this.p0.y === this.p1.y
33919};
33920LineSegment.prototype.distance = function distance () {
33921 if (arguments[0] instanceof LineSegment) {
33922 var ls = arguments[0];
33923 return CGAlgorithms.distanceLineLine(this.p0, this.p1, ls.p0, ls.p1)
33924 } else if (arguments[0] instanceof Coordinate) {
33925 var p = arguments[0];
33926 return CGAlgorithms.distancePointLine(p, this.p0, this.p1)
33927 }
33928};
33929LineSegment.prototype.pointAlong = function pointAlong (segmentLengthFraction) {
33930 var coord = new Coordinate();
33931 coord.x = this.p0.x + segmentLengthFraction * (this.p1.x - this.p0.x);
33932 coord.y = this.p0.y + segmentLengthFraction * (this.p1.y - this.p0.y);
33933 return coord
33934};
33935LineSegment.prototype.hashCode = function hashCode () {
33936 var bits0 = Double.doubleToLongBits(this.p0.x);
33937 bits0 ^= Double.doubleToLongBits(this.p0.y) * 31;
33938 var hash0 = Math.trunc(bits0) ^ Math.trunc(bits0 >> 32);
33939 var bits1 = Double.doubleToLongBits(this.p1.x);
33940 bits1 ^= Double.doubleToLongBits(this.p1.y) * 31;
33941 var hash1 = Math.trunc(bits1) ^ Math.trunc(bits1 >> 32);
33942 return hash0 ^ hash1
33943};
33944LineSegment.prototype.interfaces_ = function interfaces_ () {
33945 return [Comparable, Serializable]
33946};
33947LineSegment.prototype.getClass = function getClass () {
33948 return LineSegment
33949};
33950LineSegment.midPoint = function midPoint (p0, p1) {
33951 return new Coordinate((p0.x + p1.x) / 2, (p0.y + p1.y) / 2)
33952};
33953staticAccessors$24.serialVersionUID.get = function () { return 3252005833466256227 };
33954
33955Object.defineProperties( LineSegment, staticAccessors$24 );
33956
33957var MonotoneChainOverlapAction = function MonotoneChainOverlapAction () {
33958 this.tempEnv1 = new Envelope();
33959 this.tempEnv2 = new Envelope();
33960 this._overlapSeg1 = new LineSegment();
33961 this._overlapSeg2 = new LineSegment();
33962};
33963MonotoneChainOverlapAction.prototype.overlap = function overlap () {
33964 if (arguments.length === 2) {
33965 // const seg1 = arguments[0]
33966 // const seg2 = arguments[1]
33967 } else if (arguments.length === 4) {
33968 var mc1 = arguments[0];
33969 var start1 = arguments[1];
33970 var mc2 = arguments[2];
33971 var start2 = arguments[3];
33972 mc1.getLineSegment(start1, this._overlapSeg1);
33973 mc2.getLineSegment(start2, this._overlapSeg2);
33974 this.overlap(this._overlapSeg1, this._overlapSeg2);
33975 }
33976};
33977MonotoneChainOverlapAction.prototype.interfaces_ = function interfaces_ () {
33978 return []
33979};
33980MonotoneChainOverlapAction.prototype.getClass = function getClass () {
33981 return MonotoneChainOverlapAction
33982};
33983
33984var MonotoneChain = function MonotoneChain () {
33985 this._pts = null;
33986 this._start = null;
33987 this._end = null;
33988 this._env = null;
33989 this._context = null;
33990 this._id = null;
33991 var pts = arguments[0];
33992 var start = arguments[1];
33993 var end = arguments[2];
33994 var context = arguments[3];
33995 this._pts = pts;
33996 this._start = start;
33997 this._end = end;
33998 this._context = context;
33999};
34000MonotoneChain.prototype.getLineSegment = function getLineSegment (index, ls) {
34001 ls.p0 = this._pts[index];
34002 ls.p1 = this._pts[index + 1];
34003};
34004MonotoneChain.prototype.computeSelect = function computeSelect (searchEnv, start0, end0, mcs) {
34005 var p0 = this._pts[start0];
34006 var p1 = this._pts[end0];
34007 mcs.tempEnv1.init(p0, p1);
34008 if (end0 - start0 === 1) {
34009 mcs.select(this, start0);
34010 return null
34011 }
34012 if (!searchEnv.intersects(mcs.tempEnv1)) { return null }
34013 var mid = Math.trunc((start0 + end0) / 2);
34014 if (start0 < mid) {
34015 this.computeSelect(searchEnv, start0, mid, mcs);
34016 }
34017 if (mid < end0) {
34018 this.computeSelect(searchEnv, mid, end0, mcs);
34019 }
34020};
34021MonotoneChain.prototype.getCoordinates = function getCoordinates () {
34022 var this$1 = this;
34023
34024 var coord = new Array(this._end - this._start + 1).fill(null);
34025 var index = 0;
34026 for (var i = this._start; i <= this._end; i++) {
34027 coord[index++] = this$1._pts[i];
34028 }
34029 return coord
34030};
34031MonotoneChain.prototype.computeOverlaps = function computeOverlaps (mc, mco) {
34032 this.computeOverlapsInternal(this._start, this._end, mc, mc._start, mc._end, mco);
34033};
34034MonotoneChain.prototype.setId = function setId (id) {
34035 this._id = id;
34036};
34037MonotoneChain.prototype.select = function select (searchEnv, mcs) {
34038 this.computeSelect(searchEnv, this._start, this._end, mcs);
34039};
34040MonotoneChain.prototype.getEnvelope = function getEnvelope () {
34041 if (this._env === null) {
34042 var p0 = this._pts[this._start];
34043 var p1 = this._pts[this._end];
34044 this._env = new Envelope(p0, p1);
34045 }
34046 return this._env
34047};
34048MonotoneChain.prototype.getEndIndex = function getEndIndex () {
34049 return this._end
34050};
34051MonotoneChain.prototype.getStartIndex = function getStartIndex () {
34052 return this._start
34053};
34054MonotoneChain.prototype.getContext = function getContext () {
34055 return this._context
34056};
34057MonotoneChain.prototype.getId = function getId () {
34058 return this._id
34059};
34060MonotoneChain.prototype.computeOverlapsInternal = function computeOverlapsInternal (start0, end0, mc, start1, end1, mco) {
34061 var p00 = this._pts[start0];
34062 var p01 = this._pts[end0];
34063 var p10 = mc._pts[start1];
34064 var p11 = mc._pts[end1];
34065 if (end0 - start0 === 1 && end1 - start1 === 1) {
34066 mco.overlap(this, start0, mc, start1);
34067 return null
34068 }
34069 mco.tempEnv1.init(p00, p01);
34070 mco.tempEnv2.init(p10, p11);
34071 if (!mco.tempEnv1.intersects(mco.tempEnv2)) { return null }
34072 var mid0 = Math.trunc((start0 + end0) / 2);
34073 var mid1 = Math.trunc((start1 + end1) / 2);
34074 if (start0 < mid0) {
34075 if (start1 < mid1) { this.computeOverlapsInternal(start0, mid0, mc, start1, mid1, mco); }
34076 if (mid1 < end1) { this.computeOverlapsInternal(start0, mid0, mc, mid1, end1, mco); }
34077 }
34078 if (mid0 < end0) {
34079 if (start1 < mid1) { this.computeOverlapsInternal(mid0, end0, mc, start1, mid1, mco); }
34080 if (mid1 < end1) { this.computeOverlapsInternal(mid0, end0, mc, mid1, end1, mco); }
34081 }
34082};
34083MonotoneChain.prototype.interfaces_ = function interfaces_ () {
34084 return []
34085};
34086MonotoneChain.prototype.getClass = function getClass () {
34087 return MonotoneChain
34088};
34089
34090var MonotoneChainBuilder = function MonotoneChainBuilder () {};
34091
34092MonotoneChainBuilder.prototype.interfaces_ = function interfaces_ () {
34093 return []
34094};
34095MonotoneChainBuilder.prototype.getClass = function getClass () {
34096 return MonotoneChainBuilder
34097};
34098MonotoneChainBuilder.getChainStartIndices = function getChainStartIndices (pts) {
34099 var start = 0;
34100 var startIndexList = new ArrayList();
34101 startIndexList.add(new Integer(start));
34102 do {
34103 var last = MonotoneChainBuilder.findChainEnd(pts, start);
34104 startIndexList.add(new Integer(last));
34105 start = last;
34106 } while (start < pts.length - 1)
34107 var startIndex = MonotoneChainBuilder.toIntArray(startIndexList);
34108 return startIndex
34109};
34110MonotoneChainBuilder.findChainEnd = function findChainEnd (pts, start) {
34111 var safeStart = start;
34112 while (safeStart < pts.length - 1 && pts[safeStart].equals2D(pts[safeStart + 1])) {
34113 safeStart++;
34114 }
34115 if (safeStart >= pts.length - 1) {
34116 return pts.length - 1
34117 }
34118 var chainQuad = Quadrant.quadrant(pts[safeStart], pts[safeStart + 1]);
34119 var last = start + 1;
34120 while (last < pts.length) {
34121 if (!pts[last - 1].equals2D(pts[last])) {
34122 var quad = Quadrant.quadrant(pts[last - 1], pts[last]);
34123 if (quad !== chainQuad) { break }
34124 }
34125 last++;
34126 }
34127 return last - 1
34128};
34129MonotoneChainBuilder.getChains = function getChains () {
34130 if (arguments.length === 1) {
34131 var pts = arguments[0];
34132 return MonotoneChainBuilder.getChains(pts, null)
34133 } else if (arguments.length === 2) {
34134 var pts$1 = arguments[0];
34135 var context = arguments[1];
34136 var mcList = new ArrayList();
34137 var startIndex = MonotoneChainBuilder.getChainStartIndices(pts$1);
34138 for (var i = 0; i < startIndex.length - 1; i++) {
34139 var mc = new MonotoneChain(pts$1, startIndex[i], startIndex[i + 1], context);
34140 mcList.add(mc);
34141 }
34142 return mcList
34143 }
34144};
34145MonotoneChainBuilder.toIntArray = function toIntArray (list) {
34146 var array = new Array(list.size()).fill(null);
34147 for (var i = 0; i < array.length; i++) {
34148 array[i] = list.get(i).intValue();
34149 }
34150 return array
34151};
34152
34153var Noder = function Noder () {};
34154
34155Noder.prototype.computeNodes = function computeNodes (segStrings) {};
34156Noder.prototype.getNodedSubstrings = function getNodedSubstrings () {};
34157Noder.prototype.interfaces_ = function interfaces_ () {
34158 return []
34159};
34160Noder.prototype.getClass = function getClass () {
34161 return Noder
34162};
34163
34164var SinglePassNoder = function SinglePassNoder () {
34165 this._segInt = null;
34166 if (arguments.length === 0) {} else if (arguments.length === 1) {
34167 var segInt = arguments[0];
34168 this.setSegmentIntersector(segInt);
34169 }
34170};
34171SinglePassNoder.prototype.setSegmentIntersector = function setSegmentIntersector (segInt) {
34172 this._segInt = segInt;
34173};
34174SinglePassNoder.prototype.interfaces_ = function interfaces_ () {
34175 return [Noder]
34176};
34177SinglePassNoder.prototype.getClass = function getClass () {
34178 return SinglePassNoder
34179};
34180
34181var MCIndexNoder = (function (SinglePassNoder$$1) {
34182 function MCIndexNoder (si) {
34183 if (si) { SinglePassNoder$$1.call(this, si); }
34184 else { SinglePassNoder$$1.call(this); }
34185 this._monoChains = new ArrayList();
34186 this._index = new STRtree();
34187 this._idCounter = 0;
34188 this._nodedSegStrings = null;
34189 this._nOverlaps = 0;
34190 }
34191
34192 if ( SinglePassNoder$$1 ) MCIndexNoder.__proto__ = SinglePassNoder$$1;
34193 MCIndexNoder.prototype = Object.create( SinglePassNoder$$1 && SinglePassNoder$$1.prototype );
34194 MCIndexNoder.prototype.constructor = MCIndexNoder;
34195
34196 var staticAccessors = { SegmentOverlapAction: { configurable: true } };
34197 MCIndexNoder.prototype.getMonotoneChains = function getMonotoneChains () {
34198 return this._monoChains
34199 };
34200 MCIndexNoder.prototype.getNodedSubstrings = function getNodedSubstrings () {
34201 return NodedSegmentString.getNodedSubstrings(this._nodedSegStrings)
34202 };
34203 MCIndexNoder.prototype.getIndex = function getIndex () {
34204 return this._index
34205 };
34206 MCIndexNoder.prototype.add = function add (segStr) {
34207 var this$1 = this;
34208
34209 var segChains = MonotoneChainBuilder.getChains(segStr.getCoordinates(), segStr);
34210 for (var i = segChains.iterator(); i.hasNext();) {
34211 var mc = i.next();
34212 mc.setId(this$1._idCounter++);
34213 this$1._index.insert(mc.getEnvelope(), mc);
34214 this$1._monoChains.add(mc);
34215 }
34216 };
34217 MCIndexNoder.prototype.computeNodes = function computeNodes (inputSegStrings) {
34218 var this$1 = this;
34219
34220 this._nodedSegStrings = inputSegStrings;
34221 for (var i = inputSegStrings.iterator(); i.hasNext();) {
34222 this$1.add(i.next());
34223 }
34224 this.intersectChains();
34225 };
34226 MCIndexNoder.prototype.intersectChains = function intersectChains () {
34227 var this$1 = this;
34228
34229 var overlapAction = new SegmentOverlapAction(this._segInt);
34230 for (var i = this._monoChains.iterator(); i.hasNext();) {
34231 var queryChain = i.next();
34232 var overlapChains = this$1._index.query(queryChain.getEnvelope());
34233 for (var j = overlapChains.iterator(); j.hasNext();) {
34234 var testChain = j.next();
34235 if (testChain.getId() > queryChain.getId()) {
34236 queryChain.computeOverlaps(testChain, overlapAction);
34237 this$1._nOverlaps++;
34238 }
34239 if (this$1._segInt.isDone()) { return null }
34240 }
34241 }
34242 };
34243 MCIndexNoder.prototype.interfaces_ = function interfaces_ () {
34244 return []
34245 };
34246 MCIndexNoder.prototype.getClass = function getClass () {
34247 return MCIndexNoder
34248 };
34249 staticAccessors.SegmentOverlapAction.get = function () { return SegmentOverlapAction };
34250
34251 Object.defineProperties( MCIndexNoder, staticAccessors );
34252
34253 return MCIndexNoder;
34254}(SinglePassNoder));
34255
34256var SegmentOverlapAction = (function (MonotoneChainOverlapAction$$1) {
34257 function SegmentOverlapAction () {
34258 MonotoneChainOverlapAction$$1.call(this);
34259 this._si = null;
34260 var si = arguments[0];
34261 this._si = si;
34262 }
34263
34264 if ( MonotoneChainOverlapAction$$1 ) SegmentOverlapAction.__proto__ = MonotoneChainOverlapAction$$1;
34265 SegmentOverlapAction.prototype = Object.create( MonotoneChainOverlapAction$$1 && MonotoneChainOverlapAction$$1.prototype );
34266 SegmentOverlapAction.prototype.constructor = SegmentOverlapAction;
34267 SegmentOverlapAction.prototype.overlap = function overlap () {
34268 if (arguments.length === 4) {
34269 var mc1 = arguments[0];
34270 var start1 = arguments[1];
34271 var mc2 = arguments[2];
34272 var start2 = arguments[3];
34273 var ss1 = mc1.getContext();
34274 var ss2 = mc2.getContext();
34275 this._si.processIntersections(ss1, start1, ss2, start2);
34276 } else { return MonotoneChainOverlapAction$$1.prototype.overlap.apply(this, arguments) }
34277 };
34278 SegmentOverlapAction.prototype.interfaces_ = function interfaces_ () {
34279 return []
34280 };
34281 SegmentOverlapAction.prototype.getClass = function getClass () {
34282 return SegmentOverlapAction
34283 };
34284
34285 return SegmentOverlapAction;
34286}(MonotoneChainOverlapAction));
34287
34288var BufferParameters = function BufferParameters () {
34289 this._quadrantSegments = BufferParameters.DEFAULT_QUADRANT_SEGMENTS;
34290 this._endCapStyle = BufferParameters.CAP_ROUND;
34291 this._joinStyle = BufferParameters.JOIN_ROUND;
34292 this._mitreLimit = BufferParameters.DEFAULT_MITRE_LIMIT;
34293 this._isSingleSided = false;
34294 this._simplifyFactor = BufferParameters.DEFAULT_SIMPLIFY_FACTOR;
34295
34296 if (arguments.length === 0) {} else if (arguments.length === 1) {
34297 var quadrantSegments = arguments[0];
34298 this.setQuadrantSegments(quadrantSegments);
34299 } else if (arguments.length === 2) {
34300 var quadrantSegments$1 = arguments[0];
34301 var endCapStyle = arguments[1];
34302 this.setQuadrantSegments(quadrantSegments$1);
34303 this.setEndCapStyle(endCapStyle);
34304 } else if (arguments.length === 4) {
34305 var quadrantSegments$2 = arguments[0];
34306 var endCapStyle$1 = arguments[1];
34307 var joinStyle = arguments[2];
34308 var mitreLimit = arguments[3];
34309 this.setQuadrantSegments(quadrantSegments$2);
34310 this.setEndCapStyle(endCapStyle$1);
34311 this.setJoinStyle(joinStyle);
34312 this.setMitreLimit(mitreLimit);
34313 }
34314};
34315
34316var staticAccessors$25 = { CAP_ROUND: { configurable: true },CAP_FLAT: { configurable: true },CAP_SQUARE: { configurable: true },JOIN_ROUND: { configurable: true },JOIN_MITRE: { configurable: true },JOIN_BEVEL: { configurable: true },DEFAULT_QUADRANT_SEGMENTS: { configurable: true },DEFAULT_MITRE_LIMIT: { configurable: true },DEFAULT_SIMPLIFY_FACTOR: { configurable: true } };
34317BufferParameters.prototype.getEndCapStyle = function getEndCapStyle () {
34318 return this._endCapStyle
34319};
34320BufferParameters.prototype.isSingleSided = function isSingleSided () {
34321 return this._isSingleSided
34322};
34323BufferParameters.prototype.setQuadrantSegments = function setQuadrantSegments (quadSegs) {
34324 this._quadrantSegments = quadSegs;
34325 if (this._quadrantSegments === 0) { this._joinStyle = BufferParameters.JOIN_BEVEL; }
34326 if (this._quadrantSegments < 0) {
34327 this._joinStyle = BufferParameters.JOIN_MITRE;
34328 this._mitreLimit = Math.abs(this._quadrantSegments);
34329 }
34330 if (quadSegs <= 0) {
34331 this._quadrantSegments = 1;
34332 }
34333 if (this._joinStyle !== BufferParameters.JOIN_ROUND) {
34334 this._quadrantSegments = BufferParameters.DEFAULT_QUADRANT_SEGMENTS;
34335 }
34336};
34337BufferParameters.prototype.getJoinStyle = function getJoinStyle () {
34338 return this._joinStyle
34339};
34340BufferParameters.prototype.setJoinStyle = function setJoinStyle (joinStyle) {
34341 this._joinStyle = joinStyle;
34342};
34343BufferParameters.prototype.setSimplifyFactor = function setSimplifyFactor (simplifyFactor) {
34344 this._simplifyFactor = simplifyFactor < 0 ? 0 : simplifyFactor;
34345};
34346BufferParameters.prototype.getSimplifyFactor = function getSimplifyFactor () {
34347 return this._simplifyFactor
34348};
34349BufferParameters.prototype.getQuadrantSegments = function getQuadrantSegments () {
34350 return this._quadrantSegments
34351};
34352BufferParameters.prototype.setEndCapStyle = function setEndCapStyle (endCapStyle) {
34353 this._endCapStyle = endCapStyle;
34354};
34355BufferParameters.prototype.getMitreLimit = function getMitreLimit () {
34356 return this._mitreLimit
34357};
34358BufferParameters.prototype.setMitreLimit = function setMitreLimit (mitreLimit) {
34359 this._mitreLimit = mitreLimit;
34360};
34361BufferParameters.prototype.setSingleSided = function setSingleSided (isSingleSided) {
34362 this._isSingleSided = isSingleSided;
34363};
34364BufferParameters.prototype.interfaces_ = function interfaces_ () {
34365 return []
34366};
34367BufferParameters.prototype.getClass = function getClass () {
34368 return BufferParameters
34369};
34370BufferParameters.bufferDistanceError = function bufferDistanceError (quadSegs) {
34371 var alpha = Math.PI / 2.0 / quadSegs;
34372 return 1 - Math.cos(alpha / 2.0)
34373};
34374staticAccessors$25.CAP_ROUND.get = function () { return 1 };
34375staticAccessors$25.CAP_FLAT.get = function () { return 2 };
34376staticAccessors$25.CAP_SQUARE.get = function () { return 3 };
34377staticAccessors$25.JOIN_ROUND.get = function () { return 1 };
34378staticAccessors$25.JOIN_MITRE.get = function () { return 2 };
34379staticAccessors$25.JOIN_BEVEL.get = function () { return 3 };
34380staticAccessors$25.DEFAULT_QUADRANT_SEGMENTS.get = function () { return 8 };
34381staticAccessors$25.DEFAULT_MITRE_LIMIT.get = function () { return 5.0 };
34382staticAccessors$25.DEFAULT_SIMPLIFY_FACTOR.get = function () { return 0.01 };
34383
34384Object.defineProperties( BufferParameters, staticAccessors$25 );
34385
34386var BufferInputLineSimplifier = function BufferInputLineSimplifier (inputLine) {
34387 this._distanceTol = null;
34388 this._isDeleted = null;
34389 this._angleOrientation = CGAlgorithms.COUNTERCLOCKWISE;
34390 this._inputLine = inputLine || null;
34391};
34392
34393var staticAccessors$26 = { INIT: { configurable: true },DELETE: { configurable: true },KEEP: { configurable: true },NUM_PTS_TO_CHECK: { configurable: true } };
34394BufferInputLineSimplifier.prototype.isDeletable = function isDeletable (i0, i1, i2, distanceTol) {
34395 var p0 = this._inputLine[i0];
34396 var p1 = this._inputLine[i1];
34397 var p2 = this._inputLine[i2];
34398 if (!this.isConcave(p0, p1, p2)) { return false }
34399 if (!this.isShallow(p0, p1, p2, distanceTol)) { return false }
34400 return this.isShallowSampled(p0, p1, i0, i2, distanceTol)
34401};
34402BufferInputLineSimplifier.prototype.deleteShallowConcavities = function deleteShallowConcavities () {
34403 var this$1 = this;
34404
34405 var index = 1;
34406 // const maxIndex = this._inputLine.length - 1
34407 var midIndex = this.findNextNonDeletedIndex(index);
34408 var lastIndex = this.findNextNonDeletedIndex(midIndex);
34409 var isChanged = false;
34410 while (lastIndex < this._inputLine.length) {
34411 var isMiddleVertexDeleted = false;
34412 if (this$1.isDeletable(index, midIndex, lastIndex, this$1._distanceTol)) {
34413 this$1._isDeleted[midIndex] = BufferInputLineSimplifier.DELETE;
34414 isMiddleVertexDeleted = true;
34415 isChanged = true;
34416 }
34417 if (isMiddleVertexDeleted) { index = lastIndex; } else { index = midIndex; }
34418 midIndex = this$1.findNextNonDeletedIndex(index);
34419 lastIndex = this$1.findNextNonDeletedIndex(midIndex);
34420 }
34421 return isChanged
34422};
34423BufferInputLineSimplifier.prototype.isShallowConcavity = function isShallowConcavity (p0, p1, p2, distanceTol) {
34424 var orientation = CGAlgorithms.computeOrientation(p0, p1, p2);
34425 var isAngleToSimplify = orientation === this._angleOrientation;
34426 if (!isAngleToSimplify) { return false }
34427 var dist = CGAlgorithms.distancePointLine(p1, p0, p2);
34428 return dist < distanceTol
34429};
34430BufferInputLineSimplifier.prototype.isShallowSampled = function isShallowSampled (p0, p2, i0, i2, distanceTol) {
34431 var this$1 = this;
34432
34433 var inc = Math.trunc((i2 - i0) / BufferInputLineSimplifier.NUM_PTS_TO_CHECK);
34434 if (inc <= 0) { inc = 1; }
34435 for (var i = i0; i < i2; i += inc) {
34436 if (!this$1.isShallow(p0, p2, this$1._inputLine[i], distanceTol)) { return false }
34437 }
34438 return true
34439};
34440BufferInputLineSimplifier.prototype.isConcave = function isConcave (p0, p1, p2) {
34441 var orientation = CGAlgorithms.computeOrientation(p0, p1, p2);
34442 var isConcave = orientation === this._angleOrientation;
34443 return isConcave
34444};
34445BufferInputLineSimplifier.prototype.simplify = function simplify (distanceTol) {
34446 var this$1 = this;
34447
34448 this._distanceTol = Math.abs(distanceTol);
34449 if (distanceTol < 0) { this._angleOrientation = CGAlgorithms.CLOCKWISE; }
34450 this._isDeleted = new Array(this._inputLine.length).fill(null);
34451 var isChanged = false;
34452 do {
34453 isChanged = this$1.deleteShallowConcavities();
34454 } while (isChanged)
34455 return this.collapseLine()
34456};
34457BufferInputLineSimplifier.prototype.findNextNonDeletedIndex = function findNextNonDeletedIndex (index) {
34458 var next = index + 1;
34459 while (next < this._inputLine.length && this._isDeleted[next] === BufferInputLineSimplifier.DELETE) { next++; }
34460 return next
34461};
34462BufferInputLineSimplifier.prototype.isShallow = function isShallow (p0, p1, p2, distanceTol) {
34463 var dist = CGAlgorithms.distancePointLine(p1, p0, p2);
34464 return dist < distanceTol
34465};
34466BufferInputLineSimplifier.prototype.collapseLine = function collapseLine () {
34467 var this$1 = this;
34468
34469 var coordList = new CoordinateList();
34470 for (var i = 0; i < this._inputLine.length; i++) {
34471 if (this$1._isDeleted[i] !== BufferInputLineSimplifier.DELETE) { coordList.add(this$1._inputLine[i]); }
34472 }
34473 return coordList.toCoordinateArray()
34474};
34475BufferInputLineSimplifier.prototype.interfaces_ = function interfaces_ () {
34476 return []
34477};
34478BufferInputLineSimplifier.prototype.getClass = function getClass () {
34479 return BufferInputLineSimplifier
34480};
34481BufferInputLineSimplifier.simplify = function simplify (inputLine, distanceTol) {
34482 var simp = new BufferInputLineSimplifier(inputLine);
34483 return simp.simplify(distanceTol)
34484};
34485staticAccessors$26.INIT.get = function () { return 0 };
34486staticAccessors$26.DELETE.get = function () { return 1 };
34487staticAccessors$26.KEEP.get = function () { return 1 };
34488staticAccessors$26.NUM_PTS_TO_CHECK.get = function () { return 10 };
34489
34490Object.defineProperties( BufferInputLineSimplifier, staticAccessors$26 );
34491
34492var OffsetSegmentString = function OffsetSegmentString () {
34493 this._ptList = null;
34494 this._precisionModel = null;
34495 this._minimimVertexDistance = 0.0;
34496 this._ptList = new ArrayList();
34497};
34498
34499var staticAccessors$28 = { COORDINATE_ARRAY_TYPE: { configurable: true } };
34500OffsetSegmentString.prototype.getCoordinates = function getCoordinates () {
34501 var coord = this._ptList.toArray(OffsetSegmentString.COORDINATE_ARRAY_TYPE);
34502 return coord
34503};
34504OffsetSegmentString.prototype.setPrecisionModel = function setPrecisionModel (precisionModel) {
34505 this._precisionModel = precisionModel;
34506};
34507OffsetSegmentString.prototype.addPt = function addPt (pt) {
34508 var bufPt = new Coordinate(pt);
34509 this._precisionModel.makePrecise(bufPt);
34510 if (this.isRedundant(bufPt)) { return null }
34511 this._ptList.add(bufPt);
34512};
34513OffsetSegmentString.prototype.revere = function revere () {};
34514OffsetSegmentString.prototype.addPts = function addPts (pt, isForward) {
34515 var this$1 = this;
34516
34517 if (isForward) {
34518 for (var i = 0; i < pt.length; i++) {
34519 this$1.addPt(pt[i]);
34520 }
34521 } else {
34522 for (var i$1 = pt.length - 1; i$1 >= 0; i$1--) {
34523 this$1.addPt(pt[i$1]);
34524 }
34525 }
34526};
34527OffsetSegmentString.prototype.isRedundant = function isRedundant (pt) {
34528 if (this._ptList.size() < 1) { return false }
34529 var lastPt = this._ptList.get(this._ptList.size() - 1);
34530 var ptDist = pt.distance(lastPt);
34531 if (ptDist < this._minimimVertexDistance) { return true }
34532 return false
34533};
34534OffsetSegmentString.prototype.toString = function toString () {
34535 var fact = new GeometryFactory();
34536 var line = fact.createLineString(this.getCoordinates());
34537 return line.toString()
34538};
34539OffsetSegmentString.prototype.closeRing = function closeRing () {
34540 if (this._ptList.size() < 1) { return null }
34541 var startPt = new Coordinate(this._ptList.get(0));
34542 var lastPt = this._ptList.get(this._ptList.size() - 1);
34543 // const last2Pt = null
34544 // if (this._ptList.size() >= 2) last2Pt = this._ptList.get(this._ptList.size() - 2)
34545 if (startPt.equals(lastPt)) { return null }
34546 this._ptList.add(startPt);
34547};
34548OffsetSegmentString.prototype.setMinimumVertexDistance = function setMinimumVertexDistance (minimimVertexDistance) {
34549 this._minimimVertexDistance = minimimVertexDistance;
34550};
34551OffsetSegmentString.prototype.interfaces_ = function interfaces_ () {
34552 return []
34553};
34554OffsetSegmentString.prototype.getClass = function getClass () {
34555 return OffsetSegmentString
34556};
34557staticAccessors$28.COORDINATE_ARRAY_TYPE.get = function () { return new Array(0).fill(null) };
34558
34559Object.defineProperties( OffsetSegmentString, staticAccessors$28 );
34560
34561var Angle = function Angle () {};
34562
34563var staticAccessors$29 = { PI_TIMES_2: { configurable: true },PI_OVER_2: { configurable: true },PI_OVER_4: { configurable: true },COUNTERCLOCKWISE: { configurable: true },CLOCKWISE: { configurable: true },NONE: { configurable: true } };
34564
34565Angle.prototype.interfaces_ = function interfaces_ () {
34566 return []
34567};
34568Angle.prototype.getClass = function getClass () {
34569 return Angle
34570};
34571Angle.toDegrees = function toDegrees (radians) {
34572 return radians * 180 / Math.PI
34573};
34574Angle.normalize = function normalize (angle) {
34575 while (angle > Math.PI) { angle -= Angle.PI_TIMES_2; }
34576 while (angle <= -Math.PI) { angle += Angle.PI_TIMES_2; }
34577 return angle
34578};
34579Angle.angle = function angle () {
34580 if (arguments.length === 1) {
34581 var p = arguments[0];
34582 return Math.atan2(p.y, p.x)
34583 } else if (arguments.length === 2) {
34584 var p0 = arguments[0];
34585 var p1 = arguments[1];
34586 var dx = p1.x - p0.x;
34587 var dy = p1.y - p0.y;
34588 return Math.atan2(dy, dx)
34589 }
34590};
34591Angle.isAcute = function isAcute (p0, p1, p2) {
34592 var dx0 = p0.x - p1.x;
34593 var dy0 = p0.y - p1.y;
34594 var dx1 = p2.x - p1.x;
34595 var dy1 = p2.y - p1.y;
34596 var dotprod = dx0 * dx1 + dy0 * dy1;
34597 return dotprod > 0
34598};
34599Angle.isObtuse = function isObtuse (p0, p1, p2) {
34600 var dx0 = p0.x - p1.x;
34601 var dy0 = p0.y - p1.y;
34602 var dx1 = p2.x - p1.x;
34603 var dy1 = p2.y - p1.y;
34604 var dotprod = dx0 * dx1 + dy0 * dy1;
34605 return dotprod < 0
34606};
34607Angle.interiorAngle = function interiorAngle (p0, p1, p2) {
34608 var anglePrev = Angle.angle(p1, p0);
34609 var angleNext = Angle.angle(p1, p2);
34610 return Math.abs(angleNext - anglePrev)
34611};
34612Angle.normalizePositive = function normalizePositive (angle) {
34613 if (angle < 0.0) {
34614 while (angle < 0.0) { angle += Angle.PI_TIMES_2; }
34615 if (angle >= Angle.PI_TIMES_2) { angle = 0.0; }
34616 } else {
34617 while (angle >= Angle.PI_TIMES_2) { angle -= Angle.PI_TIMES_2; }
34618 if (angle < 0.0) { angle = 0.0; }
34619 }
34620 return angle
34621};
34622Angle.angleBetween = function angleBetween (tip1, tail, tip2) {
34623 var a1 = Angle.angle(tail, tip1);
34624 var a2 = Angle.angle(tail, tip2);
34625 return Angle.diff(a1, a2)
34626};
34627Angle.diff = function diff (ang1, ang2) {
34628 var delAngle = null;
34629 if (ang1 < ang2) {
34630 delAngle = ang2 - ang1;
34631 } else {
34632 delAngle = ang1 - ang2;
34633 }
34634 if (delAngle > Math.PI) {
34635 delAngle = 2 * Math.PI - delAngle;
34636 }
34637 return delAngle
34638};
34639Angle.toRadians = function toRadians (angleDegrees) {
34640 return angleDegrees * Math.PI / 180.0
34641};
34642Angle.getTurn = function getTurn (ang1, ang2) {
34643 var crossproduct = Math.sin(ang2 - ang1);
34644 if (crossproduct > 0) {
34645 return Angle.COUNTERCLOCKWISE
34646 }
34647 if (crossproduct < 0) {
34648 return Angle.CLOCKWISE
34649 }
34650 return Angle.NONE
34651};
34652Angle.angleBetweenOriented = function angleBetweenOriented (tip1, tail, tip2) {
34653 var a1 = Angle.angle(tail, tip1);
34654 var a2 = Angle.angle(tail, tip2);
34655 var angDel = a2 - a1;
34656 if (angDel <= -Math.PI) { return angDel + Angle.PI_TIMES_2 }
34657 if (angDel > Math.PI) { return angDel - Angle.PI_TIMES_2 }
34658 return angDel
34659};
34660staticAccessors$29.PI_TIMES_2.get = function () { return 2.0 * Math.PI };
34661staticAccessors$29.PI_OVER_2.get = function () { return Math.PI / 2.0 };
34662staticAccessors$29.PI_OVER_4.get = function () { return Math.PI / 4.0 };
34663staticAccessors$29.COUNTERCLOCKWISE.get = function () { return CGAlgorithms.COUNTERCLOCKWISE };
34664staticAccessors$29.CLOCKWISE.get = function () { return CGAlgorithms.CLOCKWISE };
34665staticAccessors$29.NONE.get = function () { return CGAlgorithms.COLLINEAR };
34666
34667Object.defineProperties( Angle, staticAccessors$29 );
34668
34669var OffsetSegmentGenerator = function OffsetSegmentGenerator () {
34670 this._maxCurveSegmentError = 0.0;
34671 this._filletAngleQuantum = null;
34672 this._closingSegLengthFactor = 1;
34673 this._segList = null;
34674 this._distance = 0.0;
34675 this._precisionModel = null;
34676 this._bufParams = null;
34677 this._li = null;
34678 this._s0 = null;
34679 this._s1 = null;
34680 this._s2 = null;
34681 this._seg0 = new LineSegment();
34682 this._seg1 = new LineSegment();
34683 this._offset0 = new LineSegment();
34684 this._offset1 = new LineSegment();
34685 this._side = 0;
34686 this._hasNarrowConcaveAngle = false;
34687 var precisionModel = arguments[0];
34688 var bufParams = arguments[1];
34689 var distance = arguments[2];
34690 this._precisionModel = precisionModel;
34691 this._bufParams = bufParams;
34692 this._li = new RobustLineIntersector();
34693 this._filletAngleQuantum = Math.PI / 2.0 / bufParams.getQuadrantSegments();
34694 if (bufParams.getQuadrantSegments() >= 8 && bufParams.getJoinStyle() === BufferParameters.JOIN_ROUND) { this._closingSegLengthFactor = OffsetSegmentGenerator.MAX_CLOSING_SEG_LEN_FACTOR; }
34695 this.init(distance);
34696};
34697
34698var staticAccessors$27 = { OFFSET_SEGMENT_SEPARATION_FACTOR: { configurable: true },INSIDE_TURN_VERTEX_SNAP_DISTANCE_FACTOR: { configurable: true },CURVE_VERTEX_SNAP_DISTANCE_FACTOR: { configurable: true },MAX_CLOSING_SEG_LEN_FACTOR: { configurable: true } };
34699OffsetSegmentGenerator.prototype.addNextSegment = function addNextSegment (p, addStartPoint) {
34700 this._s0 = this._s1;
34701 this._s1 = this._s2;
34702 this._s2 = p;
34703 this._seg0.setCoordinates(this._s0, this._s1);
34704 this.computeOffsetSegment(this._seg0, this._side, this._distance, this._offset0);
34705 this._seg1.setCoordinates(this._s1, this._s2);
34706 this.computeOffsetSegment(this._seg1, this._side, this._distance, this._offset1);
34707 if (this._s1.equals(this._s2)) { return null }
34708 var orientation = CGAlgorithms.computeOrientation(this._s0, this._s1, this._s2);
34709 var outsideTurn = (orientation === CGAlgorithms.CLOCKWISE && this._side === Position.LEFT) || (orientation === CGAlgorithms.COUNTERCLOCKWISE && this._side === Position.RIGHT);
34710 if (orientation === 0) {
34711 this.addCollinear(addStartPoint);
34712 } else if (outsideTurn) {
34713 this.addOutsideTurn(orientation, addStartPoint);
34714 } else {
34715 this.addInsideTurn(orientation, addStartPoint);
34716 }
34717};
34718OffsetSegmentGenerator.prototype.addLineEndCap = function addLineEndCap (p0, p1) {
34719 var seg = new LineSegment(p0, p1);
34720 var offsetL = new LineSegment();
34721 this.computeOffsetSegment(seg, Position.LEFT, this._distance, offsetL);
34722 var offsetR = new LineSegment();
34723 this.computeOffsetSegment(seg, Position.RIGHT, this._distance, offsetR);
34724 var dx = p1.x - p0.x;
34725 var dy = p1.y - p0.y;
34726 var angle = Math.atan2(dy, dx);
34727 switch (this._bufParams.getEndCapStyle()) {
34728 case BufferParameters.CAP_ROUND:
34729 this._segList.addPt(offsetL.p1);
34730 this.addFilletArc(p1, angle + Math.PI / 2, angle - Math.PI / 2, CGAlgorithms.CLOCKWISE, this._distance);
34731 this._segList.addPt(offsetR.p1);
34732 break
34733 case BufferParameters.CAP_FLAT:
34734 this._segList.addPt(offsetL.p1);
34735 this._segList.addPt(offsetR.p1);
34736 break
34737 case BufferParameters.CAP_SQUARE:
34738 var squareCapSideOffset = new Coordinate();
34739 squareCapSideOffset.x = Math.abs(this._distance) * Math.cos(angle);
34740 squareCapSideOffset.y = Math.abs(this._distance) * Math.sin(angle);
34741 var squareCapLOffset = new Coordinate(offsetL.p1.x + squareCapSideOffset.x, offsetL.p1.y + squareCapSideOffset.y);
34742 var squareCapROffset = new Coordinate(offsetR.p1.x + squareCapSideOffset.x, offsetR.p1.y + squareCapSideOffset.y);
34743 this._segList.addPt(squareCapLOffset);
34744 this._segList.addPt(squareCapROffset);
34745 break
34746 default:
34747 }
34748};
34749OffsetSegmentGenerator.prototype.getCoordinates = function getCoordinates () {
34750 var pts = this._segList.getCoordinates();
34751 return pts
34752};
34753OffsetSegmentGenerator.prototype.addMitreJoin = function addMitreJoin (p, offset0, offset1, distance) {
34754 var isMitreWithinLimit = true;
34755 var intPt = null;
34756 try {
34757 intPt = HCoordinate.intersection(offset0.p0, offset0.p1, offset1.p0, offset1.p1);
34758 var mitreRatio = distance <= 0.0 ? 1.0 : intPt.distance(p) / Math.abs(distance);
34759 if (mitreRatio > this._bufParams.getMitreLimit()) { isMitreWithinLimit = false; }
34760 } catch (ex) {
34761 if (ex instanceof NotRepresentableException) {
34762 intPt = new Coordinate(0, 0);
34763 isMitreWithinLimit = false;
34764 } else { throw ex }
34765 } finally {}
34766 if (isMitreWithinLimit) {
34767 this._segList.addPt(intPt);
34768 } else {
34769 this.addLimitedMitreJoin(offset0, offset1, distance, this._bufParams.getMitreLimit());
34770 }
34771};
34772OffsetSegmentGenerator.prototype.addFilletCorner = function addFilletCorner (p, p0, p1, direction, radius) {
34773 var dx0 = p0.x - p.x;
34774 var dy0 = p0.y - p.y;
34775 var startAngle = Math.atan2(dy0, dx0);
34776 var dx1 = p1.x - p.x;
34777 var dy1 = p1.y - p.y;
34778 var endAngle = Math.atan2(dy1, dx1);
34779 if (direction === CGAlgorithms.CLOCKWISE) {
34780 if (startAngle <= endAngle) { startAngle += 2.0 * Math.PI; }
34781 } else {
34782 if (startAngle >= endAngle) { startAngle -= 2.0 * Math.PI; }
34783 }
34784 this._segList.addPt(p0);
34785 this.addFilletArc(p, startAngle, endAngle, direction, radius);
34786 this._segList.addPt(p1);
34787};
34788OffsetSegmentGenerator.prototype.addOutsideTurn = function addOutsideTurn (orientation, addStartPoint) {
34789 if (this._offset0.p1.distance(this._offset1.p0) < this._distance * OffsetSegmentGenerator.OFFSET_SEGMENT_SEPARATION_FACTOR) {
34790 this._segList.addPt(this._offset0.p1);
34791 return null
34792 }
34793 if (this._bufParams.getJoinStyle() === BufferParameters.JOIN_MITRE) {
34794 this.addMitreJoin(this._s1, this._offset0, this._offset1, this._distance);
34795 } else if (this._bufParams.getJoinStyle() === BufferParameters.JOIN_BEVEL) {
34796 this.addBevelJoin(this._offset0, this._offset1);
34797 } else {
34798 if (addStartPoint) { this._segList.addPt(this._offset0.p1); }
34799 this.addFilletCorner(this._s1, this._offset0.p1, this._offset1.p0, orientation, this._distance);
34800 this._segList.addPt(this._offset1.p0);
34801 }
34802};
34803OffsetSegmentGenerator.prototype.createSquare = function createSquare (p) {
34804 this._segList.addPt(new Coordinate(p.x + this._distance, p.y + this._distance));
34805 this._segList.addPt(new Coordinate(p.x + this._distance, p.y - this._distance));
34806 this._segList.addPt(new Coordinate(p.x - this._distance, p.y - this._distance));
34807 this._segList.addPt(new Coordinate(p.x - this._distance, p.y + this._distance));
34808 this._segList.closeRing();
34809};
34810OffsetSegmentGenerator.prototype.addSegments = function addSegments (pt, isForward) {
34811 this._segList.addPts(pt, isForward);
34812};
34813OffsetSegmentGenerator.prototype.addFirstSegment = function addFirstSegment () {
34814 this._segList.addPt(this._offset1.p0);
34815};
34816OffsetSegmentGenerator.prototype.addLastSegment = function addLastSegment () {
34817 this._segList.addPt(this._offset1.p1);
34818};
34819OffsetSegmentGenerator.prototype.initSideSegments = function initSideSegments (s1, s2, side) {
34820 this._s1 = s1;
34821 this._s2 = s2;
34822 this._side = side;
34823 this._seg1.setCoordinates(s1, s2);
34824 this.computeOffsetSegment(this._seg1, side, this._distance, this._offset1);
34825};
34826OffsetSegmentGenerator.prototype.addLimitedMitreJoin = function addLimitedMitreJoin (offset0, offset1, distance, mitreLimit) {
34827 var basePt = this._seg0.p1;
34828 var ang0 = Angle.angle(basePt, this._seg0.p0);
34829 // const ang1 = Angle.angle(basePt, this._seg1.p1)
34830 var angDiff = Angle.angleBetweenOriented(this._seg0.p0, basePt, this._seg1.p1);
34831 var angDiffHalf = angDiff / 2;
34832 var midAng = Angle.normalize(ang0 + angDiffHalf);
34833 var mitreMidAng = Angle.normalize(midAng + Math.PI);
34834 var mitreDist = mitreLimit * distance;
34835 var bevelDelta = mitreDist * Math.abs(Math.sin(angDiffHalf));
34836 var bevelHalfLen = distance - bevelDelta;
34837 var bevelMidX = basePt.x + mitreDist * Math.cos(mitreMidAng);
34838 var bevelMidY = basePt.y + mitreDist * Math.sin(mitreMidAng);
34839 var bevelMidPt = new Coordinate(bevelMidX, bevelMidY);
34840 var mitreMidLine = new LineSegment(basePt, bevelMidPt);
34841 var bevelEndLeft = mitreMidLine.pointAlongOffset(1.0, bevelHalfLen);
34842 var bevelEndRight = mitreMidLine.pointAlongOffset(1.0, -bevelHalfLen);
34843 if (this._side === Position.LEFT) {
34844 this._segList.addPt(bevelEndLeft);
34845 this._segList.addPt(bevelEndRight);
34846 } else {
34847 this._segList.addPt(bevelEndRight);
34848 this._segList.addPt(bevelEndLeft);
34849 }
34850};
34851OffsetSegmentGenerator.prototype.computeOffsetSegment = function computeOffsetSegment (seg, side, distance, offset) {
34852 var sideSign = side === Position.LEFT ? 1 : -1;
34853 var dx = seg.p1.x - seg.p0.x;
34854 var dy = seg.p1.y - seg.p0.y;
34855 var len = Math.sqrt(dx * dx + dy * dy);
34856 var ux = sideSign * distance * dx / len;
34857 var uy = sideSign * distance * dy / len;
34858 offset.p0.x = seg.p0.x - uy;
34859 offset.p0.y = seg.p0.y + ux;
34860 offset.p1.x = seg.p1.x - uy;
34861 offset.p1.y = seg.p1.y + ux;
34862};
34863OffsetSegmentGenerator.prototype.addFilletArc = function addFilletArc (p, startAngle, endAngle, direction, radius) {
34864 var this$1 = this;
34865
34866 var directionFactor = direction === CGAlgorithms.CLOCKWISE ? -1 : 1;
34867 var totalAngle = Math.abs(startAngle - endAngle);
34868 var nSegs = Math.trunc(totalAngle / this._filletAngleQuantum + 0.5);
34869 if (nSegs < 1) { return null }
34870 var initAngle = 0.0;
34871 var currAngleInc = totalAngle / nSegs;
34872 var currAngle = initAngle;
34873 var pt = new Coordinate();
34874 while (currAngle < totalAngle) {
34875 var angle = startAngle + directionFactor * currAngle;
34876 pt.x = p.x + radius * Math.cos(angle);
34877 pt.y = p.y + radius * Math.sin(angle);
34878 this$1._segList.addPt(pt);
34879 currAngle += currAngleInc;
34880 }
34881};
34882OffsetSegmentGenerator.prototype.addInsideTurn = function addInsideTurn (orientation, addStartPoint) {
34883 this._li.computeIntersection(this._offset0.p0, this._offset0.p1, this._offset1.p0, this._offset1.p1);
34884 if (this._li.hasIntersection()) {
34885 this._segList.addPt(this._li.getIntersection(0));
34886 } else {
34887 this._hasNarrowConcaveAngle = true;
34888 if (this._offset0.p1.distance(this._offset1.p0) < this._distance * OffsetSegmentGenerator.INSIDE_TURN_VERTEX_SNAP_DISTANCE_FACTOR) {
34889 this._segList.addPt(this._offset0.p1);
34890 } else {
34891 this._segList.addPt(this._offset0.p1);
34892 if (this._closingSegLengthFactor > 0) {
34893 var mid0 = new Coordinate((this._closingSegLengthFactor * this._offset0.p1.x + this._s1.x) / (this._closingSegLengthFactor + 1), (this._closingSegLengthFactor * this._offset0.p1.y + this._s1.y) / (this._closingSegLengthFactor + 1));
34894 this._segList.addPt(mid0);
34895 var mid1 = new Coordinate((this._closingSegLengthFactor * this._offset1.p0.x + this._s1.x) / (this._closingSegLengthFactor + 1), (this._closingSegLengthFactor * this._offset1.p0.y + this._s1.y) / (this._closingSegLengthFactor + 1));
34896 this._segList.addPt(mid1);
34897 } else {
34898 this._segList.addPt(this._s1);
34899 }
34900 this._segList.addPt(this._offset1.p0);
34901 }
34902 }
34903};
34904OffsetSegmentGenerator.prototype.createCircle = function createCircle (p) {
34905 var pt = new Coordinate(p.x + this._distance, p.y);
34906 this._segList.addPt(pt);
34907 this.addFilletArc(p, 0.0, 2.0 * Math.PI, -1, this._distance);
34908 this._segList.closeRing();
34909};
34910OffsetSegmentGenerator.prototype.addBevelJoin = function addBevelJoin (offset0, offset1) {
34911 this._segList.addPt(offset0.p1);
34912 this._segList.addPt(offset1.p0);
34913};
34914OffsetSegmentGenerator.prototype.init = function init (distance) {
34915 this._distance = distance;
34916 this._maxCurveSegmentError = distance * (1 - Math.cos(this._filletAngleQuantum / 2.0));
34917 this._segList = new OffsetSegmentString();
34918 this._segList.setPrecisionModel(this._precisionModel);
34919 this._segList.setMinimumVertexDistance(distance * OffsetSegmentGenerator.CURVE_VERTEX_SNAP_DISTANCE_FACTOR);
34920};
34921OffsetSegmentGenerator.prototype.addCollinear = function addCollinear (addStartPoint) {
34922 this._li.computeIntersection(this._s0, this._s1, this._s1, this._s2);
34923 var numInt = this._li.getIntersectionNum();
34924 if (numInt >= 2) {
34925 if (this._bufParams.getJoinStyle() === BufferParameters.JOIN_BEVEL || this._bufParams.getJoinStyle() === BufferParameters.JOIN_MITRE) {
34926 if (addStartPoint) { this._segList.addPt(this._offset0.p1); }
34927 this._segList.addPt(this._offset1.p0);
34928 } else {
34929 this.addFilletCorner(this._s1, this._offset0.p1, this._offset1.p0, CGAlgorithms.CLOCKWISE, this._distance);
34930 }
34931 }
34932};
34933OffsetSegmentGenerator.prototype.closeRing = function closeRing () {
34934 this._segList.closeRing();
34935};
34936OffsetSegmentGenerator.prototype.hasNarrowConcaveAngle = function hasNarrowConcaveAngle () {
34937 return this._hasNarrowConcaveAngle
34938};
34939OffsetSegmentGenerator.prototype.interfaces_ = function interfaces_ () {
34940 return []
34941};
34942OffsetSegmentGenerator.prototype.getClass = function getClass () {
34943 return OffsetSegmentGenerator
34944};
34945staticAccessors$27.OFFSET_SEGMENT_SEPARATION_FACTOR.get = function () { return 1.0E-3 };
34946staticAccessors$27.INSIDE_TURN_VERTEX_SNAP_DISTANCE_FACTOR.get = function () { return 1.0E-3 };
34947staticAccessors$27.CURVE_VERTEX_SNAP_DISTANCE_FACTOR.get = function () { return 1.0E-6 };
34948staticAccessors$27.MAX_CLOSING_SEG_LEN_FACTOR.get = function () { return 80 };
34949
34950Object.defineProperties( OffsetSegmentGenerator, staticAccessors$27 );
34951
34952var OffsetCurveBuilder = function OffsetCurveBuilder () {
34953 this._distance = 0.0;
34954 this._precisionModel = null;
34955 this._bufParams = null;
34956 var precisionModel = arguments[0];
34957 var bufParams = arguments[1];
34958 this._precisionModel = precisionModel;
34959 this._bufParams = bufParams;
34960};
34961OffsetCurveBuilder.prototype.getOffsetCurve = function getOffsetCurve (inputPts, distance) {
34962 this._distance = distance;
34963 if (distance === 0.0) { return null }
34964 var isRightSide = distance < 0.0;
34965 var posDistance = Math.abs(distance);
34966 var segGen = this.getSegGen(posDistance);
34967 if (inputPts.length <= 1) {
34968 this.computePointCurve(inputPts[0], segGen);
34969 } else {
34970 this.computeOffsetCurve(inputPts, isRightSide, segGen);
34971 }
34972 var curvePts = segGen.getCoordinates();
34973 if (isRightSide) { CoordinateArrays.reverse(curvePts); }
34974 return curvePts
34975};
34976OffsetCurveBuilder.prototype.computeSingleSidedBufferCurve = function computeSingleSidedBufferCurve (inputPts, isRightSide, segGen) {
34977 var distTol = this.simplifyTolerance(this._distance);
34978 if (isRightSide) {
34979 segGen.addSegments(inputPts, true);
34980 var simp2 = BufferInputLineSimplifier.simplify(inputPts, -distTol);
34981 var n2 = simp2.length - 1;
34982 segGen.initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT);
34983 segGen.addFirstSegment();
34984 for (var i = n2 - 2; i >= 0; i--) {
34985 segGen.addNextSegment(simp2[i], true);
34986 }
34987 } else {
34988 segGen.addSegments(inputPts, false);
34989 var simp1 = BufferInputLineSimplifier.simplify(inputPts, distTol);
34990 var n1 = simp1.length - 1;
34991 segGen.initSideSegments(simp1[0], simp1[1], Position.LEFT);
34992 segGen.addFirstSegment();
34993 for (var i$1 = 2; i$1 <= n1; i$1++) {
34994 segGen.addNextSegment(simp1[i$1], true);
34995 }
34996 }
34997 segGen.addLastSegment();
34998 segGen.closeRing();
34999};
35000OffsetCurveBuilder.prototype.computeRingBufferCurve = function computeRingBufferCurve (inputPts, side, segGen) {
35001 var distTol = this.simplifyTolerance(this._distance);
35002 if (side === Position.RIGHT) { distTol = -distTol; }
35003 var simp = BufferInputLineSimplifier.simplify(inputPts, distTol);
35004 var n = simp.length - 1;
35005 segGen.initSideSegments(simp[n - 1], simp[0], side);
35006 for (var i = 1; i <= n; i++) {
35007 var addStartPoint = i !== 1;
35008 segGen.addNextSegment(simp[i], addStartPoint);
35009 }
35010 segGen.closeRing();
35011};
35012OffsetCurveBuilder.prototype.computeLineBufferCurve = function computeLineBufferCurve (inputPts, segGen) {
35013 var distTol = this.simplifyTolerance(this._distance);
35014 var simp1 = BufferInputLineSimplifier.simplify(inputPts, distTol);
35015 var n1 = simp1.length - 1;
35016 segGen.initSideSegments(simp1[0], simp1[1], Position.LEFT);
35017 for (var i = 2; i <= n1; i++) {
35018 segGen.addNextSegment(simp1[i], true);
35019 }
35020 segGen.addLastSegment();
35021 segGen.addLineEndCap(simp1[n1 - 1], simp1[n1]);
35022 var simp2 = BufferInputLineSimplifier.simplify(inputPts, -distTol);
35023 var n2 = simp2.length - 1;
35024 segGen.initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT);
35025 for (var i$1 = n2 - 2; i$1 >= 0; i$1--) {
35026 segGen.addNextSegment(simp2[i$1], true);
35027 }
35028 segGen.addLastSegment();
35029 segGen.addLineEndCap(simp2[1], simp2[0]);
35030 segGen.closeRing();
35031};
35032OffsetCurveBuilder.prototype.computePointCurve = function computePointCurve (pt, segGen) {
35033 switch (this._bufParams.getEndCapStyle()) {
35034 case BufferParameters.CAP_ROUND:
35035 segGen.createCircle(pt);
35036 break
35037 case BufferParameters.CAP_SQUARE:
35038 segGen.createSquare(pt);
35039 break
35040 default:
35041 }
35042};
35043OffsetCurveBuilder.prototype.getLineCurve = function getLineCurve (inputPts, distance) {
35044 this._distance = distance;
35045 if (distance < 0.0 && !this._bufParams.isSingleSided()) { return null }
35046 if (distance === 0.0) { return null }
35047 var posDistance = Math.abs(distance);
35048 var segGen = this.getSegGen(posDistance);
35049 if (inputPts.length <= 1) {
35050 this.computePointCurve(inputPts[0], segGen);
35051 } else {
35052 if (this._bufParams.isSingleSided()) {
35053 var isRightSide = distance < 0.0;
35054 this.computeSingleSidedBufferCurve(inputPts, isRightSide, segGen);
35055 } else { this.computeLineBufferCurve(inputPts, segGen); }
35056 }
35057 var lineCoord = segGen.getCoordinates();
35058 return lineCoord
35059};
35060OffsetCurveBuilder.prototype.getBufferParameters = function getBufferParameters () {
35061 return this._bufParams
35062};
35063OffsetCurveBuilder.prototype.simplifyTolerance = function simplifyTolerance (bufDistance) {
35064 return bufDistance * this._bufParams.getSimplifyFactor()
35065};
35066OffsetCurveBuilder.prototype.getRingCurve = function getRingCurve (inputPts, side, distance) {
35067 this._distance = distance;
35068 if (inputPts.length <= 2) { return this.getLineCurve(inputPts, distance) }
35069 if (distance === 0.0) {
35070 return OffsetCurveBuilder.copyCoordinates(inputPts)
35071 }
35072 var segGen = this.getSegGen(distance);
35073 this.computeRingBufferCurve(inputPts, side, segGen);
35074 return segGen.getCoordinates()
35075};
35076OffsetCurveBuilder.prototype.computeOffsetCurve = function computeOffsetCurve (inputPts, isRightSide, segGen) {
35077 var distTol = this.simplifyTolerance(this._distance);
35078 if (isRightSide) {
35079 var simp2 = BufferInputLineSimplifier.simplify(inputPts, -distTol);
35080 var n2 = simp2.length - 1;
35081 segGen.initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT);
35082 segGen.addFirstSegment();
35083 for (var i = n2 - 2; i >= 0; i--) {
35084 segGen.addNextSegment(simp2[i], true);
35085 }
35086 } else {
35087 var simp1 = BufferInputLineSimplifier.simplify(inputPts, distTol);
35088 var n1 = simp1.length - 1;
35089 segGen.initSideSegments(simp1[0], simp1[1], Position.LEFT);
35090 segGen.addFirstSegment();
35091 for (var i$1 = 2; i$1 <= n1; i$1++) {
35092 segGen.addNextSegment(simp1[i$1], true);
35093 }
35094 }
35095 segGen.addLastSegment();
35096};
35097OffsetCurveBuilder.prototype.getSegGen = function getSegGen (distance) {
35098 return new OffsetSegmentGenerator(this._precisionModel, this._bufParams, distance)
35099};
35100OffsetCurveBuilder.prototype.interfaces_ = function interfaces_ () {
35101 return []
35102};
35103OffsetCurveBuilder.prototype.getClass = function getClass () {
35104 return OffsetCurveBuilder
35105};
35106OffsetCurveBuilder.copyCoordinates = function copyCoordinates (pts) {
35107 var copy = new Array(pts.length).fill(null);
35108 for (var i = 0; i < copy.length; i++) {
35109 copy[i] = new Coordinate(pts[i]);
35110 }
35111 return copy
35112};
35113
35114var SubgraphDepthLocater = function SubgraphDepthLocater () {
35115 this._subgraphs = null;
35116 this._seg = new LineSegment();
35117 this._cga = new CGAlgorithms();
35118 var subgraphs = arguments[0];
35119 this._subgraphs = subgraphs;
35120};
35121
35122var staticAccessors$30 = { DepthSegment: { configurable: true } };
35123SubgraphDepthLocater.prototype.findStabbedSegments = function findStabbedSegments () {
35124 var this$1 = this;
35125
35126 if (arguments.length === 1) {
35127 var stabbingRayLeftPt = arguments[0];
35128 var stabbedSegments = new ArrayList();
35129 for (var i = this._subgraphs.iterator(); i.hasNext();) {
35130 var bsg = i.next();
35131 var env = bsg.getEnvelope();
35132 if (stabbingRayLeftPt.y < env.getMinY() || stabbingRayLeftPt.y > env.getMaxY()) { continue }
35133 this$1.findStabbedSegments(stabbingRayLeftPt, bsg.getDirectedEdges(), stabbedSegments);
35134 }
35135 return stabbedSegments
35136 } else if (arguments.length === 3) {
35137 if (hasInterface(arguments[2], List) && (arguments[0] instanceof Coordinate && arguments[1] instanceof DirectedEdge)) {
35138 var stabbingRayLeftPt$1 = arguments[0];
35139 var dirEdge = arguments[1];
35140 var stabbedSegments$1 = arguments[2];
35141 var pts = dirEdge.getEdge().getCoordinates();
35142 for (var i$1 = 0; i$1 < pts.length - 1; i$1++) {
35143 this$1._seg.p0 = pts[i$1];
35144 this$1._seg.p1 = pts[i$1 + 1];
35145 if (this$1._seg.p0.y > this$1._seg.p1.y) { this$1._seg.reverse(); }
35146 var maxx = Math.max(this$1._seg.p0.x, this$1._seg.p1.x);
35147 if (maxx < stabbingRayLeftPt$1.x) { continue }
35148 if (this$1._seg.isHorizontal()) { continue }
35149 if (stabbingRayLeftPt$1.y < this$1._seg.p0.y || stabbingRayLeftPt$1.y > this$1._seg.p1.y) { continue }
35150 if (CGAlgorithms.computeOrientation(this$1._seg.p0, this$1._seg.p1, stabbingRayLeftPt$1) === CGAlgorithms.RIGHT) { continue }
35151 var depth = dirEdge.getDepth(Position.LEFT);
35152 if (!this$1._seg.p0.equals(pts[i$1])) { depth = dirEdge.getDepth(Position.RIGHT); }
35153 var ds = new DepthSegment(this$1._seg, depth);
35154 stabbedSegments$1.add(ds);
35155 }
35156 } else if (hasInterface(arguments[2], List) && (arguments[0] instanceof Coordinate && hasInterface(arguments[1], List))) {
35157 var stabbingRayLeftPt$2 = arguments[0];
35158 var dirEdges = arguments[1];
35159 var stabbedSegments$2 = arguments[2];
35160 for (var i$2 = dirEdges.iterator(); i$2.hasNext();) {
35161 var de = i$2.next();
35162 if (!de.isForward()) { continue }
35163 this$1.findStabbedSegments(stabbingRayLeftPt$2, de, stabbedSegments$2);
35164 }
35165 }
35166 }
35167};
35168SubgraphDepthLocater.prototype.getDepth = function getDepth (p) {
35169 var stabbedSegments = this.findStabbedSegments(p);
35170 if (stabbedSegments.size() === 0) { return 0 }
35171 var ds = Collections.min(stabbedSegments);
35172 return ds._leftDepth
35173};
35174SubgraphDepthLocater.prototype.interfaces_ = function interfaces_ () {
35175 return []
35176};
35177SubgraphDepthLocater.prototype.getClass = function getClass () {
35178 return SubgraphDepthLocater
35179};
35180staticAccessors$30.DepthSegment.get = function () { return DepthSegment };
35181
35182Object.defineProperties( SubgraphDepthLocater, staticAccessors$30 );
35183
35184var DepthSegment = function DepthSegment () {
35185 this._upwardSeg = null;
35186 this._leftDepth = null;
35187 var seg = arguments[0];
35188 var depth = arguments[1];
35189 this._upwardSeg = new LineSegment(seg);
35190 this._leftDepth = depth;
35191};
35192DepthSegment.prototype.compareTo = function compareTo (obj) {
35193 var other = obj;
35194 if (this._upwardSeg.minX() >= other._upwardSeg.maxX()) { return 1 }
35195 if (this._upwardSeg.maxX() <= other._upwardSeg.minX()) { return -1 }
35196 var orientIndex = this._upwardSeg.orientationIndex(other._upwardSeg);
35197 if (orientIndex !== 0) { return orientIndex }
35198 orientIndex = -1 * other._upwardSeg.orientationIndex(this._upwardSeg);
35199 if (orientIndex !== 0) { return orientIndex }
35200 return this._upwardSeg.compareTo(other._upwardSeg)
35201};
35202DepthSegment.prototype.compareX = function compareX (seg0, seg1) {
35203 var compare0 = seg0.p0.compareTo(seg1.p0);
35204 if (compare0 !== 0) { return compare0 }
35205 return seg0.p1.compareTo(seg1.p1)
35206};
35207DepthSegment.prototype.toString = function toString () {
35208 return this._upwardSeg.toString()
35209};
35210DepthSegment.prototype.interfaces_ = function interfaces_ () {
35211 return [Comparable]
35212};
35213DepthSegment.prototype.getClass = function getClass () {
35214 return DepthSegment
35215};
35216
35217var Triangle$1 = function Triangle (p0, p1, p2) {
35218 this.p0 = p0 || null;
35219 this.p1 = p1 || null;
35220 this.p2 = p2 || null;
35221};
35222Triangle$1.prototype.area = function area () {
35223 return Triangle$1.area(this.p0, this.p1, this.p2)
35224};
35225Triangle$1.prototype.signedArea = function signedArea () {
35226 return Triangle$1.signedArea(this.p0, this.p1, this.p2)
35227};
35228Triangle$1.prototype.interpolateZ = function interpolateZ (p) {
35229 if (p === null) { throw new IllegalArgumentException('Supplied point is null.') }
35230 return Triangle$1.interpolateZ(p, this.p0, this.p1, this.p2)
35231};
35232Triangle$1.prototype.longestSideLength = function longestSideLength () {
35233 return Triangle$1.longestSideLength(this.p0, this.p1, this.p2)
35234};
35235Triangle$1.prototype.isAcute = function isAcute () {
35236 return Triangle$1.isAcute(this.p0, this.p1, this.p2)
35237};
35238Triangle$1.prototype.circumcentre = function circumcentre () {
35239 return Triangle$1.circumcentre(this.p0, this.p1, this.p2)
35240};
35241Triangle$1.prototype.area3D = function area3D () {
35242 return Triangle$1.area3D(this.p0, this.p1, this.p2)
35243};
35244Triangle$1.prototype.centroid = function centroid () {
35245 return Triangle$1.centroid(this.p0, this.p1, this.p2)
35246};
35247Triangle$1.prototype.inCentre = function inCentre () {
35248 return Triangle$1.inCentre(this.p0, this.p1, this.p2)
35249};
35250Triangle$1.prototype.interfaces_ = function interfaces_ () {
35251 return []
35252};
35253Triangle$1.prototype.getClass = function getClass () {
35254 return Triangle$1
35255};
35256Triangle$1.area = function area (a, b, c) {
35257 return Math.abs(((c.x - a.x) * (b.y - a.y) - (b.x - a.x) * (c.y - a.y)) / 2)
35258};
35259Triangle$1.signedArea = function signedArea (a, b, c) {
35260 return ((c.x - a.x) * (b.y - a.y) - (b.x - a.x) * (c.y - a.y)) / 2
35261};
35262Triangle$1.det = function det (m00, m01, m10, m11) {
35263 return m00 * m11 - m01 * m10
35264};
35265Triangle$1.interpolateZ = function interpolateZ (p, v0, v1, v2) {
35266 var x0 = v0.x;
35267 var y0 = v0.y;
35268 var a = v1.x - x0;
35269 var b = v2.x - x0;
35270 var c = v1.y - y0;
35271 var d = v2.y - y0;
35272 var det = a * d - b * c;
35273 var dx = p.x - x0;
35274 var dy = p.y - y0;
35275 var t = (d * dx - b * dy) / det;
35276 var u = (-c * dx + a * dy) / det;
35277 var z = v0.z + t * (v1.z - v0.z) + u * (v2.z - v0.z);
35278 return z
35279};
35280Triangle$1.longestSideLength = function longestSideLength (a, b, c) {
35281 var lenAB = a.distance(b);
35282 var lenBC = b.distance(c);
35283 var lenCA = c.distance(a);
35284 var maxLen = lenAB;
35285 if (lenBC > maxLen) { maxLen = lenBC; }
35286 if (lenCA > maxLen) { maxLen = lenCA; }
35287 return maxLen
35288};
35289Triangle$1.isAcute = function isAcute (a, b, c) {
35290 if (!Angle.isAcute(a, b, c)) { return false }
35291 if (!Angle.isAcute(b, c, a)) { return false }
35292 if (!Angle.isAcute(c, a, b)) { return false }
35293 return true
35294};
35295Triangle$1.circumcentre = function circumcentre (a, b, c) {
35296 var cx = c.x;
35297 var cy = c.y;
35298 var ax = a.x - cx;
35299 var ay = a.y - cy;
35300 var bx = b.x - cx;
35301 var by = b.y - cy;
35302 var denom = 2 * Triangle$1.det(ax, ay, bx, by);
35303 var numx = Triangle$1.det(ay, ax * ax + ay * ay, by, bx * bx + by * by);
35304 var numy = Triangle$1.det(ax, ax * ax + ay * ay, bx, bx * bx + by * by);
35305 var ccx = cx - numx / denom;
35306 var ccy = cy + numy / denom;
35307 return new Coordinate(ccx, ccy)
35308};
35309Triangle$1.perpendicularBisector = function perpendicularBisector (a, b) {
35310 var dx = b.x - a.x;
35311 var dy = b.y - a.y;
35312 var l1 = new HCoordinate(a.x + dx / 2.0, a.y + dy / 2.0, 1.0);
35313 var l2 = new HCoordinate(a.x - dy + dx / 2.0, a.y + dx + dy / 2.0, 1.0);
35314 return new HCoordinate(l1, l2)
35315};
35316Triangle$1.angleBisector = function angleBisector (a, b, c) {
35317 var len0 = b.distance(a);
35318 var len2 = b.distance(c);
35319 var frac = len0 / (len0 + len2);
35320 var dx = c.x - a.x;
35321 var dy = c.y - a.y;
35322 var splitPt = new Coordinate(a.x + frac * dx, a.y + frac * dy);
35323 return splitPt
35324};
35325Triangle$1.area3D = function area3D (a, b, c) {
35326 var ux = b.x - a.x;
35327 var uy = b.y - a.y;
35328 var uz = b.z - a.z;
35329 var vx = c.x - a.x;
35330 var vy = c.y - a.y;
35331 var vz = c.z - a.z;
35332 var crossx = uy * vz - uz * vy;
35333 var crossy = uz * vx - ux * vz;
35334 var crossz = ux * vy - uy * vx;
35335 var absSq = crossx * crossx + crossy * crossy + crossz * crossz;
35336 var area3D = Math.sqrt(absSq) / 2;
35337 return area3D
35338};
35339Triangle$1.centroid = function centroid (a, b, c) {
35340 var x = (a.x + b.x + c.x) / 3;
35341 var y = (a.y + b.y + c.y) / 3;
35342 return new Coordinate(x, y)
35343};
35344Triangle$1.inCentre = function inCentre (a, b, c) {
35345 var len0 = b.distance(c);
35346 var len1 = a.distance(c);
35347 var len2 = a.distance(b);
35348 var circum = len0 + len1 + len2;
35349 var inCentreX = (len0 * a.x + len1 * b.x + len2 * c.x) / circum;
35350 var inCentreY = (len0 * a.y + len1 * b.y + len2 * c.y) / circum;
35351 return new Coordinate(inCentreX, inCentreY)
35352};
35353
35354var OffsetCurveSetBuilder = function OffsetCurveSetBuilder () {
35355 this._inputGeom = null;
35356 this._distance = null;
35357 this._curveBuilder = null;
35358 this._curveList = new ArrayList();
35359 var inputGeom = arguments[0];
35360 var distance = arguments[1];
35361 var curveBuilder = arguments[2];
35362 this._inputGeom = inputGeom;
35363 this._distance = distance;
35364 this._curveBuilder = curveBuilder;
35365};
35366OffsetCurveSetBuilder.prototype.addPoint = function addPoint (p) {
35367 if (this._distance <= 0.0) { return null }
35368 var coord = p.getCoordinates();
35369 var curve = this._curveBuilder.getLineCurve(coord, this._distance);
35370 this.addCurve(curve, Location.EXTERIOR, Location.INTERIOR);
35371};
35372OffsetCurveSetBuilder.prototype.addPolygon = function addPolygon (p) {
35373 var this$1 = this;
35374
35375 var offsetDistance = this._distance;
35376 var offsetSide = Position.LEFT;
35377 if (this._distance < 0.0) {
35378 offsetDistance = -this._distance;
35379 offsetSide = Position.RIGHT;
35380 }
35381 var shell = p.getExteriorRing();
35382 var shellCoord = CoordinateArrays.removeRepeatedPoints(shell.getCoordinates());
35383 if (this._distance < 0.0 && this.isErodedCompletely(shell, this._distance)) { return null }
35384 if (this._distance <= 0.0 && shellCoord.length < 3) { return null }
35385 this.addPolygonRing(shellCoord, offsetDistance, offsetSide, Location.EXTERIOR, Location.INTERIOR);
35386 for (var i = 0; i < p.getNumInteriorRing(); i++) {
35387 var hole = p.getInteriorRingN(i);
35388 var holeCoord = CoordinateArrays.removeRepeatedPoints(hole.getCoordinates());
35389 if (this$1._distance > 0.0 && this$1.isErodedCompletely(hole, -this$1._distance)) { continue }
35390 this$1.addPolygonRing(holeCoord, offsetDistance, Position.opposite(offsetSide), Location.INTERIOR, Location.EXTERIOR);
35391 }
35392};
35393OffsetCurveSetBuilder.prototype.isTriangleErodedCompletely = function isTriangleErodedCompletely (triangleCoord, bufferDistance) {
35394 var tri = new Triangle$1(triangleCoord[0], triangleCoord[1], triangleCoord[2]);
35395 var inCentre = tri.inCentre();
35396 var distToCentre = CGAlgorithms.distancePointLine(inCentre, tri.p0, tri.p1);
35397 return distToCentre < Math.abs(bufferDistance)
35398};
35399OffsetCurveSetBuilder.prototype.addLineString = function addLineString (line) {
35400 if (this._distance <= 0.0 && !this._curveBuilder.getBufferParameters().isSingleSided()) { return null }
35401 var coord = CoordinateArrays.removeRepeatedPoints(line.getCoordinates());
35402 var curve = this._curveBuilder.getLineCurve(coord, this._distance);
35403 this.addCurve(curve, Location.EXTERIOR, Location.INTERIOR);
35404};
35405OffsetCurveSetBuilder.prototype.addCurve = function addCurve (coord, leftLoc, rightLoc) {
35406 if (coord === null || coord.length < 2) { return null }
35407 var e = new NodedSegmentString(coord, new Label(0, Location.BOUNDARY, leftLoc, rightLoc));
35408 this._curveList.add(e);
35409};
35410OffsetCurveSetBuilder.prototype.getCurves = function getCurves () {
35411 this.add(this._inputGeom);
35412 return this._curveList
35413};
35414OffsetCurveSetBuilder.prototype.addPolygonRing = function addPolygonRing (coord, offsetDistance, side, cwLeftLoc, cwRightLoc) {
35415 if (offsetDistance === 0.0 && coord.length < LinearRing.MINIMUM_VALID_SIZE) { return null }
35416 var leftLoc = cwLeftLoc;
35417 var rightLoc = cwRightLoc;
35418 if (coord.length >= LinearRing.MINIMUM_VALID_SIZE && CGAlgorithms.isCCW(coord)) {
35419 leftLoc = cwRightLoc;
35420 rightLoc = cwLeftLoc;
35421 side = Position.opposite(side);
35422 }
35423 var curve = this._curveBuilder.getRingCurve(coord, side, offsetDistance);
35424 this.addCurve(curve, leftLoc, rightLoc);
35425};
35426OffsetCurveSetBuilder.prototype.add = function add (g) {
35427 if (g.isEmpty()) { return null }
35428 if (g instanceof Polygon) { this.addPolygon(g); }
35429 else if (g instanceof LineString$1) { this.addLineString(g); }
35430 else if (g instanceof Point) { this.addPoint(g); }
35431 else if (g instanceof MultiPoint) { this.addCollection(g); }
35432 else if (g instanceof MultiLineString) { this.addCollection(g); }
35433 else if (g instanceof MultiPolygon) { this.addCollection(g); }
35434 else if (g instanceof GeometryCollection) { this.addCollection(g); }
35435 // else throw new UnsupportedOperationException(g.getClass().getName())
35436};
35437OffsetCurveSetBuilder.prototype.isErodedCompletely = function isErodedCompletely (ring, bufferDistance) {
35438 var ringCoord = ring.getCoordinates();
35439 // const minDiam = 0.0
35440 if (ringCoord.length < 4) { return bufferDistance < 0 }
35441 if (ringCoord.length === 4) { return this.isTriangleErodedCompletely(ringCoord, bufferDistance) }
35442 var env = ring.getEnvelopeInternal();
35443 var envMinDimension = Math.min(env.getHeight(), env.getWidth());
35444 if (bufferDistance < 0.0 && 2 * Math.abs(bufferDistance) > envMinDimension) { return true }
35445 return false
35446};
35447OffsetCurveSetBuilder.prototype.addCollection = function addCollection (gc) {
35448 var this$1 = this;
35449
35450 for (var i = 0; i < gc.getNumGeometries(); i++) {
35451 var g = gc.getGeometryN(i);
35452 this$1.add(g);
35453 }
35454};
35455OffsetCurveSetBuilder.prototype.interfaces_ = function interfaces_ () {
35456 return []
35457};
35458OffsetCurveSetBuilder.prototype.getClass = function getClass () {
35459 return OffsetCurveSetBuilder
35460};
35461
35462var PointOnGeometryLocator = function PointOnGeometryLocator () {};
35463
35464PointOnGeometryLocator.prototype.locate = function locate (p) {};
35465PointOnGeometryLocator.prototype.interfaces_ = function interfaces_ () {
35466 return []
35467};
35468PointOnGeometryLocator.prototype.getClass = function getClass () {
35469 return PointOnGeometryLocator
35470};
35471
35472var GeometryCollectionIterator = function GeometryCollectionIterator () {
35473 this._parent = null;
35474 this._atStart = null;
35475 this._max = null;
35476 this._index = null;
35477 this._subcollectionIterator = null;
35478 var parent = arguments[0];
35479 this._parent = parent;
35480 this._atStart = true;
35481 this._index = 0;
35482 this._max = parent.getNumGeometries();
35483};
35484GeometryCollectionIterator.prototype.next = function next () {
35485 if (this._atStart) {
35486 this._atStart = false;
35487 if (GeometryCollectionIterator.isAtomic(this._parent)) { this._index++; }
35488 return this._parent
35489 }
35490 if (this._subcollectionIterator !== null) {
35491 if (this._subcollectionIterator.hasNext()) {
35492 return this._subcollectionIterator.next()
35493 } else {
35494 this._subcollectionIterator = null;
35495 }
35496 }
35497 if (this._index >= this._max) {
35498 throw new NoSuchElementException()
35499 }
35500 var obj = this._parent.getGeometryN(this._index++);
35501 if (obj instanceof GeometryCollection) {
35502 this._subcollectionIterator = new GeometryCollectionIterator(obj);
35503 return this._subcollectionIterator.next()
35504 }
35505 return obj
35506};
35507GeometryCollectionIterator.prototype.remove = function remove () {
35508 throw new Error(this.getClass().getName())
35509};
35510GeometryCollectionIterator.prototype.hasNext = function hasNext () {
35511 if (this._atStart) {
35512 return true
35513 }
35514 if (this._subcollectionIterator !== null) {
35515 if (this._subcollectionIterator.hasNext()) {
35516 return true
35517 }
35518 this._subcollectionIterator = null;
35519 }
35520 if (this._index >= this._max) {
35521 return false
35522 }
35523 return true
35524};
35525GeometryCollectionIterator.prototype.interfaces_ = function interfaces_ () {
35526 return [Iterator]
35527};
35528GeometryCollectionIterator.prototype.getClass = function getClass () {
35529 return GeometryCollectionIterator
35530};
35531GeometryCollectionIterator.isAtomic = function isAtomic (geom) {
35532 return !(geom instanceof GeometryCollection)
35533};
35534
35535var SimplePointInAreaLocator = function SimplePointInAreaLocator () {
35536 this._geom = null;
35537 var geom = arguments[0];
35538 this._geom = geom;
35539};
35540SimplePointInAreaLocator.prototype.locate = function locate (p) {
35541 return SimplePointInAreaLocator.locate(p, this._geom)
35542};
35543SimplePointInAreaLocator.prototype.interfaces_ = function interfaces_ () {
35544 return [PointOnGeometryLocator]
35545};
35546SimplePointInAreaLocator.prototype.getClass = function getClass () {
35547 return SimplePointInAreaLocator
35548};
35549SimplePointInAreaLocator.isPointInRing = function isPointInRing (p, ring) {
35550 if (!ring.getEnvelopeInternal().intersects(p)) { return false }
35551 return CGAlgorithms.isPointInRing(p, ring.getCoordinates())
35552};
35553SimplePointInAreaLocator.containsPointInPolygon = function containsPointInPolygon (p, poly) {
35554 if (poly.isEmpty()) { return false }
35555 var shell = poly.getExteriorRing();
35556 if (!SimplePointInAreaLocator.isPointInRing(p, shell)) { return false }
35557 for (var i = 0; i < poly.getNumInteriorRing(); i++) {
35558 var hole = poly.getInteriorRingN(i);
35559 if (SimplePointInAreaLocator.isPointInRing(p, hole)) { return false }
35560 }
35561 return true
35562};
35563SimplePointInAreaLocator.containsPoint = function containsPoint (p, geom) {
35564 if (geom instanceof Polygon) {
35565 return SimplePointInAreaLocator.containsPointInPolygon(p, geom)
35566 } else if (geom instanceof GeometryCollection) {
35567 var geomi = new GeometryCollectionIterator(geom);
35568 while (geomi.hasNext()) {
35569 var g2 = geomi.next();
35570 if (g2 !== geom) { if (SimplePointInAreaLocator.containsPoint(p, g2)) { return true } }
35571 }
35572 }
35573 return false
35574};
35575SimplePointInAreaLocator.locate = function locate (p, geom) {
35576 if (geom.isEmpty()) { return Location.EXTERIOR }
35577 if (SimplePointInAreaLocator.containsPoint(p, geom)) { return Location.INTERIOR }
35578 return Location.EXTERIOR
35579};
35580
35581var EdgeEndStar = function EdgeEndStar () {
35582 this._edgeMap = new TreeMap();
35583 this._edgeList = null;
35584 this._ptInAreaLocation = [Location.NONE, Location.NONE];
35585};
35586EdgeEndStar.prototype.getNextCW = function getNextCW (ee) {
35587 this.getEdges();
35588 var i = this._edgeList.indexOf(ee);
35589 var iNextCW = i - 1;
35590 if (i === 0) { iNextCW = this._edgeList.size() - 1; }
35591 return this._edgeList.get(iNextCW)
35592};
35593EdgeEndStar.prototype.propagateSideLabels = function propagateSideLabels (geomIndex) {
35594 var startLoc = Location.NONE;
35595 for (var it = this.iterator(); it.hasNext();) {
35596 var e = it.next();
35597 var label = e.getLabel();
35598 if (label.isArea(geomIndex) && label.getLocation(geomIndex, Position.LEFT) !== Location.NONE) { startLoc = label.getLocation(geomIndex, Position.LEFT); }
35599 }
35600 if (startLoc === Location.NONE) { return null }
35601 var currLoc = startLoc;
35602 for (var it$1 = this.iterator(); it$1.hasNext();) {
35603 var e$1 = it$1.next();
35604 var label$1 = e$1.getLabel();
35605 if (label$1.getLocation(geomIndex, Position.ON) === Location.NONE) { label$1.setLocation(geomIndex, Position.ON, currLoc); }
35606 if (label$1.isArea(geomIndex)) {
35607 var leftLoc = label$1.getLocation(geomIndex, Position.LEFT);
35608 var rightLoc = label$1.getLocation(geomIndex, Position.RIGHT);
35609 if (rightLoc !== Location.NONE) {
35610 if (rightLoc !== currLoc) { throw new TopologyException('side location conflict', e$1.getCoordinate()) }
35611 if (leftLoc === Location.NONE) {
35612 Assert.shouldNeverReachHere('found single null side (at ' + e$1.getCoordinate() + ')');
35613 }
35614 currLoc = leftLoc;
35615 } else {
35616 Assert.isTrue(label$1.getLocation(geomIndex, Position.LEFT) === Location.NONE, 'found single null side');
35617 label$1.setLocation(geomIndex, Position.RIGHT, currLoc);
35618 label$1.setLocation(geomIndex, Position.LEFT, currLoc);
35619 }
35620 }
35621 }
35622};
35623EdgeEndStar.prototype.getCoordinate = function getCoordinate () {
35624 var it = this.iterator();
35625 if (!it.hasNext()) { return null }
35626 var e = it.next();
35627 return e.getCoordinate()
35628};
35629EdgeEndStar.prototype.print = function print (out) {
35630 System.out.println('EdgeEndStar: ' + this.getCoordinate());
35631 for (var it = this.iterator(); it.hasNext();) {
35632 var e = it.next();
35633 e.print(out);
35634 }
35635};
35636EdgeEndStar.prototype.isAreaLabelsConsistent = function isAreaLabelsConsistent (geomGraph) {
35637 this.computeEdgeEndLabels(geomGraph.getBoundaryNodeRule());
35638 return this.checkAreaLabelsConsistent(0)
35639};
35640EdgeEndStar.prototype.checkAreaLabelsConsistent = function checkAreaLabelsConsistent (geomIndex) {
35641 var edges = this.getEdges();
35642 if (edges.size() <= 0) { return true }
35643 var lastEdgeIndex = edges.size() - 1;
35644 var startLabel = edges.get(lastEdgeIndex).getLabel();
35645 var startLoc = startLabel.getLocation(geomIndex, Position.LEFT);
35646 Assert.isTrue(startLoc !== Location.NONE, 'Found unlabelled area edge');
35647 var currLoc = startLoc;
35648 for (var it = this.iterator(); it.hasNext();) {
35649 var e = it.next();
35650 var label = e.getLabel();
35651 Assert.isTrue(label.isArea(geomIndex), 'Found non-area edge');
35652 var leftLoc = label.getLocation(geomIndex, Position.LEFT);
35653 var rightLoc = label.getLocation(geomIndex, Position.RIGHT);
35654 if (leftLoc === rightLoc) {
35655 return false
35656 }
35657 if (rightLoc !== currLoc) {
35658 return false
35659 }
35660 currLoc = leftLoc;
35661 }
35662 return true
35663};
35664EdgeEndStar.prototype.findIndex = function findIndex (eSearch) {
35665 var this$1 = this;
35666
35667 this.iterator();
35668 for (var i = 0; i < this._edgeList.size(); i++) {
35669 var e = this$1._edgeList.get(i);
35670 if (e === eSearch) { return i }
35671 }
35672 return -1
35673};
35674EdgeEndStar.prototype.iterator = function iterator () {
35675 return this.getEdges().iterator()
35676};
35677EdgeEndStar.prototype.getEdges = function getEdges () {
35678 if (this._edgeList === null) {
35679 this._edgeList = new ArrayList(this._edgeMap.values());
35680 }
35681 return this._edgeList
35682};
35683EdgeEndStar.prototype.getLocation = function getLocation (geomIndex, p, geom) {
35684 if (this._ptInAreaLocation[geomIndex] === Location.NONE) {
35685 this._ptInAreaLocation[geomIndex] = SimplePointInAreaLocator.locate(p, geom[geomIndex].getGeometry());
35686 }
35687 return this._ptInAreaLocation[geomIndex]
35688};
35689EdgeEndStar.prototype.toString = function toString () {
35690 var buf = new StringBuffer();
35691 buf.append('EdgeEndStar: ' + this.getCoordinate());
35692 buf.append('\n');
35693 for (var it = this.iterator(); it.hasNext();) {
35694 var e = it.next();
35695 buf.append(e);
35696 buf.append('\n');
35697 }
35698 return buf.toString()
35699};
35700EdgeEndStar.prototype.computeEdgeEndLabels = function computeEdgeEndLabels (boundaryNodeRule) {
35701 for (var it = this.iterator(); it.hasNext();) {
35702 var ee = it.next();
35703 ee.computeLabel(boundaryNodeRule);
35704 }
35705};
35706EdgeEndStar.prototype.computeLabelling = function computeLabelling (geomGraph) {
35707 var this$1 = this;
35708
35709 this.computeEdgeEndLabels(geomGraph[0].getBoundaryNodeRule());
35710 this.propagateSideLabels(0);
35711 this.propagateSideLabels(1);
35712 var hasDimensionalCollapseEdge = [false, false];
35713 for (var it = this.iterator(); it.hasNext();) {
35714 var e = it.next();
35715 var label = e.getLabel();
35716 for (var geomi = 0; geomi < 2; geomi++) {
35717 if (label.isLine(geomi) && label.getLocation(geomi) === Location.BOUNDARY) { hasDimensionalCollapseEdge[geomi] = true; }
35718 }
35719 }
35720 for (var it$1 = this.iterator(); it$1.hasNext();) {
35721 var e$1 = it$1.next();
35722 var label$1 = e$1.getLabel();
35723 for (var geomi$1 = 0; geomi$1 < 2; geomi$1++) {
35724 if (label$1.isAnyNull(geomi$1)) {
35725 var loc = Location.NONE;
35726 if (hasDimensionalCollapseEdge[geomi$1]) {
35727 loc = Location.EXTERIOR;
35728 } else {
35729 var p = e$1.getCoordinate();
35730 loc = this$1.getLocation(geomi$1, p, geomGraph);
35731 }
35732 label$1.setAllLocationsIfNull(geomi$1, loc);
35733 }
35734 }
35735 }
35736};
35737EdgeEndStar.prototype.getDegree = function getDegree () {
35738 return this._edgeMap.size()
35739};
35740EdgeEndStar.prototype.insertEdgeEnd = function insertEdgeEnd (e, obj) {
35741 this._edgeMap.put(e, obj);
35742 this._edgeList = null;
35743};
35744EdgeEndStar.prototype.interfaces_ = function interfaces_ () {
35745 return []
35746};
35747EdgeEndStar.prototype.getClass = function getClass () {
35748 return EdgeEndStar
35749};
35750
35751var DirectedEdgeStar = (function (EdgeEndStar$$1) {
35752 function DirectedEdgeStar () {
35753 EdgeEndStar$$1.call(this);
35754 this._resultAreaEdgeList = null;
35755 this._label = null;
35756 this._SCANNING_FOR_INCOMING = 1;
35757 this._LINKING_TO_OUTGOING = 2;
35758 }
35759
35760 if ( EdgeEndStar$$1 ) DirectedEdgeStar.__proto__ = EdgeEndStar$$1;
35761 DirectedEdgeStar.prototype = Object.create( EdgeEndStar$$1 && EdgeEndStar$$1.prototype );
35762 DirectedEdgeStar.prototype.constructor = DirectedEdgeStar;
35763 DirectedEdgeStar.prototype.linkResultDirectedEdges = function linkResultDirectedEdges () {
35764 var this$1 = this;
35765
35766 this.getResultAreaEdges();
35767 var firstOut = null;
35768 var incoming = null;
35769 var state = this._SCANNING_FOR_INCOMING;
35770 for (var i = 0; i < this._resultAreaEdgeList.size(); i++) {
35771 var nextOut = this$1._resultAreaEdgeList.get(i);
35772 var nextIn = nextOut.getSym();
35773 if (!nextOut.getLabel().isArea()) { continue }
35774 if (firstOut === null && nextOut.isInResult()) { firstOut = nextOut; }
35775 switch (state) {
35776 case this$1._SCANNING_FOR_INCOMING:
35777 if (!nextIn.isInResult()) { continue }
35778 incoming = nextIn;
35779 state = this$1._LINKING_TO_OUTGOING;
35780 break
35781 case this$1._LINKING_TO_OUTGOING:
35782 if (!nextOut.isInResult()) { continue }
35783 incoming.setNext(nextOut);
35784 state = this$1._SCANNING_FOR_INCOMING;
35785 break
35786 default:
35787 }
35788 }
35789 if (state === this._LINKING_TO_OUTGOING) {
35790 if (firstOut === null) { throw new TopologyException('no outgoing dirEdge found', this.getCoordinate()) }
35791 Assert.isTrue(firstOut.isInResult(), 'unable to link last incoming dirEdge');
35792 incoming.setNext(firstOut);
35793 }
35794 };
35795 DirectedEdgeStar.prototype.insert = function insert (ee) {
35796 var de = ee;
35797 this.insertEdgeEnd(de, de);
35798 };
35799 DirectedEdgeStar.prototype.getRightmostEdge = function getRightmostEdge () {
35800 var edges = this.getEdges();
35801 var size = edges.size();
35802 if (size < 1) { return null }
35803 var de0 = edges.get(0);
35804 if (size === 1) { return de0 }
35805 var deLast = edges.get(size - 1);
35806 var quad0 = de0.getQuadrant();
35807 var quad1 = deLast.getQuadrant();
35808 if (Quadrant.isNorthern(quad0) && Quadrant.isNorthern(quad1)) { return de0; } else if (!Quadrant.isNorthern(quad0) && !Quadrant.isNorthern(quad1)) { return deLast; } else {
35809 // const nonHorizontalEdge = null
35810 if (de0.getDy() !== 0) { return de0; } else if (deLast.getDy() !== 0) { return deLast }
35811 }
35812 Assert.shouldNeverReachHere('found two horizontal edges incident on node');
35813 return null
35814 };
35815 DirectedEdgeStar.prototype.print = function print (out) {
35816 System.out.println('DirectedEdgeStar: ' + this.getCoordinate());
35817 for (var it = this.iterator(); it.hasNext();) {
35818 var de = it.next();
35819 out.print('out ');
35820 de.print(out);
35821 out.println();
35822 out.print('in ');
35823 de.getSym().print(out);
35824 out.println();
35825 }
35826 };
35827 DirectedEdgeStar.prototype.getResultAreaEdges = function getResultAreaEdges () {
35828 var this$1 = this;
35829
35830 if (this._resultAreaEdgeList !== null) { return this._resultAreaEdgeList }
35831 this._resultAreaEdgeList = new ArrayList();
35832 for (var it = this.iterator(); it.hasNext();) {
35833 var de = it.next();
35834 if (de.isInResult() || de.getSym().isInResult()) { this$1._resultAreaEdgeList.add(de); }
35835 }
35836 return this._resultAreaEdgeList
35837 };
35838 DirectedEdgeStar.prototype.updateLabelling = function updateLabelling (nodeLabel) {
35839 for (var it = this.iterator(); it.hasNext();) {
35840 var de = it.next();
35841 var label = de.getLabel();
35842 label.setAllLocationsIfNull(0, nodeLabel.getLocation(0));
35843 label.setAllLocationsIfNull(1, nodeLabel.getLocation(1));
35844 }
35845 };
35846 DirectedEdgeStar.prototype.linkAllDirectedEdges = function linkAllDirectedEdges () {
35847 var this$1 = this;
35848
35849 this.getEdges();
35850 var prevOut = null;
35851 var firstIn = null;
35852 for (var i = this._edgeList.size() - 1; i >= 0; i--) {
35853 var nextOut = this$1._edgeList.get(i);
35854 var nextIn = nextOut.getSym();
35855 if (firstIn === null) { firstIn = nextIn; }
35856 if (prevOut !== null) { nextIn.setNext(prevOut); }
35857 prevOut = nextOut;
35858 }
35859 firstIn.setNext(prevOut);
35860 };
35861 DirectedEdgeStar.prototype.computeDepths = function computeDepths () {
35862 var this$1 = this;
35863
35864 if (arguments.length === 1) {
35865 var de = arguments[0];
35866 var edgeIndex = this.findIndex(de);
35867 // const label = de.getLabel()
35868 var startDepth = de.getDepth(Position.LEFT);
35869 var targetLastDepth = de.getDepth(Position.RIGHT);
35870 var nextDepth = this.computeDepths(edgeIndex + 1, this._edgeList.size(), startDepth);
35871 var lastDepth = this.computeDepths(0, edgeIndex, nextDepth);
35872 if (lastDepth !== targetLastDepth) { throw new TopologyException('depth mismatch at ' + de.getCoordinate()) }
35873 } else if (arguments.length === 3) {
35874 var startIndex = arguments[0];
35875 var endIndex = arguments[1];
35876 var startDepth$1 = arguments[2];
35877 var currDepth = startDepth$1;
35878 for (var i = startIndex; i < endIndex; i++) {
35879 var nextDe = this$1._edgeList.get(i);
35880 // const label = nextDe.getLabel()
35881 nextDe.setEdgeDepths(Position.RIGHT, currDepth);
35882 currDepth = nextDe.getDepth(Position.LEFT);
35883 }
35884 return currDepth
35885 }
35886 };
35887 DirectedEdgeStar.prototype.mergeSymLabels = function mergeSymLabels () {
35888 for (var it = this.iterator(); it.hasNext();) {
35889 var de = it.next();
35890 var label = de.getLabel();
35891 label.merge(de.getSym().getLabel());
35892 }
35893 };
35894 DirectedEdgeStar.prototype.linkMinimalDirectedEdges = function linkMinimalDirectedEdges (er) {
35895 var this$1 = this;
35896
35897 var firstOut = null;
35898 var incoming = null;
35899 var state = this._SCANNING_FOR_INCOMING;
35900 for (var i = this._resultAreaEdgeList.size() - 1; i >= 0; i--) {
35901 var nextOut = this$1._resultAreaEdgeList.get(i);
35902 var nextIn = nextOut.getSym();
35903 if (firstOut === null && nextOut.getEdgeRing() === er) { firstOut = nextOut; }
35904 switch (state) {
35905 case this$1._SCANNING_FOR_INCOMING:
35906 if (nextIn.getEdgeRing() !== er) { continue }
35907 incoming = nextIn;
35908 state = this$1._LINKING_TO_OUTGOING;
35909 break
35910 case this$1._LINKING_TO_OUTGOING:
35911 if (nextOut.getEdgeRing() !== er) { continue }
35912 incoming.setNextMin(nextOut);
35913 state = this$1._SCANNING_FOR_INCOMING;
35914 break
35915 default:
35916 }
35917 }
35918 if (state === this._LINKING_TO_OUTGOING) {
35919 Assert.isTrue(firstOut !== null, 'found null for first outgoing dirEdge');
35920 Assert.isTrue(firstOut.getEdgeRing() === er, 'unable to link last incoming dirEdge');
35921 incoming.setNextMin(firstOut);
35922 }
35923 };
35924 DirectedEdgeStar.prototype.getOutgoingDegree = function getOutgoingDegree () {
35925 if (arguments.length === 0) {
35926 var degree = 0;
35927 for (var it = this.iterator(); it.hasNext();) {
35928 var de = it.next();
35929 if (de.isInResult()) { degree++; }
35930 }
35931 return degree
35932 } else if (arguments.length === 1) {
35933 var er = arguments[0];
35934 var degree$1 = 0;
35935 for (var it$1 = this.iterator(); it$1.hasNext();) {
35936 var de$1 = it$1.next();
35937 if (de$1.getEdgeRing() === er) { degree$1++; }
35938 }
35939 return degree$1
35940 }
35941 };
35942 DirectedEdgeStar.prototype.getLabel = function getLabel () {
35943 return this._label
35944 };
35945 DirectedEdgeStar.prototype.findCoveredLineEdges = function findCoveredLineEdges () {
35946 var startLoc = Location.NONE;
35947 for (var it = this.iterator(); it.hasNext();) {
35948 var nextOut = it.next();
35949 var nextIn = nextOut.getSym();
35950 if (!nextOut.isLineEdge()) {
35951 if (nextOut.isInResult()) {
35952 startLoc = Location.INTERIOR;
35953 break
35954 }
35955 if (nextIn.isInResult()) {
35956 startLoc = Location.EXTERIOR;
35957 break
35958 }
35959 }
35960 }
35961 if (startLoc === Location.NONE) { return null }
35962 var currLoc = startLoc;
35963 for (var it$1 = this.iterator(); it$1.hasNext();) {
35964 var nextOut$1 = it$1.next();
35965 var nextIn$1 = nextOut$1.getSym();
35966 if (nextOut$1.isLineEdge()) {
35967 nextOut$1.getEdge().setCovered(currLoc === Location.INTERIOR);
35968 } else {
35969 if (nextOut$1.isInResult()) { currLoc = Location.EXTERIOR; }
35970 if (nextIn$1.isInResult()) { currLoc = Location.INTERIOR; }
35971 }
35972 }
35973 };
35974 DirectedEdgeStar.prototype.computeLabelling = function computeLabelling (geom) {
35975 var this$1 = this;
35976
35977 EdgeEndStar$$1.prototype.computeLabelling.call(this, geom);
35978 this._label = new Label(Location.NONE);
35979 for (var it = this.iterator(); it.hasNext();) {
35980 var ee = it.next();
35981 var e = ee.getEdge();
35982 var eLabel = e.getLabel();
35983 for (var i = 0; i < 2; i++) {
35984 var eLoc = eLabel.getLocation(i);
35985 if (eLoc === Location.INTERIOR || eLoc === Location.BOUNDARY) { this$1._label.setLocation(i, Location.INTERIOR); }
35986 }
35987 }
35988 };
35989 DirectedEdgeStar.prototype.interfaces_ = function interfaces_ () {
35990 return []
35991 };
35992 DirectedEdgeStar.prototype.getClass = function getClass () {
35993 return DirectedEdgeStar
35994 };
35995
35996 return DirectedEdgeStar;
35997}(EdgeEndStar));
35998
35999var OverlayNodeFactory = (function (NodeFactory$$1) {
36000 function OverlayNodeFactory () {
36001 NodeFactory$$1.apply(this, arguments);
36002 }
36003
36004 if ( NodeFactory$$1 ) OverlayNodeFactory.__proto__ = NodeFactory$$1;
36005 OverlayNodeFactory.prototype = Object.create( NodeFactory$$1 && NodeFactory$$1.prototype );
36006 OverlayNodeFactory.prototype.constructor = OverlayNodeFactory;
36007
36008 OverlayNodeFactory.prototype.createNode = function createNode (coord) {
36009 return new Node$2(coord, new DirectedEdgeStar())
36010 };
36011 OverlayNodeFactory.prototype.interfaces_ = function interfaces_ () {
36012 return []
36013 };
36014 OverlayNodeFactory.prototype.getClass = function getClass () {
36015 return OverlayNodeFactory
36016 };
36017
36018 return OverlayNodeFactory;
36019}(NodeFactory));
36020
36021var OrientedCoordinateArray = function OrientedCoordinateArray () {
36022 this._pts = null;
36023 this._orientation = null;
36024 var pts = arguments[0];
36025 this._pts = pts;
36026 this._orientation = OrientedCoordinateArray.orientation(pts);
36027};
36028OrientedCoordinateArray.prototype.compareTo = function compareTo (o1) {
36029 var oca = o1;
36030 var comp = OrientedCoordinateArray.compareOriented(this._pts, this._orientation, oca._pts, oca._orientation);
36031 return comp
36032};
36033OrientedCoordinateArray.prototype.interfaces_ = function interfaces_ () {
36034 return [Comparable]
36035};
36036OrientedCoordinateArray.prototype.getClass = function getClass () {
36037 return OrientedCoordinateArray
36038};
36039OrientedCoordinateArray.orientation = function orientation (pts) {
36040 return CoordinateArrays.increasingDirection(pts) === 1
36041};
36042OrientedCoordinateArray.compareOriented = function compareOriented (pts1, orientation1, pts2, orientation2) {
36043 var dir1 = orientation1 ? 1 : -1;
36044 var dir2 = orientation2 ? 1 : -1;
36045 var limit1 = orientation1 ? pts1.length : -1;
36046 var limit2 = orientation2 ? pts2.length : -1;
36047 var i1 = orientation1 ? 0 : pts1.length - 1;
36048 var i2 = orientation2 ? 0 : pts2.length - 1;
36049 // const comp = 0
36050 while (true) {
36051 var compPt = pts1[i1].compareTo(pts2[i2]);
36052 if (compPt !== 0) { return compPt }
36053 i1 += dir1;
36054 i2 += dir2;
36055 var done1 = i1 === limit1;
36056 var done2 = i2 === limit2;
36057 if (done1 && !done2) { return -1 }
36058 if (!done1 && done2) { return 1 }
36059 if (done1 && done2) { return 0 }
36060 }
36061};
36062
36063var EdgeList = function EdgeList () {
36064 this._edges = new ArrayList();
36065 this._ocaMap = new TreeMap();
36066};
36067EdgeList.prototype.print = function print (out) {
36068 var this$1 = this;
36069
36070 out.print('MULTILINESTRING ( ');
36071 for (var j = 0; j < this._edges.size(); j++) {
36072 var e = this$1._edges.get(j);
36073 if (j > 0) { out.print(','); }
36074 out.print('(');
36075 var pts = e.getCoordinates();
36076 for (var i = 0; i < pts.length; i++) {
36077 if (i > 0) { out.print(','); }
36078 out.print(pts[i].x + ' ' + pts[i].y);
36079 }
36080 out.println(')');
36081 }
36082 out.print(') ');
36083};
36084EdgeList.prototype.addAll = function addAll (edgeColl) {
36085 var this$1 = this;
36086
36087 for (var i = edgeColl.iterator(); i.hasNext();) {
36088 this$1.add(i.next());
36089 }
36090};
36091EdgeList.prototype.findEdgeIndex = function findEdgeIndex (e) {
36092 var this$1 = this;
36093
36094 for (var i = 0; i < this._edges.size(); i++) {
36095 if (this$1._edges.get(i).equals(e)) { return i }
36096 }
36097 return -1
36098};
36099EdgeList.prototype.iterator = function iterator () {
36100 return this._edges.iterator()
36101};
36102EdgeList.prototype.getEdges = function getEdges () {
36103 return this._edges
36104};
36105EdgeList.prototype.get = function get (i) {
36106 return this._edges.get(i)
36107};
36108EdgeList.prototype.findEqualEdge = function findEqualEdge (e) {
36109 var oca = new OrientedCoordinateArray(e.getCoordinates());
36110 var matchEdge = this._ocaMap.get(oca);
36111 return matchEdge
36112};
36113EdgeList.prototype.add = function add (e) {
36114 this._edges.add(e);
36115 var oca = new OrientedCoordinateArray(e.getCoordinates());
36116 this._ocaMap.put(oca, e);
36117};
36118EdgeList.prototype.interfaces_ = function interfaces_ () {
36119 return []
36120};
36121EdgeList.prototype.getClass = function getClass () {
36122 return EdgeList
36123};
36124
36125var SegmentIntersector = function SegmentIntersector () {};
36126
36127SegmentIntersector.prototype.processIntersections = function processIntersections (e0, segIndex0, e1, segIndex1) {};
36128SegmentIntersector.prototype.isDone = function isDone () {};
36129SegmentIntersector.prototype.interfaces_ = function interfaces_ () {
36130 return []
36131};
36132SegmentIntersector.prototype.getClass = function getClass () {
36133 return SegmentIntersector
36134};
36135
36136var IntersectionAdder = function IntersectionAdder () {
36137 this._hasIntersection = false;
36138 this._hasProper = false;
36139 this._hasProperInterior = false;
36140 this._hasInterior = false;
36141 this._properIntersectionPoint = null;
36142 this._li = null;
36143 this._isSelfIntersection = null;
36144 this.numIntersections = 0;
36145 this.numInteriorIntersections = 0;
36146 this.numProperIntersections = 0;
36147 this.numTests = 0;
36148 var li = arguments[0];
36149 this._li = li;
36150};
36151IntersectionAdder.prototype.isTrivialIntersection = function isTrivialIntersection (e0, segIndex0, e1, segIndex1) {
36152 if (e0 === e1) {
36153 if (this._li.getIntersectionNum() === 1) {
36154 if (IntersectionAdder.isAdjacentSegments(segIndex0, segIndex1)) { return true }
36155 if (e0.isClosed()) {
36156 var maxSegIndex = e0.size() - 1;
36157 if ((segIndex0 === 0 && segIndex1 === maxSegIndex) ||
36158 (segIndex1 === 0 && segIndex0 === maxSegIndex)) {
36159 return true
36160 }
36161 }
36162 }
36163 }
36164 return false
36165};
36166IntersectionAdder.prototype.getProperIntersectionPoint = function getProperIntersectionPoint () {
36167 return this._properIntersectionPoint
36168};
36169IntersectionAdder.prototype.hasProperInteriorIntersection = function hasProperInteriorIntersection () {
36170 return this._hasProperInterior
36171};
36172IntersectionAdder.prototype.getLineIntersector = function getLineIntersector () {
36173 return this._li
36174};
36175IntersectionAdder.prototype.hasProperIntersection = function hasProperIntersection () {
36176 return this._hasProper
36177};
36178IntersectionAdder.prototype.processIntersections = function processIntersections (e0, segIndex0, e1, segIndex1) {
36179 if (e0 === e1 && segIndex0 === segIndex1) { return null }
36180 this.numTests++;
36181 var p00 = e0.getCoordinates()[segIndex0];
36182 var p01 = e0.getCoordinates()[segIndex0 + 1];
36183 var p10 = e1.getCoordinates()[segIndex1];
36184 var p11 = e1.getCoordinates()[segIndex1 + 1];
36185 this._li.computeIntersection(p00, p01, p10, p11);
36186 if (this._li.hasIntersection()) {
36187 this.numIntersections++;
36188 if (this._li.isInteriorIntersection()) {
36189 this.numInteriorIntersections++;
36190 this._hasInterior = true;
36191 }
36192 if (!this.isTrivialIntersection(e0, segIndex0, e1, segIndex1)) {
36193 this._hasIntersection = true;
36194 e0.addIntersections(this._li, segIndex0, 0);
36195 e1.addIntersections(this._li, segIndex1, 1);
36196 if (this._li.isProper()) {
36197 this.numProperIntersections++;
36198 this._hasProper = true;
36199 this._hasProperInterior = true;
36200 }
36201 }
36202 }
36203};
36204IntersectionAdder.prototype.hasIntersection = function hasIntersection () {
36205 return this._hasIntersection
36206};
36207IntersectionAdder.prototype.isDone = function isDone () {
36208 return false
36209};
36210IntersectionAdder.prototype.hasInteriorIntersection = function hasInteriorIntersection () {
36211 return this._hasInterior
36212};
36213IntersectionAdder.prototype.interfaces_ = function interfaces_ () {
36214 return [SegmentIntersector]
36215};
36216IntersectionAdder.prototype.getClass = function getClass () {
36217 return IntersectionAdder
36218};
36219IntersectionAdder.isAdjacentSegments = function isAdjacentSegments (i1, i2) {
36220 return Math.abs(i1 - i2) === 1
36221};
36222
36223var EdgeIntersection = function EdgeIntersection () {
36224 this.coord = null;
36225 this.segmentIndex = null;
36226 this.dist = null;
36227 var coord = arguments[0];
36228 var segmentIndex = arguments[1];
36229 var dist = arguments[2];
36230 this.coord = new Coordinate(coord);
36231 this.segmentIndex = segmentIndex;
36232 this.dist = dist;
36233};
36234EdgeIntersection.prototype.getSegmentIndex = function getSegmentIndex () {
36235 return this.segmentIndex
36236};
36237EdgeIntersection.prototype.getCoordinate = function getCoordinate () {
36238 return this.coord
36239};
36240EdgeIntersection.prototype.print = function print (out) {
36241 out.print(this.coord);
36242 out.print(' seg # = ' + this.segmentIndex);
36243 out.println(' dist = ' + this.dist);
36244};
36245EdgeIntersection.prototype.compareTo = function compareTo (obj) {
36246 var other = obj;
36247 return this.compare(other.segmentIndex, other.dist)
36248};
36249EdgeIntersection.prototype.isEndPoint = function isEndPoint (maxSegmentIndex) {
36250 if (this.segmentIndex === 0 && this.dist === 0.0) { return true }
36251 if (this.segmentIndex === maxSegmentIndex) { return true }
36252 return false
36253};
36254EdgeIntersection.prototype.toString = function toString () {
36255 return this.coord + ' seg # = ' + this.segmentIndex + ' dist = ' + this.dist
36256};
36257EdgeIntersection.prototype.getDistance = function getDistance () {
36258 return this.dist
36259};
36260EdgeIntersection.prototype.compare = function compare (segmentIndex, dist) {
36261 if (this.segmentIndex < segmentIndex) { return -1 }
36262 if (this.segmentIndex > segmentIndex) { return 1 }
36263 if (this.dist < dist) { return -1 }
36264 if (this.dist > dist) { return 1 }
36265 return 0
36266};
36267EdgeIntersection.prototype.interfaces_ = function interfaces_ () {
36268 return [Comparable]
36269};
36270EdgeIntersection.prototype.getClass = function getClass () {
36271 return EdgeIntersection
36272};
36273
36274var EdgeIntersectionList = function EdgeIntersectionList () {
36275 this._nodeMap = new TreeMap();
36276 this.edge = null;
36277 var edge = arguments[0];
36278 this.edge = edge;
36279};
36280EdgeIntersectionList.prototype.print = function print (out) {
36281 out.println('Intersections:');
36282 for (var it = this.iterator(); it.hasNext();) {
36283 var ei = it.next();
36284 ei.print(out);
36285 }
36286};
36287EdgeIntersectionList.prototype.iterator = function iterator () {
36288 return this._nodeMap.values().iterator()
36289};
36290EdgeIntersectionList.prototype.addSplitEdges = function addSplitEdges (edgeList) {
36291 var this$1 = this;
36292
36293 this.addEndpoints();
36294 var it = this.iterator();
36295 var eiPrev = it.next();
36296 while (it.hasNext()) {
36297 var ei = it.next();
36298 var newEdge = this$1.createSplitEdge(eiPrev, ei);
36299 edgeList.add(newEdge);
36300 eiPrev = ei;
36301 }
36302};
36303EdgeIntersectionList.prototype.addEndpoints = function addEndpoints () {
36304 var maxSegIndex = this.edge.pts.length - 1;
36305 this.add(this.edge.pts[0], 0, 0.0);
36306 this.add(this.edge.pts[maxSegIndex], maxSegIndex, 0.0);
36307};
36308EdgeIntersectionList.prototype.createSplitEdge = function createSplitEdge (ei0, ei1) {
36309 var this$1 = this;
36310
36311 var npts = ei1.segmentIndex - ei0.segmentIndex + 2;
36312 var lastSegStartPt = this.edge.pts[ei1.segmentIndex];
36313 var useIntPt1 = ei1.dist > 0.0 || !ei1.coord.equals2D(lastSegStartPt);
36314 if (!useIntPt1) {
36315 npts--;
36316 }
36317 var pts = new Array(npts).fill(null);
36318 var ipt = 0;
36319 pts[ipt++] = new Coordinate(ei0.coord);
36320 for (var i = ei0.segmentIndex + 1; i <= ei1.segmentIndex; i++) {
36321 pts[ipt++] = this$1.edge.pts[i];
36322 }
36323 if (useIntPt1) { pts[ipt] = ei1.coord; }
36324 return new Edge$1(pts, new Label(this.edge._label))
36325};
36326EdgeIntersectionList.prototype.add = function add (intPt, segmentIndex, dist) {
36327 var eiNew = new EdgeIntersection(intPt, segmentIndex, dist);
36328 var ei = this._nodeMap.get(eiNew);
36329 if (ei !== null) {
36330 return ei
36331 }
36332 this._nodeMap.put(eiNew, eiNew);
36333 return eiNew
36334};
36335EdgeIntersectionList.prototype.isIntersection = function isIntersection (pt) {
36336 for (var it = this.iterator(); it.hasNext();) {
36337 var ei = it.next();
36338 if (ei.coord.equals(pt)) { return true }
36339 }
36340 return false
36341};
36342EdgeIntersectionList.prototype.interfaces_ = function interfaces_ () {
36343 return []
36344};
36345EdgeIntersectionList.prototype.getClass = function getClass () {
36346 return EdgeIntersectionList
36347};
36348
36349var MonotoneChainIndexer = function MonotoneChainIndexer () {};
36350
36351MonotoneChainIndexer.prototype.getChainStartIndices = function getChainStartIndices (pts) {
36352 var this$1 = this;
36353
36354 var start = 0;
36355 var startIndexList = new ArrayList();
36356 startIndexList.add(new Integer(start));
36357 do {
36358 var last = this$1.findChainEnd(pts, start);
36359 startIndexList.add(new Integer(last));
36360 start = last;
36361 } while (start < pts.length - 1)
36362 var startIndex = MonotoneChainIndexer.toIntArray(startIndexList);
36363 return startIndex
36364};
36365MonotoneChainIndexer.prototype.findChainEnd = function findChainEnd (pts, start) {
36366 var chainQuad = Quadrant.quadrant(pts[start], pts[start + 1]);
36367 var last = start + 1;
36368 while (last < pts.length) {
36369 var quad = Quadrant.quadrant(pts[last - 1], pts[last]);
36370 if (quad !== chainQuad) { break }
36371 last++;
36372 }
36373 return last - 1
36374};
36375MonotoneChainIndexer.prototype.interfaces_ = function interfaces_ () {
36376 return []
36377};
36378MonotoneChainIndexer.prototype.getClass = function getClass () {
36379 return MonotoneChainIndexer
36380};
36381MonotoneChainIndexer.toIntArray = function toIntArray (list) {
36382 var array = new Array(list.size()).fill(null);
36383 for (var i = 0; i < array.length; i++) {
36384 array[i] = list.get(i).intValue();
36385 }
36386 return array
36387};
36388
36389var MonotoneChainEdge = function MonotoneChainEdge () {
36390 this.e = null;
36391 this.pts = null;
36392 this.startIndex = null;
36393 this.env1 = new Envelope();
36394 this.env2 = new Envelope();
36395 var e = arguments[0];
36396 this.e = e;
36397 this.pts = e.getCoordinates();
36398 var mcb = new MonotoneChainIndexer();
36399 this.startIndex = mcb.getChainStartIndices(this.pts);
36400};
36401MonotoneChainEdge.prototype.getCoordinates = function getCoordinates () {
36402 return this.pts
36403};
36404MonotoneChainEdge.prototype.getMaxX = function getMaxX (chainIndex) {
36405 var x1 = this.pts[this.startIndex[chainIndex]].x;
36406 var x2 = this.pts[this.startIndex[chainIndex + 1]].x;
36407 return x1 > x2 ? x1 : x2
36408};
36409MonotoneChainEdge.prototype.getMinX = function getMinX (chainIndex) {
36410 var x1 = this.pts[this.startIndex[chainIndex]].x;
36411 var x2 = this.pts[this.startIndex[chainIndex + 1]].x;
36412 return x1 < x2 ? x1 : x2
36413};
36414MonotoneChainEdge.prototype.computeIntersectsForChain = function computeIntersectsForChain () {
36415 if (arguments.length === 4) {
36416 var chainIndex0 = arguments[0];
36417 var mce = arguments[1];
36418 var chainIndex1 = arguments[2];
36419 var si = arguments[3];
36420 this.computeIntersectsForChain(this.startIndex[chainIndex0], this.startIndex[chainIndex0 + 1], mce, mce.startIndex[chainIndex1], mce.startIndex[chainIndex1 + 1], si);
36421 } else if (arguments.length === 6) {
36422 var start0 = arguments[0];
36423 var end0 = arguments[1];
36424 var mce$1 = arguments[2];
36425 var start1 = arguments[3];
36426 var end1 = arguments[4];
36427 var ei = arguments[5];
36428 var p00 = this.pts[start0];
36429 var p01 = this.pts[end0];
36430 var p10 = mce$1.pts[start1];
36431 var p11 = mce$1.pts[end1];
36432 if (end0 - start0 === 1 && end1 - start1 === 1) {
36433 ei.addIntersections(this.e, start0, mce$1.e, start1);
36434 return null
36435 }
36436 this.env1.init(p00, p01);
36437 this.env2.init(p10, p11);
36438 if (!this.env1.intersects(this.env2)) { return null }
36439 var mid0 = Math.trunc((start0 + end0) / 2);
36440 var mid1 = Math.trunc((start1 + end1) / 2);
36441 if (start0 < mid0) {
36442 if (start1 < mid1) { this.computeIntersectsForChain(start0, mid0, mce$1, start1, mid1, ei); }
36443 if (mid1 < end1) { this.computeIntersectsForChain(start0, mid0, mce$1, mid1, end1, ei); }
36444 }
36445 if (mid0 < end0) {
36446 if (start1 < mid1) { this.computeIntersectsForChain(mid0, end0, mce$1, start1, mid1, ei); }
36447 if (mid1 < end1) { this.computeIntersectsForChain(mid0, end0, mce$1, mid1, end1, ei); }
36448 }
36449 }
36450};
36451MonotoneChainEdge.prototype.getStartIndexes = function getStartIndexes () {
36452 return this.startIndex
36453};
36454MonotoneChainEdge.prototype.computeIntersects = function computeIntersects (mce, si) {
36455 var this$1 = this;
36456
36457 for (var i = 0; i < this.startIndex.length - 1; i++) {
36458 for (var j = 0; j < mce.startIndex.length - 1; j++) {
36459 this$1.computeIntersectsForChain(i, mce, j, si);
36460 }
36461 }
36462};
36463MonotoneChainEdge.prototype.interfaces_ = function interfaces_ () {
36464 return []
36465};
36466MonotoneChainEdge.prototype.getClass = function getClass () {
36467 return MonotoneChainEdge
36468};
36469
36470var Depth = function Depth () {
36471 var this$1 = this;
36472
36473 this._depth = Array(2).fill().map(function () { return Array(3); });
36474 for (var i = 0; i < 2; i++) {
36475 for (var j = 0; j < 3; j++) {
36476 this$1._depth[i][j] = Depth.NULL_VALUE;
36477 }
36478 }
36479};
36480
36481var staticAccessors$31 = { NULL_VALUE: { configurable: true } };
36482Depth.prototype.getDepth = function getDepth (geomIndex, posIndex) {
36483 return this._depth[geomIndex][posIndex]
36484};
36485Depth.prototype.setDepth = function setDepth (geomIndex, posIndex, depthValue) {
36486 this._depth[geomIndex][posIndex] = depthValue;
36487};
36488Depth.prototype.isNull = function isNull () {
36489 var this$1 = this;
36490
36491 if (arguments.length === 0) {
36492 for (var i = 0; i < 2; i++) {
36493 for (var j = 0; j < 3; j++) {
36494 if (this$1._depth[i][j] !== Depth.NULL_VALUE) { return false }
36495 }
36496 }
36497 return true
36498 } else if (arguments.length === 1) {
36499 var geomIndex = arguments[0];
36500 return this._depth[geomIndex][1] === Depth.NULL_VALUE
36501 } else if (arguments.length === 2) {
36502 var geomIndex$1 = arguments[0];
36503 var posIndex = arguments[1];
36504 return this._depth[geomIndex$1][posIndex] === Depth.NULL_VALUE
36505 }
36506};
36507Depth.prototype.normalize = function normalize () {
36508 var this$1 = this;
36509
36510 for (var i = 0; i < 2; i++) {
36511 if (!this$1.isNull(i)) {
36512 var minDepth = this$1._depth[i][1];
36513 if (this$1._depth[i][2] < minDepth) { minDepth = this$1._depth[i][2]; }
36514 if (minDepth < 0) { minDepth = 0; }
36515 for (var j = 1; j < 3; j++) {
36516 var newValue = 0;
36517 if (this$1._depth[i][j] > minDepth) { newValue = 1; }
36518 this$1._depth[i][j] = newValue;
36519 }
36520 }
36521 }
36522};
36523Depth.prototype.getDelta = function getDelta (geomIndex) {
36524 return this._depth[geomIndex][Position.RIGHT] - this._depth[geomIndex][Position.LEFT]
36525};
36526Depth.prototype.getLocation = function getLocation (geomIndex, posIndex) {
36527 if (this._depth[geomIndex][posIndex] <= 0) { return Location.EXTERIOR }
36528 return Location.INTERIOR
36529};
36530Depth.prototype.toString = function toString () {
36531 return 'A: ' + this._depth[0][1] + ',' + this._depth[0][2] + ' B: ' + this._depth[1][1] + ',' + this._depth[1][2]
36532};
36533Depth.prototype.add = function add () {
36534 var this$1 = this;
36535
36536 if (arguments.length === 1) {
36537 var lbl = arguments[0];
36538 for (var i = 0; i < 2; i++) {
36539 for (var j = 1; j < 3; j++) {
36540 var loc = lbl.getLocation(i, j);
36541 if (loc === Location.EXTERIOR || loc === Location.INTERIOR) {
36542 if (this$1.isNull(i, j)) {
36543 this$1._depth[i][j] = Depth.depthAtLocation(loc);
36544 } else { this$1._depth[i][j] += Depth.depthAtLocation(loc); }
36545 }
36546 }
36547 }
36548 } else if (arguments.length === 3) {
36549 var geomIndex = arguments[0];
36550 var posIndex = arguments[1];
36551 var location = arguments[2];
36552 if (location === Location.INTERIOR) { this._depth[geomIndex][posIndex]++; }
36553 }
36554};
36555Depth.prototype.interfaces_ = function interfaces_ () {
36556 return []
36557};
36558Depth.prototype.getClass = function getClass () {
36559 return Depth
36560};
36561Depth.depthAtLocation = function depthAtLocation (location) {
36562 if (location === Location.EXTERIOR) { return 0 }
36563 if (location === Location.INTERIOR) { return 1 }
36564 return Depth.NULL_VALUE
36565};
36566staticAccessors$31.NULL_VALUE.get = function () { return -1 };
36567
36568Object.defineProperties( Depth, staticAccessors$31 );
36569
36570var Edge$1 = (function (GraphComponent$$1) {
36571 function Edge () {
36572 GraphComponent$$1.call(this);
36573 this.pts = null;
36574 this._env = null;
36575 this.eiList = new EdgeIntersectionList(this);
36576 this._name = null;
36577 this._mce = null;
36578 this._isIsolated = true;
36579 this._depth = new Depth();
36580 this._depthDelta = 0;
36581 if (arguments.length === 1) {
36582 var pts = arguments[0];
36583 Edge.call(this, pts, null);
36584 } else if (arguments.length === 2) {
36585 var pts$1 = arguments[0];
36586 var label = arguments[1];
36587 this.pts = pts$1;
36588 this._label = label;
36589 }
36590 }
36591
36592 if ( GraphComponent$$1 ) Edge.__proto__ = GraphComponent$$1;
36593 Edge.prototype = Object.create( GraphComponent$$1 && GraphComponent$$1.prototype );
36594 Edge.prototype.constructor = Edge;
36595 Edge.prototype.getDepth = function getDepth () {
36596 return this._depth
36597 };
36598 Edge.prototype.getCollapsedEdge = function getCollapsedEdge () {
36599 var newPts = new Array(2).fill(null);
36600 newPts[0] = this.pts[0];
36601 newPts[1] = this.pts[1];
36602 var newe = new Edge(newPts, Label.toLineLabel(this._label));
36603 return newe
36604 };
36605 Edge.prototype.isIsolated = function isIsolated () {
36606 return this._isIsolated
36607 };
36608 Edge.prototype.getCoordinates = function getCoordinates () {
36609 return this.pts
36610 };
36611 Edge.prototype.setIsolated = function setIsolated (isIsolated) {
36612 this._isIsolated = isIsolated;
36613 };
36614 Edge.prototype.setName = function setName (name) {
36615 this._name = name;
36616 };
36617 Edge.prototype.equals = function equals (o) {
36618 var this$1 = this;
36619
36620 if (!(o instanceof Edge)) { return false }
36621 var e = o;
36622 if (this.pts.length !== e.pts.length) { return false }
36623 var isEqualForward = true;
36624 var isEqualReverse = true;
36625 var iRev = this.pts.length;
36626 for (var i = 0; i < this.pts.length; i++) {
36627 if (!this$1.pts[i].equals2D(e.pts[i])) {
36628 isEqualForward = false;
36629 }
36630 if (!this$1.pts[i].equals2D(e.pts[--iRev])) {
36631 isEqualReverse = false;
36632 }
36633 if (!isEqualForward && !isEqualReverse) { return false }
36634 }
36635 return true
36636 };
36637 Edge.prototype.getCoordinate = function getCoordinate () {
36638 if (arguments.length === 0) {
36639 if (this.pts.length > 0) { return this.pts[0] }
36640 return null
36641 } else if (arguments.length === 1) {
36642 var i = arguments[0];
36643 return this.pts[i]
36644 }
36645 };
36646 Edge.prototype.print = function print (out) {
36647 var this$1 = this;
36648
36649 out.print('edge ' + this._name + ': ');
36650 out.print('LINESTRING (');
36651 for (var i = 0; i < this.pts.length; i++) {
36652 if (i > 0) { out.print(','); }
36653 out.print(this$1.pts[i].x + ' ' + this$1.pts[i].y);
36654 }
36655 out.print(') ' + this._label + ' ' + this._depthDelta);
36656 };
36657 Edge.prototype.computeIM = function computeIM (im) {
36658 Edge.updateIM(this._label, im);
36659 };
36660 Edge.prototype.isCollapsed = function isCollapsed () {
36661 if (!this._label.isArea()) { return false }
36662 if (this.pts.length !== 3) { return false }
36663 if (this.pts[0].equals(this.pts[2])) { return true }
36664 return false
36665 };
36666 Edge.prototype.isClosed = function isClosed () {
36667 return this.pts[0].equals(this.pts[this.pts.length - 1])
36668 };
36669 Edge.prototype.getMaximumSegmentIndex = function getMaximumSegmentIndex () {
36670 return this.pts.length - 1
36671 };
36672 Edge.prototype.getDepthDelta = function getDepthDelta () {
36673 return this._depthDelta
36674 };
36675 Edge.prototype.getNumPoints = function getNumPoints () {
36676 return this.pts.length
36677 };
36678 Edge.prototype.printReverse = function printReverse (out) {
36679 var this$1 = this;
36680
36681 out.print('edge ' + this._name + ': ');
36682 for (var i = this.pts.length - 1; i >= 0; i--) {
36683 out.print(this$1.pts[i] + ' ');
36684 }
36685 out.println('');
36686 };
36687 Edge.prototype.getMonotoneChainEdge = function getMonotoneChainEdge () {
36688 if (this._mce === null) { this._mce = new MonotoneChainEdge(this); }
36689 return this._mce
36690 };
36691 Edge.prototype.getEnvelope = function getEnvelope () {
36692 var this$1 = this;
36693
36694 if (this._env === null) {
36695 this._env = new Envelope();
36696 for (var i = 0; i < this.pts.length; i++) {
36697 this$1._env.expandToInclude(this$1.pts[i]);
36698 }
36699 }
36700 return this._env
36701 };
36702 Edge.prototype.addIntersection = function addIntersection (li, segmentIndex, geomIndex, intIndex) {
36703 var intPt = new Coordinate(li.getIntersection(intIndex));
36704 var normalizedSegmentIndex = segmentIndex;
36705 var dist = li.getEdgeDistance(geomIndex, intIndex);
36706 var nextSegIndex = normalizedSegmentIndex + 1;
36707 if (nextSegIndex < this.pts.length) {
36708 var nextPt = this.pts[nextSegIndex];
36709 if (intPt.equals2D(nextPt)) {
36710 normalizedSegmentIndex = nextSegIndex;
36711 dist = 0.0;
36712 }
36713 }
36714 this.eiList.add(intPt, normalizedSegmentIndex, dist);
36715 };
36716 Edge.prototype.toString = function toString () {
36717 var this$1 = this;
36718
36719 var buf = new StringBuffer();
36720 buf.append('edge ' + this._name + ': ');
36721 buf.append('LINESTRING (');
36722 for (var i = 0; i < this.pts.length; i++) {
36723 if (i > 0) { buf.append(','); }
36724 buf.append(this$1.pts[i].x + ' ' + this$1.pts[i].y);
36725 }
36726 buf.append(') ' + this._label + ' ' + this._depthDelta);
36727 return buf.toString()
36728 };
36729 Edge.prototype.isPointwiseEqual = function isPointwiseEqual (e) {
36730 var this$1 = this;
36731
36732 if (this.pts.length !== e.pts.length) { return false }
36733 for (var i = 0; i < this.pts.length; i++) {
36734 if (!this$1.pts[i].equals2D(e.pts[i])) {
36735 return false
36736 }
36737 }
36738 return true
36739 };
36740 Edge.prototype.setDepthDelta = function setDepthDelta (depthDelta) {
36741 this._depthDelta = depthDelta;
36742 };
36743 Edge.prototype.getEdgeIntersectionList = function getEdgeIntersectionList () {
36744 return this.eiList
36745 };
36746 Edge.prototype.addIntersections = function addIntersections (li, segmentIndex, geomIndex) {
36747 var this$1 = this;
36748
36749 for (var i = 0; i < li.getIntersectionNum(); i++) {
36750 this$1.addIntersection(li, segmentIndex, geomIndex, i);
36751 }
36752 };
36753 Edge.prototype.interfaces_ = function interfaces_ () {
36754 return []
36755 };
36756 Edge.prototype.getClass = function getClass () {
36757 return Edge
36758 };
36759 Edge.updateIM = function updateIM () {
36760 if (arguments.length === 2) {
36761 var label = arguments[0];
36762 var im = arguments[1];
36763 im.setAtLeastIfValid(label.getLocation(0, Position.ON), label.getLocation(1, Position.ON), 1);
36764 if (label.isArea()) {
36765 im.setAtLeastIfValid(label.getLocation(0, Position.LEFT), label.getLocation(1, Position.LEFT), 2);
36766 im.setAtLeastIfValid(label.getLocation(0, Position.RIGHT), label.getLocation(1, Position.RIGHT), 2);
36767 }
36768 } else { return GraphComponent$$1.prototype.updateIM.apply(this, arguments) }
36769 };
36770
36771 return Edge;
36772}(GraphComponent));
36773
36774var BufferBuilder = function BufferBuilder (bufParams) {
36775 this._workingPrecisionModel = null;
36776 this._workingNoder = null;
36777 this._geomFact = null;
36778 this._graph = null;
36779 this._edgeList = new EdgeList();
36780 this._bufParams = bufParams || null;
36781};
36782BufferBuilder.prototype.setWorkingPrecisionModel = function setWorkingPrecisionModel (pm) {
36783 this._workingPrecisionModel = pm;
36784};
36785BufferBuilder.prototype.insertUniqueEdge = function insertUniqueEdge (e) {
36786 var existingEdge = this._edgeList.findEqualEdge(e);
36787 if (existingEdge !== null) {
36788 var existingLabel = existingEdge.getLabel();
36789 var labelToMerge = e.getLabel();
36790 if (!existingEdge.isPointwiseEqual(e)) {
36791 labelToMerge = new Label(e.getLabel());
36792 labelToMerge.flip();
36793 }
36794 existingLabel.merge(labelToMerge);
36795 var mergeDelta = BufferBuilder.depthDelta(labelToMerge);
36796 var existingDelta = existingEdge.getDepthDelta();
36797 var newDelta = existingDelta + mergeDelta;
36798 existingEdge.setDepthDelta(newDelta);
36799 } else {
36800 this._edgeList.add(e);
36801 e.setDepthDelta(BufferBuilder.depthDelta(e.getLabel()));
36802 }
36803};
36804BufferBuilder.prototype.buildSubgraphs = function buildSubgraphs (subgraphList, polyBuilder) {
36805 var processedGraphs = new ArrayList();
36806 for (var i = subgraphList.iterator(); i.hasNext();) {
36807 var subgraph = i.next();
36808 var p = subgraph.getRightmostCoordinate();
36809 var locater = new SubgraphDepthLocater(processedGraphs);
36810 var outsideDepth = locater.getDepth(p);
36811 subgraph.computeDepth(outsideDepth);
36812 subgraph.findResultEdges();
36813 processedGraphs.add(subgraph);
36814 polyBuilder.add(subgraph.getDirectedEdges(), subgraph.getNodes());
36815 }
36816};
36817BufferBuilder.prototype.createSubgraphs = function createSubgraphs (graph) {
36818 var subgraphList = new ArrayList();
36819 for (var i = graph.getNodes().iterator(); i.hasNext();) {
36820 var node = i.next();
36821 if (!node.isVisited()) {
36822 var subgraph = new BufferSubgraph();
36823 subgraph.create(node);
36824 subgraphList.add(subgraph);
36825 }
36826 }
36827 Collections.sort(subgraphList, Collections.reverseOrder());
36828 return subgraphList
36829};
36830BufferBuilder.prototype.createEmptyResultGeometry = function createEmptyResultGeometry () {
36831 var emptyGeom = this._geomFact.createPolygon();
36832 return emptyGeom
36833};
36834BufferBuilder.prototype.getNoder = function getNoder (precisionModel) {
36835 if (this._workingNoder !== null) { return this._workingNoder }
36836 var noder = new MCIndexNoder();
36837 var li = new RobustLineIntersector();
36838 li.setPrecisionModel(precisionModel);
36839 noder.setSegmentIntersector(new IntersectionAdder(li));
36840 return noder
36841};
36842BufferBuilder.prototype.buffer = function buffer (g, distance) {
36843 var precisionModel = this._workingPrecisionModel;
36844 if (precisionModel === null) { precisionModel = g.getPrecisionModel(); }
36845 this._geomFact = g.getFactory();
36846 var curveBuilder = new OffsetCurveBuilder(precisionModel, this._bufParams);
36847 var curveSetBuilder = new OffsetCurveSetBuilder(g, distance, curveBuilder);
36848 var bufferSegStrList = curveSetBuilder.getCurves();
36849 if (bufferSegStrList.size() <= 0) {
36850 return this.createEmptyResultGeometry()
36851 }
36852 this.computeNodedEdges(bufferSegStrList, precisionModel);
36853 this._graph = new PlanarGraph(new OverlayNodeFactory());
36854 this._graph.addEdges(this._edgeList.getEdges());
36855 var subgraphList = this.createSubgraphs(this._graph);
36856 var polyBuilder = new PolygonBuilder(this._geomFact);
36857 this.buildSubgraphs(subgraphList, polyBuilder);
36858 var resultPolyList = polyBuilder.getPolygons();
36859 if (resultPolyList.size() <= 0) {
36860 return this.createEmptyResultGeometry()
36861 }
36862 var resultGeom = this._geomFact.buildGeometry(resultPolyList);
36863 return resultGeom
36864};
36865BufferBuilder.prototype.computeNodedEdges = function computeNodedEdges (bufferSegStrList, precisionModel) {
36866 var this$1 = this;
36867
36868 var noder = this.getNoder(precisionModel);
36869 noder.computeNodes(bufferSegStrList);
36870 var nodedSegStrings = noder.getNodedSubstrings();
36871 for (var i = nodedSegStrings.iterator(); i.hasNext();) {
36872 var segStr = i.next();
36873 var pts = segStr.getCoordinates();
36874 if (pts.length === 2 && pts[0].equals2D(pts[1])) { continue }
36875 var oldLabel = segStr.getData();
36876 var edge = new Edge$1(segStr.getCoordinates(), new Label(oldLabel));
36877 this$1.insertUniqueEdge(edge);
36878 }
36879};
36880BufferBuilder.prototype.setNoder = function setNoder (noder) {
36881 this._workingNoder = noder;
36882};
36883BufferBuilder.prototype.interfaces_ = function interfaces_ () {
36884 return []
36885};
36886BufferBuilder.prototype.getClass = function getClass () {
36887 return BufferBuilder
36888};
36889BufferBuilder.depthDelta = function depthDelta (label) {
36890 var lLoc = label.getLocation(0, Position.LEFT);
36891 var rLoc = label.getLocation(0, Position.RIGHT);
36892 if (lLoc === Location.INTERIOR && rLoc === Location.EXTERIOR) { return 1; } else if (lLoc === Location.EXTERIOR && rLoc === Location.INTERIOR) { return -1 }
36893 return 0
36894};
36895BufferBuilder.convertSegStrings = function convertSegStrings (it) {
36896 var fact = new GeometryFactory();
36897 var lines = new ArrayList();
36898 while (it.hasNext()) {
36899 var ss = it.next();
36900 var line = fact.createLineString(ss.getCoordinates());
36901 lines.add(line);
36902 }
36903 return fact.buildGeometry(lines)
36904};
36905
36906var ScaledNoder = function ScaledNoder () {
36907 this._noder = null;
36908 this._scaleFactor = null;
36909 this._offsetX = null;
36910 this._offsetY = null;
36911 this._isScaled = false;
36912 if (arguments.length === 2) {
36913 var noder = arguments[0];
36914 var scaleFactor = arguments[1];
36915 this._noder = noder;
36916 this._scaleFactor = scaleFactor;
36917 this._offsetX = 0.0;
36918 this._offsetY = 0.0;
36919 this._isScaled = !this.isIntegerPrecision();
36920 } else if (arguments.length === 4) {
36921 var noder$1 = arguments[0];
36922 var scaleFactor$1 = arguments[1];
36923 var offsetX = arguments[2];
36924 var offsetY = arguments[3];
36925 this._noder = noder$1;
36926 this._scaleFactor = scaleFactor$1;
36927 this._offsetX = offsetX;
36928 this._offsetY = offsetY;
36929 this._isScaled = !this.isIntegerPrecision();
36930 }
36931};
36932ScaledNoder.prototype.rescale = function rescale () {
36933 var this$1 = this;
36934
36935 if (hasInterface(arguments[0], Collection)) {
36936 var segStrings = arguments[0];
36937 for (var i = segStrings.iterator(); i.hasNext();) {
36938 var ss = i.next();
36939 this$1.rescale(ss.getCoordinates());
36940 }
36941 } else if (arguments[0] instanceof Array) {
36942 var pts = arguments[0];
36943 // let p0 = null
36944 // let p1 = null
36945 // if (pts.length === 2) {
36946 // p0 = new Coordinate(pts[0])
36947 // p1 = new Coordinate(pts[1])
36948 // }
36949 for (var i$1 = 0; i$1 < pts.length; i$1++) {
36950 pts[i$1].x = pts[i$1].x / this$1._scaleFactor + this$1._offsetX;
36951 pts[i$1].y = pts[i$1].y / this$1._scaleFactor + this$1._offsetY;
36952 }
36953 if (pts.length === 2 && pts[0].equals2D(pts[1])) {
36954 System.out.println(pts);
36955 }
36956 }
36957};
36958ScaledNoder.prototype.scale = function scale () {
36959 var this$1 = this;
36960
36961 if (hasInterface(arguments[0], Collection)) {
36962 var segStrings = arguments[0];
36963 var nodedSegmentStrings = new ArrayList();
36964 for (var i = segStrings.iterator(); i.hasNext();) {
36965 var ss = i.next();
36966 nodedSegmentStrings.add(new NodedSegmentString(this$1.scale(ss.getCoordinates()), ss.getData()));
36967 }
36968 return nodedSegmentStrings
36969 } else if (arguments[0] instanceof Array) {
36970 var pts = arguments[0];
36971 var roundPts = new Array(pts.length).fill(null);
36972 for (var i$1 = 0; i$1 < pts.length; i$1++) {
36973 roundPts[i$1] = new Coordinate(Math.round((pts[i$1].x - this$1._offsetX) * this$1._scaleFactor), Math.round((pts[i$1].y - this$1._offsetY) * this$1._scaleFactor), pts[i$1].z);
36974 }
36975 var roundPtsNoDup = CoordinateArrays.removeRepeatedPoints(roundPts);
36976 return roundPtsNoDup
36977 }
36978};
36979ScaledNoder.prototype.isIntegerPrecision = function isIntegerPrecision () {
36980 return this._scaleFactor === 1.0
36981};
36982ScaledNoder.prototype.getNodedSubstrings = function getNodedSubstrings () {
36983 var splitSS = this._noder.getNodedSubstrings();
36984 if (this._isScaled) { this.rescale(splitSS); }
36985 return splitSS
36986};
36987ScaledNoder.prototype.computeNodes = function computeNodes (inputSegStrings) {
36988 var intSegStrings = inputSegStrings;
36989 if (this._isScaled) { intSegStrings = this.scale(inputSegStrings); }
36990 this._noder.computeNodes(intSegStrings);
36991};
36992ScaledNoder.prototype.interfaces_ = function interfaces_ () {
36993 return [Noder]
36994};
36995ScaledNoder.prototype.getClass = function getClass () {
36996 return ScaledNoder
36997};
36998
36999var NodingValidator = function NodingValidator () {
37000 this._li = new RobustLineIntersector();
37001 this._segStrings = null;
37002 var segStrings = arguments[0];
37003 this._segStrings = segStrings;
37004};
37005
37006var staticAccessors$33 = { fact: { configurable: true } };
37007NodingValidator.prototype.checkEndPtVertexIntersections = function checkEndPtVertexIntersections () {
37008 var this$1 = this;
37009
37010 if (arguments.length === 0) {
37011 for (var i = this._segStrings.iterator(); i.hasNext();) {
37012 var ss = i.next();
37013 var pts = ss.getCoordinates();
37014 this$1.checkEndPtVertexIntersections(pts[0], this$1._segStrings);
37015 this$1.checkEndPtVertexIntersections(pts[pts.length - 1], this$1._segStrings);
37016 }
37017 } else if (arguments.length === 2) {
37018 var testPt = arguments[0];
37019 var segStrings = arguments[1];
37020 for (var i$1 = segStrings.iterator(); i$1.hasNext();) {
37021 var ss$1 = i$1.next();
37022 var pts$1 = ss$1.getCoordinates();
37023 for (var j = 1; j < pts$1.length - 1; j++) {
37024 if (pts$1[j].equals(testPt)) { throw new RuntimeException('found endpt/interior pt intersection at index ' + j + ' :pt ' + testPt) }
37025 }
37026 }
37027 }
37028};
37029NodingValidator.prototype.checkInteriorIntersections = function checkInteriorIntersections () {
37030 var this$1 = this;
37031
37032 if (arguments.length === 0) {
37033 for (var i = this._segStrings.iterator(); i.hasNext();) {
37034 var ss0 = i.next();
37035 for (var j = this._segStrings.iterator(); j.hasNext();) {
37036 var ss1 = j.next();
37037 this$1.checkInteriorIntersections(ss0, ss1);
37038 }
37039 }
37040 } else if (arguments.length === 2) {
37041 var ss0$1 = arguments[0];
37042 var ss1$1 = arguments[1];
37043 var pts0 = ss0$1.getCoordinates();
37044 var pts1 = ss1$1.getCoordinates();
37045 for (var i0 = 0; i0 < pts0.length - 1; i0++) {
37046 for (var i1 = 0; i1 < pts1.length - 1; i1++) {
37047 this$1.checkInteriorIntersections(ss0$1, i0, ss1$1, i1);
37048 }
37049 }
37050 } else if (arguments.length === 4) {
37051 var e0 = arguments[0];
37052 var segIndex0 = arguments[1];
37053 var e1 = arguments[2];
37054 var segIndex1 = arguments[3];
37055 if (e0 === e1 && segIndex0 === segIndex1) { return null }
37056 var p00 = e0.getCoordinates()[segIndex0];
37057 var p01 = e0.getCoordinates()[segIndex0 + 1];
37058 var p10 = e1.getCoordinates()[segIndex1];
37059 var p11 = e1.getCoordinates()[segIndex1 + 1];
37060 this._li.computeIntersection(p00, p01, p10, p11);
37061 if (this._li.hasIntersection()) {
37062 if (this._li.isProper() || this.hasInteriorIntersection(this._li, p00, p01) || this.hasInteriorIntersection(this._li, p10, p11)) {
37063 throw new RuntimeException('found non-noded intersection at ' + p00 + '-' + p01 + ' and ' + p10 + '-' + p11)
37064 }
37065 }
37066 }
37067};
37068NodingValidator.prototype.checkValid = function checkValid () {
37069 this.checkEndPtVertexIntersections();
37070 this.checkInteriorIntersections();
37071 this.checkCollapses();
37072};
37073NodingValidator.prototype.checkCollapses = function checkCollapses () {
37074 var this$1 = this;
37075
37076 if (arguments.length === 0) {
37077 for (var i = this._segStrings.iterator(); i.hasNext();) {
37078 var ss = i.next();
37079 this$1.checkCollapses(ss);
37080 }
37081 } else if (arguments.length === 1) {
37082 var ss$1 = arguments[0];
37083 var pts = ss$1.getCoordinates();
37084 for (var i$1 = 0; i$1 < pts.length - 2; i$1++) {
37085 this$1.checkCollapse(pts[i$1], pts[i$1 + 1], pts[i$1 + 2]);
37086 }
37087 }
37088};
37089NodingValidator.prototype.hasInteriorIntersection = function hasInteriorIntersection (li, p0, p1) {
37090 for (var i = 0; i < li.getIntersectionNum(); i++) {
37091 var intPt = li.getIntersection(i);
37092 if (!(intPt.equals(p0) || intPt.equals(p1))) { return true }
37093 }
37094 return false
37095};
37096NodingValidator.prototype.checkCollapse = function checkCollapse (p0, p1, p2) {
37097 if (p0.equals(p2)) { throw new RuntimeException('found non-noded collapse at ' + NodingValidator.fact.createLineString([p0, p1, p2])) }
37098};
37099NodingValidator.prototype.interfaces_ = function interfaces_ () {
37100 return []
37101};
37102NodingValidator.prototype.getClass = function getClass () {
37103 return NodingValidator
37104};
37105staticAccessors$33.fact.get = function () { return new GeometryFactory() };
37106
37107Object.defineProperties( NodingValidator, staticAccessors$33 );
37108
37109var HotPixel = function HotPixel () {
37110 this._li = null;
37111 this._pt = null;
37112 this._originalPt = null;
37113 this._ptScaled = null;
37114 this._p0Scaled = null;
37115 this._p1Scaled = null;
37116 this._scaleFactor = null;
37117 this._minx = null;
37118 this._maxx = null;
37119 this._miny = null;
37120 this._maxy = null;
37121 this._corner = new Array(4).fill(null);
37122 this._safeEnv = null;
37123 var pt = arguments[0];
37124 var scaleFactor = arguments[1];
37125 var li = arguments[2];
37126 this._originalPt = pt;
37127 this._pt = pt;
37128 this._scaleFactor = scaleFactor;
37129 this._li = li;
37130 if (scaleFactor <= 0) { throw new IllegalArgumentException('Scale factor must be non-zero') }
37131 if (scaleFactor !== 1.0) {
37132 this._pt = new Coordinate(this.scale(pt.x), this.scale(pt.y));
37133 this._p0Scaled = new Coordinate();
37134 this._p1Scaled = new Coordinate();
37135 }
37136 this.initCorners(this._pt);
37137};
37138
37139var staticAccessors$34 = { SAFE_ENV_EXPANSION_FACTOR: { configurable: true } };
37140HotPixel.prototype.intersectsScaled = function intersectsScaled (p0, p1) {
37141 var segMinx = Math.min(p0.x, p1.x);
37142 var segMaxx = Math.max(p0.x, p1.x);
37143 var segMiny = Math.min(p0.y, p1.y);
37144 var segMaxy = Math.max(p0.y, p1.y);
37145 var isOutsidePixelEnv = this._maxx < segMinx || this._minx > segMaxx || this._maxy < segMiny || this._miny > segMaxy;
37146 if (isOutsidePixelEnv) { return false }
37147 var intersects = this.intersectsToleranceSquare(p0, p1);
37148 Assert.isTrue(!(isOutsidePixelEnv && intersects), 'Found bad envelope test');
37149 return intersects
37150};
37151HotPixel.prototype.initCorners = function initCorners (pt) {
37152 var tolerance = 0.5;
37153 this._minx = pt.x - tolerance;
37154 this._maxx = pt.x + tolerance;
37155 this._miny = pt.y - tolerance;
37156 this._maxy = pt.y + tolerance;
37157 this._corner[0] = new Coordinate(this._maxx, this._maxy);
37158 this._corner[1] = new Coordinate(this._minx, this._maxy);
37159 this._corner[2] = new Coordinate(this._minx, this._miny);
37160 this._corner[3] = new Coordinate(this._maxx, this._miny);
37161};
37162HotPixel.prototype.intersects = function intersects (p0, p1) {
37163 if (this._scaleFactor === 1.0) { return this.intersectsScaled(p0, p1) }
37164 this.copyScaled(p0, this._p0Scaled);
37165 this.copyScaled(p1, this._p1Scaled);
37166 return this.intersectsScaled(this._p0Scaled, this._p1Scaled)
37167};
37168HotPixel.prototype.scale = function scale (val) {
37169 return Math.round(val * this._scaleFactor)
37170};
37171HotPixel.prototype.getCoordinate = function getCoordinate () {
37172 return this._originalPt
37173};
37174HotPixel.prototype.copyScaled = function copyScaled (p, pScaled) {
37175 pScaled.x = this.scale(p.x);
37176 pScaled.y = this.scale(p.y);
37177};
37178HotPixel.prototype.getSafeEnvelope = function getSafeEnvelope () {
37179 if (this._safeEnv === null) {
37180 var safeTolerance = HotPixel.SAFE_ENV_EXPANSION_FACTOR / this._scaleFactor;
37181 this._safeEnv = new Envelope(this._originalPt.x - safeTolerance, this._originalPt.x + safeTolerance, this._originalPt.y - safeTolerance, this._originalPt.y + safeTolerance);
37182 }
37183 return this._safeEnv
37184};
37185HotPixel.prototype.intersectsPixelClosure = function intersectsPixelClosure (p0, p1) {
37186 this._li.computeIntersection(p0, p1, this._corner[0], this._corner[1]);
37187 if (this._li.hasIntersection()) { return true }
37188 this._li.computeIntersection(p0, p1, this._corner[1], this._corner[2]);
37189 if (this._li.hasIntersection()) { return true }
37190 this._li.computeIntersection(p0, p1, this._corner[2], this._corner[3]);
37191 if (this._li.hasIntersection()) { return true }
37192 this._li.computeIntersection(p0, p1, this._corner[3], this._corner[0]);
37193 if (this._li.hasIntersection()) { return true }
37194 return false
37195};
37196HotPixel.prototype.intersectsToleranceSquare = function intersectsToleranceSquare (p0, p1) {
37197 var intersectsLeft = false;
37198 var intersectsBottom = false;
37199 this._li.computeIntersection(p0, p1, this._corner[0], this._corner[1]);
37200 if (this._li.isProper()) { return true }
37201 this._li.computeIntersection(p0, p1, this._corner[1], this._corner[2]);
37202 if (this._li.isProper()) { return true }
37203 if (this._li.hasIntersection()) { intersectsLeft = true; }
37204 this._li.computeIntersection(p0, p1, this._corner[2], this._corner[3]);
37205 if (this._li.isProper()) { return true }
37206 if (this._li.hasIntersection()) { intersectsBottom = true; }
37207 this._li.computeIntersection(p0, p1, this._corner[3], this._corner[0]);
37208 if (this._li.isProper()) { return true }
37209 if (intersectsLeft && intersectsBottom) { return true }
37210 if (p0.equals(this._pt)) { return true }
37211 if (p1.equals(this._pt)) { return true }
37212 return false
37213};
37214HotPixel.prototype.addSnappedNode = function addSnappedNode (segStr, segIndex) {
37215 var p0 = segStr.getCoordinate(segIndex);
37216 var p1 = segStr.getCoordinate(segIndex + 1);
37217 if (this.intersects(p0, p1)) {
37218 segStr.addIntersection(this.getCoordinate(), segIndex);
37219 return true
37220 }
37221 return false
37222};
37223HotPixel.prototype.interfaces_ = function interfaces_ () {
37224 return []
37225};
37226HotPixel.prototype.getClass = function getClass () {
37227 return HotPixel
37228};
37229staticAccessors$34.SAFE_ENV_EXPANSION_FACTOR.get = function () { return 0.75 };
37230
37231Object.defineProperties( HotPixel, staticAccessors$34 );
37232
37233var MonotoneChainSelectAction = function MonotoneChainSelectAction () {
37234 this.tempEnv1 = new Envelope();
37235 this.selectedSegment = new LineSegment();
37236};
37237MonotoneChainSelectAction.prototype.select = function select () {
37238 if (arguments.length === 1) {
37239 // const seg = arguments[0]
37240 } else if (arguments.length === 2) {
37241 var mc = arguments[0];
37242 var startIndex = arguments[1];
37243 mc.getLineSegment(startIndex, this.selectedSegment);
37244 this.select(this.selectedSegment);
37245 }
37246};
37247MonotoneChainSelectAction.prototype.interfaces_ = function interfaces_ () {
37248 return []
37249};
37250MonotoneChainSelectAction.prototype.getClass = function getClass () {
37251 return MonotoneChainSelectAction
37252};
37253
37254var MCIndexPointSnapper = function MCIndexPointSnapper () {
37255 this._index = null;
37256 var index = arguments[0];
37257 this._index = index;
37258};
37259
37260var staticAccessors$35 = { HotPixelSnapAction: { configurable: true } };
37261MCIndexPointSnapper.prototype.snap = function snap () {
37262 if (arguments.length === 1) {
37263 var hotPixel = arguments[0];
37264 return this.snap(hotPixel, null, -1)
37265 } else if (arguments.length === 3) {
37266 var hotPixel$1 = arguments[0];
37267 var parentEdge = arguments[1];
37268 var hotPixelVertexIndex = arguments[2];
37269 var pixelEnv = hotPixel$1.getSafeEnvelope();
37270 var hotPixelSnapAction = new HotPixelSnapAction(hotPixel$1, parentEdge, hotPixelVertexIndex);
37271 this._index.query(pixelEnv, {
37272 interfaces_: function () {
37273 return [ItemVisitor]
37274 },
37275 visitItem: function (item) {
37276 var testChain = item;
37277 testChain.select(pixelEnv, hotPixelSnapAction);
37278 }
37279 });
37280 return hotPixelSnapAction.isNodeAdded()
37281 }
37282};
37283MCIndexPointSnapper.prototype.interfaces_ = function interfaces_ () {
37284 return []
37285};
37286MCIndexPointSnapper.prototype.getClass = function getClass () {
37287 return MCIndexPointSnapper
37288};
37289staticAccessors$35.HotPixelSnapAction.get = function () { return HotPixelSnapAction };
37290
37291Object.defineProperties( MCIndexPointSnapper, staticAccessors$35 );
37292
37293var HotPixelSnapAction = (function (MonotoneChainSelectAction$$1) {
37294 function HotPixelSnapAction () {
37295 MonotoneChainSelectAction$$1.call(this);
37296 this._hotPixel = null;
37297 this._parentEdge = null;
37298 this._hotPixelVertexIndex = null;
37299 this._isNodeAdded = false;
37300 var hotPixel = arguments[0];
37301 var parentEdge = arguments[1];
37302 var hotPixelVertexIndex = arguments[2];
37303 this._hotPixel = hotPixel;
37304 this._parentEdge = parentEdge;
37305 this._hotPixelVertexIndex = hotPixelVertexIndex;
37306 }
37307
37308 if ( MonotoneChainSelectAction$$1 ) HotPixelSnapAction.__proto__ = MonotoneChainSelectAction$$1;
37309 HotPixelSnapAction.prototype = Object.create( MonotoneChainSelectAction$$1 && MonotoneChainSelectAction$$1.prototype );
37310 HotPixelSnapAction.prototype.constructor = HotPixelSnapAction;
37311 HotPixelSnapAction.prototype.isNodeAdded = function isNodeAdded () {
37312 return this._isNodeAdded
37313 };
37314 HotPixelSnapAction.prototype.select = function select () {
37315 if (arguments.length === 2) {
37316 var mc = arguments[0];
37317 var startIndex = arguments[1];
37318 var ss = mc.getContext();
37319 if (this._parentEdge !== null) {
37320 if (ss === this._parentEdge && startIndex === this._hotPixelVertexIndex) { return null }
37321 }
37322 this._isNodeAdded = this._hotPixel.addSnappedNode(ss, startIndex);
37323 } else { return MonotoneChainSelectAction$$1.prototype.select.apply(this, arguments) }
37324 };
37325 HotPixelSnapAction.prototype.interfaces_ = function interfaces_ () {
37326 return []
37327 };
37328 HotPixelSnapAction.prototype.getClass = function getClass () {
37329 return HotPixelSnapAction
37330 };
37331
37332 return HotPixelSnapAction;
37333}(MonotoneChainSelectAction));
37334
37335var InteriorIntersectionFinderAdder = function InteriorIntersectionFinderAdder () {
37336 this._li = null;
37337 this._interiorIntersections = null;
37338 var li = arguments[0];
37339 this._li = li;
37340 this._interiorIntersections = new ArrayList();
37341};
37342InteriorIntersectionFinderAdder.prototype.processIntersections = function processIntersections (e0, segIndex0, e1, segIndex1) {
37343 var this$1 = this;
37344
37345 if (e0 === e1 && segIndex0 === segIndex1) { return null }
37346 var p00 = e0.getCoordinates()[segIndex0];
37347 var p01 = e0.getCoordinates()[segIndex0 + 1];
37348 var p10 = e1.getCoordinates()[segIndex1];
37349 var p11 = e1.getCoordinates()[segIndex1 + 1];
37350 this._li.computeIntersection(p00, p01, p10, p11);
37351 if (this._li.hasIntersection()) {
37352 if (this._li.isInteriorIntersection()) {
37353 for (var intIndex = 0; intIndex < this._li.getIntersectionNum(); intIndex++) {
37354 this$1._interiorIntersections.add(this$1._li.getIntersection(intIndex));
37355 }
37356 e0.addIntersections(this._li, segIndex0, 0);
37357 e1.addIntersections(this._li, segIndex1, 1);
37358 }
37359 }
37360};
37361InteriorIntersectionFinderAdder.prototype.isDone = function isDone () {
37362 return false
37363};
37364InteriorIntersectionFinderAdder.prototype.getInteriorIntersections = function getInteriorIntersections () {
37365 return this._interiorIntersections
37366};
37367InteriorIntersectionFinderAdder.prototype.interfaces_ = function interfaces_ () {
37368 return [SegmentIntersector]
37369};
37370InteriorIntersectionFinderAdder.prototype.getClass = function getClass () {
37371 return InteriorIntersectionFinderAdder
37372};
37373
37374var MCIndexSnapRounder = function MCIndexSnapRounder () {
37375 this._pm = null;
37376 this._li = null;
37377 this._scaleFactor = null;
37378 this._noder = null;
37379 this._pointSnapper = null;
37380 this._nodedSegStrings = null;
37381 var pm = arguments[0];
37382 this._pm = pm;
37383 this._li = new RobustLineIntersector();
37384 this._li.setPrecisionModel(pm);
37385 this._scaleFactor = pm.getScale();
37386};
37387MCIndexSnapRounder.prototype.checkCorrectness = function checkCorrectness (inputSegmentStrings) {
37388 var resultSegStrings = NodedSegmentString.getNodedSubstrings(inputSegmentStrings);
37389 var nv = new NodingValidator(resultSegStrings);
37390 try {
37391 nv.checkValid();
37392 } catch (ex) {
37393 if (ex instanceof Exception) {
37394 ex.printStackTrace();
37395 } else { throw ex }
37396 } finally {}
37397};
37398MCIndexSnapRounder.prototype.getNodedSubstrings = function getNodedSubstrings () {
37399 return NodedSegmentString.getNodedSubstrings(this._nodedSegStrings)
37400};
37401MCIndexSnapRounder.prototype.snapRound = function snapRound (segStrings, li) {
37402 var intersections = this.findInteriorIntersections(segStrings, li);
37403 this.computeIntersectionSnaps(intersections);
37404 this.computeVertexSnaps(segStrings);
37405};
37406MCIndexSnapRounder.prototype.findInteriorIntersections = function findInteriorIntersections (segStrings, li) {
37407 var intFinderAdder = new InteriorIntersectionFinderAdder(li);
37408 this._noder.setSegmentIntersector(intFinderAdder);
37409 this._noder.computeNodes(segStrings);
37410 return intFinderAdder.getInteriorIntersections()
37411};
37412MCIndexSnapRounder.prototype.computeVertexSnaps = function computeVertexSnaps () {
37413 var this$1 = this;
37414
37415 if (hasInterface(arguments[0], Collection)) {
37416 var edges = arguments[0];
37417 for (var i0 = edges.iterator(); i0.hasNext();) {
37418 var edge0 = i0.next();
37419 this$1.computeVertexSnaps(edge0);
37420 }
37421 } else if (arguments[0] instanceof NodedSegmentString) {
37422 var e = arguments[0];
37423 var pts0 = e.getCoordinates();
37424 for (var i = 0; i < pts0.length; i++) {
37425 var hotPixel = new HotPixel(pts0[i], this$1._scaleFactor, this$1._li);
37426 var isNodeAdded = this$1._pointSnapper.snap(hotPixel, e, i);
37427 if (isNodeAdded) {
37428 e.addIntersection(pts0[i], i);
37429 }
37430 }
37431 }
37432};
37433MCIndexSnapRounder.prototype.computeNodes = function computeNodes (inputSegmentStrings) {
37434 this._nodedSegStrings = inputSegmentStrings;
37435 this._noder = new MCIndexNoder();
37436 this._pointSnapper = new MCIndexPointSnapper(this._noder.getIndex());
37437 this.snapRound(inputSegmentStrings, this._li);
37438};
37439MCIndexSnapRounder.prototype.computeIntersectionSnaps = function computeIntersectionSnaps (snapPts) {
37440 var this$1 = this;
37441
37442 for (var it = snapPts.iterator(); it.hasNext();) {
37443 var snapPt = it.next();
37444 var hotPixel = new HotPixel(snapPt, this$1._scaleFactor, this$1._li);
37445 this$1._pointSnapper.snap(hotPixel);
37446 }
37447};
37448MCIndexSnapRounder.prototype.interfaces_ = function interfaces_ () {
37449 return [Noder]
37450};
37451MCIndexSnapRounder.prototype.getClass = function getClass () {
37452 return MCIndexSnapRounder
37453};
37454
37455var BufferOp = function BufferOp () {
37456 this._argGeom = null;
37457 this._distance = null;
37458 this._bufParams = new BufferParameters();
37459 this._resultGeometry = null;
37460 this._saveException = null;
37461 if (arguments.length === 1) {
37462 var g = arguments[0];
37463 this._argGeom = g;
37464 } else if (arguments.length === 2) {
37465 var g$1 = arguments[0];
37466 var bufParams = arguments[1];
37467 this._argGeom = g$1;
37468 this._bufParams = bufParams;
37469 }
37470};
37471
37472var staticAccessors$32 = { CAP_ROUND: { configurable: true },CAP_BUTT: { configurable: true },CAP_FLAT: { configurable: true },CAP_SQUARE: { configurable: true },MAX_PRECISION_DIGITS: { configurable: true } };
37473BufferOp.prototype.bufferFixedPrecision = function bufferFixedPrecision (fixedPM) {
37474 var noder = new ScaledNoder(new MCIndexSnapRounder(new PrecisionModel(1.0)), fixedPM.getScale());
37475 var bufBuilder = new BufferBuilder(this._bufParams);
37476 bufBuilder.setWorkingPrecisionModel(fixedPM);
37477 bufBuilder.setNoder(noder);
37478 this._resultGeometry = bufBuilder.buffer(this._argGeom, this._distance);
37479};
37480BufferOp.prototype.bufferReducedPrecision = function bufferReducedPrecision () {
37481 var this$1 = this;
37482
37483 if (arguments.length === 0) {
37484 for (var precDigits = BufferOp.MAX_PRECISION_DIGITS; precDigits >= 0; precDigits--) {
37485 try {
37486 this$1.bufferReducedPrecision(precDigits);
37487 } catch (ex) {
37488 if (ex instanceof TopologyException) {
37489 this$1._saveException = ex;
37490 } else { throw ex }
37491 } finally {}
37492 if (this$1._resultGeometry !== null) { return null }
37493 }
37494 throw this._saveException
37495 } else if (arguments.length === 1) {
37496 var precisionDigits = arguments[0];
37497 var sizeBasedScaleFactor = BufferOp.precisionScaleFactor(this._argGeom, this._distance, precisionDigits);
37498 var fixedPM = new PrecisionModel(sizeBasedScaleFactor);
37499 this.bufferFixedPrecision(fixedPM);
37500 }
37501};
37502BufferOp.prototype.computeGeometry = function computeGeometry () {
37503 this.bufferOriginalPrecision();
37504 if (this._resultGeometry !== null) { return null }
37505 var argPM = this._argGeom.getFactory().getPrecisionModel();
37506 if (argPM.getType() === PrecisionModel.FIXED) { this.bufferFixedPrecision(argPM); } else { this.bufferReducedPrecision(); }
37507};
37508BufferOp.prototype.setQuadrantSegments = function setQuadrantSegments (quadrantSegments) {
37509 this._bufParams.setQuadrantSegments(quadrantSegments);
37510};
37511BufferOp.prototype.bufferOriginalPrecision = function bufferOriginalPrecision () {
37512 try {
37513 var bufBuilder = new BufferBuilder(this._bufParams);
37514 this._resultGeometry = bufBuilder.buffer(this._argGeom, this._distance);
37515 } catch (ex) {
37516 if (ex instanceof RuntimeException) {
37517 this._saveException = ex;
37518 } else { throw ex }
37519 } finally {}
37520};
37521BufferOp.prototype.getResultGeometry = function getResultGeometry (distance) {
37522 this._distance = distance;
37523 this.computeGeometry();
37524 return this._resultGeometry
37525};
37526BufferOp.prototype.setEndCapStyle = function setEndCapStyle (endCapStyle) {
37527 this._bufParams.setEndCapStyle(endCapStyle);
37528};
37529BufferOp.prototype.interfaces_ = function interfaces_ () {
37530 return []
37531};
37532BufferOp.prototype.getClass = function getClass () {
37533 return BufferOp
37534};
37535BufferOp.bufferOp = function bufferOp () {
37536 if (arguments.length === 2) {
37537 var g = arguments[0];
37538 var distance = arguments[1];
37539 var gBuf = new BufferOp(g);
37540 var geomBuf = gBuf.getResultGeometry(distance);
37541 return geomBuf
37542 } else if (arguments.length === 3) {
37543 if (Number.isInteger(arguments[2]) && (arguments[0] instanceof Geometry && typeof arguments[1] === 'number')) {
37544 var g$1 = arguments[0];
37545 var distance$1 = arguments[1];
37546 var quadrantSegments = arguments[2];
37547 var bufOp = new BufferOp(g$1);
37548 bufOp.setQuadrantSegments(quadrantSegments);
37549 var geomBuf$1 = bufOp.getResultGeometry(distance$1);
37550 return geomBuf$1
37551 } else if (arguments[2] instanceof BufferParameters && (arguments[0] instanceof Geometry && typeof arguments[1] === 'number')) {
37552 var g$2 = arguments[0];
37553 var distance$2 = arguments[1];
37554 var params = arguments[2];
37555 var bufOp$1 = new BufferOp(g$2, params);
37556 var geomBuf$2 = bufOp$1.getResultGeometry(distance$2);
37557 return geomBuf$2
37558 }
37559 } else if (arguments.length === 4) {
37560 var g$3 = arguments[0];
37561 var distance$3 = arguments[1];
37562 var quadrantSegments$1 = arguments[2];
37563 var endCapStyle = arguments[3];
37564 var bufOp$2 = new BufferOp(g$3);
37565 bufOp$2.setQuadrantSegments(quadrantSegments$1);
37566 bufOp$2.setEndCapStyle(endCapStyle);
37567 var geomBuf$3 = bufOp$2.getResultGeometry(distance$3);
37568 return geomBuf$3
37569 }
37570};
37571BufferOp.precisionScaleFactor = function precisionScaleFactor (g, distance, maxPrecisionDigits) {
37572 var env = g.getEnvelopeInternal();
37573 var envMax = MathUtil.max(Math.abs(env.getMaxX()), Math.abs(env.getMaxY()), Math.abs(env.getMinX()), Math.abs(env.getMinY()));
37574 var expandByDistance = distance > 0.0 ? distance : 0.0;
37575 var bufEnvMax = envMax + 2 * expandByDistance;
37576 var bufEnvPrecisionDigits = Math.trunc(Math.log(bufEnvMax) / Math.log(10) + 1.0);
37577 var minUnitLog10 = maxPrecisionDigits - bufEnvPrecisionDigits;
37578 var scaleFactor = Math.pow(10.0, minUnitLog10);
37579 return scaleFactor
37580};
37581staticAccessors$32.CAP_ROUND.get = function () { return BufferParameters.CAP_ROUND };
37582staticAccessors$32.CAP_BUTT.get = function () { return BufferParameters.CAP_FLAT };
37583staticAccessors$32.CAP_FLAT.get = function () { return BufferParameters.CAP_FLAT };
37584staticAccessors$32.CAP_SQUARE.get = function () { return BufferParameters.CAP_SQUARE };
37585staticAccessors$32.MAX_PRECISION_DIGITS.get = function () { return 12 };
37586
37587Object.defineProperties( BufferOp, staticAccessors$32 );
37588
37589var PointPairDistance = function PointPairDistance () {
37590 this._pt = [new Coordinate(), new Coordinate()];
37591 this._distance = Double.NaN;
37592 this._isNull = true;
37593};
37594PointPairDistance.prototype.getCoordinates = function getCoordinates () {
37595 return this._pt
37596};
37597PointPairDistance.prototype.getCoordinate = function getCoordinate (i) {
37598 return this._pt[i]
37599};
37600PointPairDistance.prototype.setMinimum = function setMinimum () {
37601 if (arguments.length === 1) {
37602 var ptDist = arguments[0];
37603 this.setMinimum(ptDist._pt[0], ptDist._pt[1]);
37604 } else if (arguments.length === 2) {
37605 var p0 = arguments[0];
37606 var p1 = arguments[1];
37607 if (this._isNull) {
37608 this.initialize(p0, p1);
37609 return null
37610 }
37611 var dist = p0.distance(p1);
37612 if (dist < this._distance) { this.initialize(p0, p1, dist); }
37613 }
37614};
37615PointPairDistance.prototype.initialize = function initialize () {
37616 if (arguments.length === 0) {
37617 this._isNull = true;
37618 } else if (arguments.length === 2) {
37619 var p0 = arguments[0];
37620 var p1 = arguments[1];
37621 this._pt[0].setCoordinate(p0);
37622 this._pt[1].setCoordinate(p1);
37623 this._distance = p0.distance(p1);
37624 this._isNull = false;
37625 } else if (arguments.length === 3) {
37626 var p0$1 = arguments[0];
37627 var p1$1 = arguments[1];
37628 var distance = arguments[2];
37629 this._pt[0].setCoordinate(p0$1);
37630 this._pt[1].setCoordinate(p1$1);
37631 this._distance = distance;
37632 this._isNull = false;
37633 }
37634};
37635PointPairDistance.prototype.getDistance = function getDistance () {
37636 return this._distance
37637};
37638PointPairDistance.prototype.setMaximum = function setMaximum () {
37639 if (arguments.length === 1) {
37640 var ptDist = arguments[0];
37641 this.setMaximum(ptDist._pt[0], ptDist._pt[1]);
37642 } else if (arguments.length === 2) {
37643 var p0 = arguments[0];
37644 var p1 = arguments[1];
37645 if (this._isNull) {
37646 this.initialize(p0, p1);
37647 return null
37648 }
37649 var dist = p0.distance(p1);
37650 if (dist > this._distance) { this.initialize(p0, p1, dist); }
37651 }
37652};
37653PointPairDistance.prototype.interfaces_ = function interfaces_ () {
37654 return []
37655};
37656PointPairDistance.prototype.getClass = function getClass () {
37657 return PointPairDistance
37658};
37659
37660var DistanceToPointFinder = function DistanceToPointFinder () {};
37661
37662DistanceToPointFinder.prototype.interfaces_ = function interfaces_ () {
37663 return []
37664};
37665DistanceToPointFinder.prototype.getClass = function getClass () {
37666 return DistanceToPointFinder
37667};
37668DistanceToPointFinder.computeDistance = function computeDistance () {
37669 if (arguments[2] instanceof PointPairDistance && (arguments[0] instanceof LineString$1 && arguments[1] instanceof Coordinate)) {
37670 var line = arguments[0];
37671 var pt = arguments[1];
37672 var ptDist = arguments[2];
37673 var coords = line.getCoordinates();
37674 var tempSegment = new LineSegment();
37675 for (var i = 0; i < coords.length - 1; i++) {
37676 tempSegment.setCoordinates(coords[i], coords[i + 1]);
37677 var closestPt = tempSegment.closestPoint(pt);
37678 ptDist.setMinimum(closestPt, pt);
37679 }
37680 } else if (arguments[2] instanceof PointPairDistance && (arguments[0] instanceof Polygon && arguments[1] instanceof Coordinate)) {
37681 var poly = arguments[0];
37682 var pt$1 = arguments[1];
37683 var ptDist$1 = arguments[2];
37684 DistanceToPointFinder.computeDistance(poly.getExteriorRing(), pt$1, ptDist$1);
37685 for (var i$1 = 0; i$1 < poly.getNumInteriorRing(); i$1++) {
37686 DistanceToPointFinder.computeDistance(poly.getInteriorRingN(i$1), pt$1, ptDist$1);
37687 }
37688 } else if (arguments[2] instanceof PointPairDistance && (arguments[0] instanceof Geometry && arguments[1] instanceof Coordinate)) {
37689 var geom = arguments[0];
37690 var pt$2 = arguments[1];
37691 var ptDist$2 = arguments[2];
37692 if (geom instanceof LineString$1) {
37693 DistanceToPointFinder.computeDistance(geom, pt$2, ptDist$2);
37694 } else if (geom instanceof Polygon) {
37695 DistanceToPointFinder.computeDistance(geom, pt$2, ptDist$2);
37696 } else if (geom instanceof GeometryCollection) {
37697 var gc = geom;
37698 for (var i$2 = 0; i$2 < gc.getNumGeometries(); i$2++) {
37699 var g = gc.getGeometryN(i$2);
37700 DistanceToPointFinder.computeDistance(g, pt$2, ptDist$2);
37701 }
37702 } else {
37703 ptDist$2.setMinimum(geom.getCoordinate(), pt$2);
37704 }
37705 } else if (arguments[2] instanceof PointPairDistance && (arguments[0] instanceof LineSegment && arguments[1] instanceof Coordinate)) {
37706 var segment = arguments[0];
37707 var pt$3 = arguments[1];
37708 var ptDist$3 = arguments[2];
37709 var closestPt$1 = segment.closestPoint(pt$3);
37710 ptDist$3.setMinimum(closestPt$1, pt$3);
37711 }
37712};
37713
37714var BufferCurveMaximumDistanceFinder = function BufferCurveMaximumDistanceFinder (inputGeom) {
37715 this._maxPtDist = new PointPairDistance();
37716 this._inputGeom = inputGeom || null;
37717};
37718
37719var staticAccessors$36 = { MaxPointDistanceFilter: { configurable: true },MaxMidpointDistanceFilter: { configurable: true } };
37720BufferCurveMaximumDistanceFinder.prototype.computeMaxMidpointDistance = function computeMaxMidpointDistance (curve) {
37721 var distFilter = new MaxMidpointDistanceFilter(this._inputGeom);
37722 curve.apply(distFilter);
37723 this._maxPtDist.setMaximum(distFilter.getMaxPointDistance());
37724};
37725BufferCurveMaximumDistanceFinder.prototype.computeMaxVertexDistance = function computeMaxVertexDistance (curve) {
37726 var distFilter = new MaxPointDistanceFilter(this._inputGeom);
37727 curve.apply(distFilter);
37728 this._maxPtDist.setMaximum(distFilter.getMaxPointDistance());
37729};
37730BufferCurveMaximumDistanceFinder.prototype.findDistance = function findDistance (bufferCurve) {
37731 this.computeMaxVertexDistance(bufferCurve);
37732 this.computeMaxMidpointDistance(bufferCurve);
37733 return this._maxPtDist.getDistance()
37734};
37735BufferCurveMaximumDistanceFinder.prototype.getDistancePoints = function getDistancePoints () {
37736 return this._maxPtDist
37737};
37738BufferCurveMaximumDistanceFinder.prototype.interfaces_ = function interfaces_ () {
37739 return []
37740};
37741BufferCurveMaximumDistanceFinder.prototype.getClass = function getClass () {
37742 return BufferCurveMaximumDistanceFinder
37743};
37744staticAccessors$36.MaxPointDistanceFilter.get = function () { return MaxPointDistanceFilter };
37745staticAccessors$36.MaxMidpointDistanceFilter.get = function () { return MaxMidpointDistanceFilter };
37746
37747Object.defineProperties( BufferCurveMaximumDistanceFinder, staticAccessors$36 );
37748
37749var MaxPointDistanceFilter = function MaxPointDistanceFilter (geom) {
37750 this._maxPtDist = new PointPairDistance();
37751 this._minPtDist = new PointPairDistance();
37752 this._geom = geom || null;
37753};
37754MaxPointDistanceFilter.prototype.filter = function filter (pt) {
37755 this._minPtDist.initialize();
37756 DistanceToPointFinder.computeDistance(this._geom, pt, this._minPtDist);
37757 this._maxPtDist.setMaximum(this._minPtDist);
37758};
37759MaxPointDistanceFilter.prototype.getMaxPointDistance = function getMaxPointDistance () {
37760 return this._maxPtDist
37761};
37762MaxPointDistanceFilter.prototype.interfaces_ = function interfaces_ () {
37763 return [CoordinateFilter]
37764};
37765MaxPointDistanceFilter.prototype.getClass = function getClass () {
37766 return MaxPointDistanceFilter
37767};
37768
37769var MaxMidpointDistanceFilter = function MaxMidpointDistanceFilter (geom) {
37770 this._maxPtDist = new PointPairDistance();
37771 this._minPtDist = new PointPairDistance();
37772 this._geom = geom || null;
37773};
37774MaxMidpointDistanceFilter.prototype.filter = function filter (seq, index) {
37775 if (index === 0) { return null }
37776 var p0 = seq.getCoordinate(index - 1);
37777 var p1 = seq.getCoordinate(index);
37778 var midPt = new Coordinate((p0.x + p1.x) / 2, (p0.y + p1.y) / 2);
37779 this._minPtDist.initialize();
37780 DistanceToPointFinder.computeDistance(this._geom, midPt, this._minPtDist);
37781 this._maxPtDist.setMaximum(this._minPtDist);
37782};
37783MaxMidpointDistanceFilter.prototype.isDone = function isDone () {
37784 return false
37785};
37786MaxMidpointDistanceFilter.prototype.isGeometryChanged = function isGeometryChanged () {
37787 return false
37788};
37789MaxMidpointDistanceFilter.prototype.getMaxPointDistance = function getMaxPointDistance () {
37790 return this._maxPtDist
37791};
37792MaxMidpointDistanceFilter.prototype.interfaces_ = function interfaces_ () {
37793 return [CoordinateSequenceFilter]
37794};
37795MaxMidpointDistanceFilter.prototype.getClass = function getClass () {
37796 return MaxMidpointDistanceFilter
37797};
37798
37799var PolygonExtracter = function PolygonExtracter (comps) {
37800 this._comps = comps || null;
37801};
37802PolygonExtracter.prototype.filter = function filter (geom) {
37803 if (geom instanceof Polygon) { this._comps.add(geom); }
37804};
37805PolygonExtracter.prototype.interfaces_ = function interfaces_ () {
37806 return [GeometryFilter]
37807};
37808PolygonExtracter.prototype.getClass = function getClass () {
37809 return PolygonExtracter
37810};
37811PolygonExtracter.getPolygons = function getPolygons () {
37812 if (arguments.length === 1) {
37813 var geom = arguments[0];
37814 return PolygonExtracter.getPolygons(geom, new ArrayList())
37815 } else if (arguments.length === 2) {
37816 var geom$1 = arguments[0];
37817 var list = arguments[1];
37818 if (geom$1 instanceof Polygon) {
37819 list.add(geom$1);
37820 } else if (geom$1 instanceof GeometryCollection) {
37821 geom$1.apply(new PolygonExtracter(list));
37822 }
37823 return list
37824 }
37825};
37826
37827var LinearComponentExtracter = function LinearComponentExtracter () {
37828 this._lines = null;
37829 this._isForcedToLineString = false;
37830 if (arguments.length === 1) {
37831 var lines = arguments[0];
37832 this._lines = lines;
37833 } else if (arguments.length === 2) {
37834 var lines$1 = arguments[0];
37835 var isForcedToLineString = arguments[1];
37836 this._lines = lines$1;
37837 this._isForcedToLineString = isForcedToLineString;
37838 }
37839};
37840LinearComponentExtracter.prototype.filter = function filter (geom) {
37841 if (this._isForcedToLineString && geom instanceof LinearRing) {
37842 var line = geom.getFactory().createLineString(geom.getCoordinateSequence());
37843 this._lines.add(line);
37844 return null
37845 }
37846 if (geom instanceof LineString$1) { this._lines.add(geom); }
37847};
37848LinearComponentExtracter.prototype.setForceToLineString = function setForceToLineString (isForcedToLineString) {
37849 this._isForcedToLineString = isForcedToLineString;
37850};
37851LinearComponentExtracter.prototype.interfaces_ = function interfaces_ () {
37852 return [GeometryComponentFilter]
37853};
37854LinearComponentExtracter.prototype.getClass = function getClass () {
37855 return LinearComponentExtracter
37856};
37857LinearComponentExtracter.getGeometry = function getGeometry () {
37858 if (arguments.length === 1) {
37859 var geom = arguments[0];
37860 return geom.getFactory().buildGeometry(LinearComponentExtracter.getLines(geom))
37861 } else if (arguments.length === 2) {
37862 var geom$1 = arguments[0];
37863 var forceToLineString = arguments[1];
37864 return geom$1.getFactory().buildGeometry(LinearComponentExtracter.getLines(geom$1, forceToLineString))
37865 }
37866};
37867LinearComponentExtracter.getLines = function getLines () {
37868 if (arguments.length === 1) {
37869 var geom = arguments[0];
37870 return LinearComponentExtracter.getLines(geom, false)
37871 } else if (arguments.length === 2) {
37872 if (hasInterface(arguments[0], Collection) && hasInterface(arguments[1], Collection)) {
37873 var geoms = arguments[0];
37874 var lines$1 = arguments[1];
37875 for (var i = geoms.iterator(); i.hasNext();) {
37876 var g = i.next();
37877 LinearComponentExtracter.getLines(g, lines$1);
37878 }
37879 return lines$1
37880 } else if (arguments[0] instanceof Geometry && typeof arguments[1] === 'boolean') {
37881 var geom$1 = arguments[0];
37882 var forceToLineString = arguments[1];
37883 var lines = new ArrayList();
37884 geom$1.apply(new LinearComponentExtracter(lines, forceToLineString));
37885 return lines
37886 } else if (arguments[0] instanceof Geometry && hasInterface(arguments[1], Collection)) {
37887 var geom$2 = arguments[0];
37888 var lines$2 = arguments[1];
37889 if (geom$2 instanceof LineString$1) {
37890 lines$2.add(geom$2);
37891 } else {
37892 geom$2.apply(new LinearComponentExtracter(lines$2));
37893 }
37894 return lines$2
37895 }
37896 } else if (arguments.length === 3) {
37897 if (typeof arguments[2] === 'boolean' && (hasInterface(arguments[0], Collection) && hasInterface(arguments[1], Collection))) {
37898 var geoms$1 = arguments[0];
37899 var lines$3 = arguments[1];
37900 var forceToLineString$1 = arguments[2];
37901 for (var i$1 = geoms$1.iterator(); i$1.hasNext();) {
37902 var g$1 = i$1.next();
37903 LinearComponentExtracter.getLines(g$1, lines$3, forceToLineString$1);
37904 }
37905 return lines$3
37906 } else if (typeof arguments[2] === 'boolean' && (arguments[0] instanceof Geometry && hasInterface(arguments[1], Collection))) {
37907 var geom$3 = arguments[0];
37908 var lines$4 = arguments[1];
37909 var forceToLineString$2 = arguments[2];
37910 geom$3.apply(new LinearComponentExtracter(lines$4, forceToLineString$2));
37911 return lines$4
37912 }
37913 }
37914};
37915
37916var PointLocator = function PointLocator () {
37917 this._boundaryRule = BoundaryNodeRule.OGC_SFS_BOUNDARY_RULE;
37918 this._isIn = null;
37919 this._numBoundaries = null;
37920 if (arguments.length === 0) {} else if (arguments.length === 1) {
37921 var boundaryRule = arguments[0];
37922 if (boundaryRule === null) { throw new IllegalArgumentException('Rule must be non-null') }
37923 this._boundaryRule = boundaryRule;
37924 }
37925};
37926PointLocator.prototype.locateInternal = function locateInternal () {
37927 var this$1 = this;
37928
37929 if (arguments[0] instanceof Coordinate && arguments[1] instanceof Polygon) {
37930 var p = arguments[0];
37931 var poly = arguments[1];
37932 if (poly.isEmpty()) { return Location.EXTERIOR }
37933 var shell = poly.getExteriorRing();
37934 var shellLoc = this.locateInPolygonRing(p, shell);
37935 if (shellLoc === Location.EXTERIOR) { return Location.EXTERIOR }
37936 if (shellLoc === Location.BOUNDARY) { return Location.BOUNDARY }
37937 for (var i = 0; i < poly.getNumInteriorRing(); i++) {
37938 var hole = poly.getInteriorRingN(i);
37939 var holeLoc = this$1.locateInPolygonRing(p, hole);
37940 if (holeLoc === Location.INTERIOR) { return Location.EXTERIOR }
37941 if (holeLoc === Location.BOUNDARY) { return Location.BOUNDARY }
37942 }
37943 return Location.INTERIOR
37944 } else if (arguments[0] instanceof Coordinate && arguments[1] instanceof LineString$1) {
37945 var p$1 = arguments[0];
37946 var l = arguments[1];
37947 if (!l.getEnvelopeInternal().intersects(p$1)) { return Location.EXTERIOR }
37948 var pt = l.getCoordinates();
37949 if (!l.isClosed()) {
37950 if (p$1.equals(pt[0]) || p$1.equals(pt[pt.length - 1])) {
37951 return Location.BOUNDARY
37952 }
37953 }
37954 if (CGAlgorithms.isOnLine(p$1, pt)) { return Location.INTERIOR }
37955 return Location.EXTERIOR
37956 } else if (arguments[0] instanceof Coordinate && arguments[1] instanceof Point) {
37957 var p$2 = arguments[0];
37958 var pt$1 = arguments[1];
37959 var ptCoord = pt$1.getCoordinate();
37960 if (ptCoord.equals2D(p$2)) { return Location.INTERIOR }
37961 return Location.EXTERIOR
37962 }
37963};
37964PointLocator.prototype.locateInPolygonRing = function locateInPolygonRing (p, ring) {
37965 if (!ring.getEnvelopeInternal().intersects(p)) { return Location.EXTERIOR }
37966 return CGAlgorithms.locatePointInRing(p, ring.getCoordinates())
37967};
37968PointLocator.prototype.intersects = function intersects (p, geom) {
37969 return this.locate(p, geom) !== Location.EXTERIOR
37970};
37971PointLocator.prototype.updateLocationInfo = function updateLocationInfo (loc) {
37972 if (loc === Location.INTERIOR) { this._isIn = true; }
37973 if (loc === Location.BOUNDARY) { this._numBoundaries++; }
37974};
37975PointLocator.prototype.computeLocation = function computeLocation (p, geom) {
37976 var this$1 = this;
37977
37978 if (geom instanceof Point) {
37979 this.updateLocationInfo(this.locateInternal(p, geom));
37980 }
37981 if (geom instanceof LineString$1) {
37982 this.updateLocationInfo(this.locateInternal(p, geom));
37983 } else if (geom instanceof Polygon) {
37984 this.updateLocationInfo(this.locateInternal(p, geom));
37985 } else if (geom instanceof MultiLineString) {
37986 var ml = geom;
37987 for (var i = 0; i < ml.getNumGeometries(); i++) {
37988 var l = ml.getGeometryN(i);
37989 this$1.updateLocationInfo(this$1.locateInternal(p, l));
37990 }
37991 } else if (geom instanceof MultiPolygon) {
37992 var mpoly = geom;
37993 for (var i$1 = 0; i$1 < mpoly.getNumGeometries(); i$1++) {
37994 var poly = mpoly.getGeometryN(i$1);
37995 this$1.updateLocationInfo(this$1.locateInternal(p, poly));
37996 }
37997 } else if (geom instanceof GeometryCollection) {
37998 var geomi = new GeometryCollectionIterator(geom);
37999 while (geomi.hasNext()) {
38000 var g2 = geomi.next();
38001 if (g2 !== geom) { this$1.computeLocation(p, g2); }
38002 }
38003 }
38004};
38005PointLocator.prototype.locate = function locate (p, geom) {
38006 if (geom.isEmpty()) { return Location.EXTERIOR }
38007 if (geom instanceof LineString$1) {
38008 return this.locateInternal(p, geom)
38009 } else if (geom instanceof Polygon) {
38010 return this.locateInternal(p, geom)
38011 }
38012 this._isIn = false;
38013 this._numBoundaries = 0;
38014 this.computeLocation(p, geom);
38015 if (this._boundaryRule.isInBoundary(this._numBoundaries)) { return Location.BOUNDARY }
38016 if (this._numBoundaries > 0 || this._isIn) { return Location.INTERIOR }
38017 return Location.EXTERIOR
38018};
38019PointLocator.prototype.interfaces_ = function interfaces_ () {
38020 return []
38021};
38022PointLocator.prototype.getClass = function getClass () {
38023 return PointLocator
38024};
38025
38026var GeometryLocation = function GeometryLocation () {
38027 this._component = null;
38028 this._segIndex = null;
38029 this._pt = null;
38030 if (arguments.length === 2) {
38031 var component = arguments[0];
38032 var pt = arguments[1];
38033 GeometryLocation.call(this, component, GeometryLocation.INSIDE_AREA, pt);
38034 } else if (arguments.length === 3) {
38035 var component$1 = arguments[0];
38036 var segIndex = arguments[1];
38037 var pt$1 = arguments[2];
38038 this._component = component$1;
38039 this._segIndex = segIndex;
38040 this._pt = pt$1;
38041 }
38042};
38043
38044var staticAccessors$38 = { INSIDE_AREA: { configurable: true } };
38045GeometryLocation.prototype.isInsideArea = function isInsideArea () {
38046 return this._segIndex === GeometryLocation.INSIDE_AREA
38047};
38048GeometryLocation.prototype.getCoordinate = function getCoordinate () {
38049 return this._pt
38050};
38051GeometryLocation.prototype.getGeometryComponent = function getGeometryComponent () {
38052 return this._component
38053};
38054GeometryLocation.prototype.getSegmentIndex = function getSegmentIndex () {
38055 return this._segIndex
38056};
38057GeometryLocation.prototype.interfaces_ = function interfaces_ () {
38058 return []
38059};
38060GeometryLocation.prototype.getClass = function getClass () {
38061 return GeometryLocation
38062};
38063staticAccessors$38.INSIDE_AREA.get = function () { return -1 };
38064
38065Object.defineProperties( GeometryLocation, staticAccessors$38 );
38066
38067var PointExtracter = function PointExtracter (pts) {
38068 this._pts = pts || null;
38069};
38070PointExtracter.prototype.filter = function filter (geom) {
38071 if (geom instanceof Point) { this._pts.add(geom); }
38072};
38073PointExtracter.prototype.interfaces_ = function interfaces_ () {
38074 return [GeometryFilter]
38075};
38076PointExtracter.prototype.getClass = function getClass () {
38077 return PointExtracter
38078};
38079PointExtracter.getPoints = function getPoints () {
38080 if (arguments.length === 1) {
38081 var geom = arguments[0];
38082 if (geom instanceof Point) {
38083 return Collections.singletonList(geom)
38084 }
38085 return PointExtracter.getPoints(geom, new ArrayList())
38086 } else if (arguments.length === 2) {
38087 var geom$1 = arguments[0];
38088 var list = arguments[1];
38089 if (geom$1 instanceof Point) {
38090 list.add(geom$1);
38091 } else if (geom$1 instanceof GeometryCollection) {
38092 geom$1.apply(new PointExtracter(list));
38093 }
38094 return list
38095 }
38096};
38097
38098var ConnectedElementLocationFilter = function ConnectedElementLocationFilter () {
38099 this._locations = null;
38100 var locations = arguments[0];
38101 this._locations = locations;
38102};
38103ConnectedElementLocationFilter.prototype.filter = function filter (geom) {
38104 if (geom instanceof Point || geom instanceof LineString$1 || geom instanceof Polygon) { this._locations.add(new GeometryLocation(geom, 0, geom.getCoordinate())); }
38105};
38106ConnectedElementLocationFilter.prototype.interfaces_ = function interfaces_ () {
38107 return [GeometryFilter]
38108};
38109ConnectedElementLocationFilter.prototype.getClass = function getClass () {
38110 return ConnectedElementLocationFilter
38111};
38112ConnectedElementLocationFilter.getLocations = function getLocations (geom) {
38113 var locations = new ArrayList();
38114 geom.apply(new ConnectedElementLocationFilter(locations));
38115 return locations
38116};
38117
38118var DistanceOp = function DistanceOp () {
38119 this._geom = null;
38120 this._terminateDistance = 0.0;
38121 this._ptLocator = new PointLocator();
38122 this._minDistanceLocation = null;
38123 this._minDistance = Double.MAX_VALUE;
38124 if (arguments.length === 2) {
38125 var g0 = arguments[0];
38126 var g1 = arguments[1];
38127 this._geom = [g0, g1];
38128 this._terminateDistance = 0.0;
38129 } else if (arguments.length === 3) {
38130 var g0$1 = arguments[0];
38131 var g1$1 = arguments[1];
38132 var terminateDistance = arguments[2];
38133 this._geom = new Array(2).fill(null);
38134 this._geom[0] = g0$1;
38135 this._geom[1] = g1$1;
38136 this._terminateDistance = terminateDistance;
38137 }
38138};
38139DistanceOp.prototype.computeContainmentDistance = function computeContainmentDistance () {
38140 var this$1 = this;
38141
38142 if (arguments.length === 0) {
38143 var locPtPoly = new Array(2).fill(null);
38144 this.computeContainmentDistance(0, locPtPoly);
38145 if (this._minDistance <= this._terminateDistance) { return null }
38146 this.computeContainmentDistance(1, locPtPoly);
38147 } else if (arguments.length === 2) {
38148 var polyGeomIndex = arguments[0];
38149 var locPtPoly$1 = arguments[1];
38150 var locationsIndex = 1 - polyGeomIndex;
38151 var polys = PolygonExtracter.getPolygons(this._geom[polyGeomIndex]);
38152 if (polys.size() > 0) {
38153 var insideLocs = ConnectedElementLocationFilter.getLocations(this._geom[locationsIndex]);
38154 this.computeContainmentDistance(insideLocs, polys, locPtPoly$1);
38155 if (this._minDistance <= this._terminateDistance) {
38156 this._minDistanceLocation[locationsIndex] = locPtPoly$1[0];
38157 this._minDistanceLocation[polyGeomIndex] = locPtPoly$1[1];
38158 return null
38159 }
38160 }
38161 } else if (arguments.length === 3) {
38162 if (arguments[2] instanceof Array && (hasInterface(arguments[0], List) && hasInterface(arguments[1], List))) {
38163 var locs = arguments[0];
38164 var polys$1 = arguments[1];
38165 var locPtPoly$2 = arguments[2];
38166 for (var i = 0; i < locs.size(); i++) {
38167 var loc = locs.get(i);
38168 for (var j = 0; j < polys$1.size(); j++) {
38169 this$1.computeContainmentDistance(loc, polys$1.get(j), locPtPoly$2);
38170 if (this$1._minDistance <= this$1._terminateDistance) { return null }
38171 }
38172 }
38173 } else if (arguments[2] instanceof Array && (arguments[0] instanceof GeometryLocation && arguments[1] instanceof Polygon)) {
38174 var ptLoc = arguments[0];
38175 var poly = arguments[1];
38176 var locPtPoly$3 = arguments[2];
38177 var pt = ptLoc.getCoordinate();
38178 if (Location.EXTERIOR !== this._ptLocator.locate(pt, poly)) {
38179 this._minDistance = 0.0;
38180 locPtPoly$3[0] = ptLoc;
38181 locPtPoly$3[1] = new GeometryLocation(poly, pt);
38182
38183 return null
38184 }
38185 }
38186 }
38187};
38188DistanceOp.prototype.computeMinDistanceLinesPoints = function computeMinDistanceLinesPoints (lines, points, locGeom) {
38189 var this$1 = this;
38190
38191 for (var i = 0; i < lines.size(); i++) {
38192 var line = lines.get(i);
38193 for (var j = 0; j < points.size(); j++) {
38194 var pt = points.get(j);
38195 this$1.computeMinDistance(line, pt, locGeom);
38196 if (this$1._minDistance <= this$1._terminateDistance) { return null }
38197 }
38198 }
38199};
38200DistanceOp.prototype.computeFacetDistance = function computeFacetDistance () {
38201 var locGeom = new Array(2).fill(null);
38202 var lines0 = LinearComponentExtracter.getLines(this._geom[0]);
38203 var lines1 = LinearComponentExtracter.getLines(this._geom[1]);
38204 var pts0 = PointExtracter.getPoints(this._geom[0]);
38205 var pts1 = PointExtracter.getPoints(this._geom[1]);
38206 this.computeMinDistanceLines(lines0, lines1, locGeom);
38207 this.updateMinDistance(locGeom, false);
38208 if (this._minDistance <= this._terminateDistance) { return null }
38209 locGeom[0] = null;
38210 locGeom[1] = null;
38211 this.computeMinDistanceLinesPoints(lines0, pts1, locGeom);
38212 this.updateMinDistance(locGeom, false);
38213 if (this._minDistance <= this._terminateDistance) { return null }
38214 locGeom[0] = null;
38215 locGeom[1] = null;
38216 this.computeMinDistanceLinesPoints(lines1, pts0, locGeom);
38217 this.updateMinDistance(locGeom, true);
38218 if (this._minDistance <= this._terminateDistance) { return null }
38219 locGeom[0] = null;
38220 locGeom[1] = null;
38221 this.computeMinDistancePoints(pts0, pts1, locGeom);
38222 this.updateMinDistance(locGeom, false);
38223};
38224DistanceOp.prototype.nearestLocations = function nearestLocations () {
38225 this.computeMinDistance();
38226 return this._minDistanceLocation
38227};
38228DistanceOp.prototype.updateMinDistance = function updateMinDistance (locGeom, flip) {
38229 if (locGeom[0] === null) { return null }
38230 if (flip) {
38231 this._minDistanceLocation[0] = locGeom[1];
38232 this._minDistanceLocation[1] = locGeom[0];
38233 } else {
38234 this._minDistanceLocation[0] = locGeom[0];
38235 this._minDistanceLocation[1] = locGeom[1];
38236 }
38237};
38238DistanceOp.prototype.nearestPoints = function nearestPoints () {
38239 this.computeMinDistance();
38240 var nearestPts = [this._minDistanceLocation[0].getCoordinate(), this._minDistanceLocation[1].getCoordinate()];
38241 return nearestPts
38242};
38243DistanceOp.prototype.computeMinDistance = function computeMinDistance () {
38244 var this$1 = this;
38245
38246 if (arguments.length === 0) {
38247 if (this._minDistanceLocation !== null) { return null }
38248 this._minDistanceLocation = new Array(2).fill(null);
38249 this.computeContainmentDistance();
38250 if (this._minDistance <= this._terminateDistance) { return null }
38251 this.computeFacetDistance();
38252 } else if (arguments.length === 3) {
38253 if (arguments[2] instanceof Array && (arguments[0] instanceof LineString$1 && arguments[1] instanceof Point)) {
38254 var line = arguments[0];
38255 var pt = arguments[1];
38256 var locGeom = arguments[2];
38257 if (line.getEnvelopeInternal().distance(pt.getEnvelopeInternal()) > this._minDistance) { return null }
38258 var coord0 = line.getCoordinates();
38259 var coord = pt.getCoordinate();
38260 for (var i = 0; i < coord0.length - 1; i++) {
38261 var dist = CGAlgorithms.distancePointLine(coord, coord0[i], coord0[i + 1]);
38262 if (dist < this$1._minDistance) {
38263 this$1._minDistance = dist;
38264 var seg = new LineSegment(coord0[i], coord0[i + 1]);
38265 var segClosestPoint = seg.closestPoint(coord);
38266 locGeom[0] = new GeometryLocation(line, i, segClosestPoint);
38267 locGeom[1] = new GeometryLocation(pt, 0, coord);
38268 }
38269 if (this$1._minDistance <= this$1._terminateDistance) { return null }
38270 }
38271 } else if (arguments[2] instanceof Array && (arguments[0] instanceof LineString$1 && arguments[1] instanceof LineString$1)) {
38272 var line0 = arguments[0];
38273 var line1 = arguments[1];
38274 var locGeom$1 = arguments[2];
38275 if (line0.getEnvelopeInternal().distance(line1.getEnvelopeInternal()) > this._minDistance) { return null }
38276 var coord0$1 = line0.getCoordinates();
38277 var coord1 = line1.getCoordinates();
38278 for (var i$1 = 0; i$1 < coord0$1.length - 1; i$1++) {
38279 for (var j = 0; j < coord1.length - 1; j++) {
38280 var dist$1 = CGAlgorithms.distanceLineLine(coord0$1[i$1], coord0$1[i$1 + 1], coord1[j], coord1[j + 1]);
38281 if (dist$1 < this$1._minDistance) {
38282 this$1._minDistance = dist$1;
38283 var seg0 = new LineSegment(coord0$1[i$1], coord0$1[i$1 + 1]);
38284 var seg1 = new LineSegment(coord1[j], coord1[j + 1]);
38285 var closestPt = seg0.closestPoints(seg1);
38286 locGeom$1[0] = new GeometryLocation(line0, i$1, closestPt[0]);
38287 locGeom$1[1] = new GeometryLocation(line1, j, closestPt[1]);
38288 }
38289 if (this$1._minDistance <= this$1._terminateDistance) { return null }
38290 }
38291 }
38292 }
38293 }
38294};
38295DistanceOp.prototype.computeMinDistancePoints = function computeMinDistancePoints (points0, points1, locGeom) {
38296 var this$1 = this;
38297
38298 for (var i = 0; i < points0.size(); i++) {
38299 var pt0 = points0.get(i);
38300 for (var j = 0; j < points1.size(); j++) {
38301 var pt1 = points1.get(j);
38302 var dist = pt0.getCoordinate().distance(pt1.getCoordinate());
38303 if (dist < this$1._minDistance) {
38304 this$1._minDistance = dist;
38305 locGeom[0] = new GeometryLocation(pt0, 0, pt0.getCoordinate());
38306 locGeom[1] = new GeometryLocation(pt1, 0, pt1.getCoordinate());
38307 }
38308 if (this$1._minDistance <= this$1._terminateDistance) { return null }
38309 }
38310 }
38311};
38312DistanceOp.prototype.distance = function distance () {
38313 if (this._geom[0] === null || this._geom[1] === null) { throw new IllegalArgumentException('null geometries are not supported') }
38314 if (this._geom[0].isEmpty() || this._geom[1].isEmpty()) { return 0.0 }
38315 this.computeMinDistance();
38316 return this._minDistance
38317};
38318DistanceOp.prototype.computeMinDistanceLines = function computeMinDistanceLines (lines0, lines1, locGeom) {
38319 var this$1 = this;
38320
38321 for (var i = 0; i < lines0.size(); i++) {
38322 var line0 = lines0.get(i);
38323 for (var j = 0; j < lines1.size(); j++) {
38324 var line1 = lines1.get(j);
38325 this$1.computeMinDistance(line0, line1, locGeom);
38326 if (this$1._minDistance <= this$1._terminateDistance) { return null }
38327 }
38328 }
38329};
38330DistanceOp.prototype.interfaces_ = function interfaces_ () {
38331 return []
38332};
38333DistanceOp.prototype.getClass = function getClass () {
38334 return DistanceOp
38335};
38336DistanceOp.distance = function distance (g0, g1) {
38337 var distOp = new DistanceOp(g0, g1);
38338 return distOp.distance()
38339};
38340DistanceOp.isWithinDistance = function isWithinDistance (g0, g1, distance) {
38341 var distOp = new DistanceOp(g0, g1, distance);
38342 return distOp.distance() <= distance
38343};
38344DistanceOp.nearestPoints = function nearestPoints (g0, g1) {
38345 var distOp = new DistanceOp(g0, g1);
38346 return distOp.nearestPoints()
38347};
38348
38349var PointPairDistance$2 = function PointPairDistance () {
38350 this._pt = [new Coordinate(), new Coordinate()];
38351 this._distance = Double.NaN;
38352 this._isNull = true;
38353};
38354PointPairDistance$2.prototype.getCoordinates = function getCoordinates () {
38355 return this._pt
38356};
38357PointPairDistance$2.prototype.getCoordinate = function getCoordinate (i) {
38358 return this._pt[i]
38359};
38360PointPairDistance$2.prototype.setMinimum = function setMinimum () {
38361 if (arguments.length === 1) {
38362 var ptDist = arguments[0];
38363 this.setMinimum(ptDist._pt[0], ptDist._pt[1]);
38364 } else if (arguments.length === 2) {
38365 var p0 = arguments[0];
38366 var p1 = arguments[1];
38367 if (this._isNull) {
38368 this.initialize(p0, p1);
38369 return null
38370 }
38371 var dist = p0.distance(p1);
38372 if (dist < this._distance) { this.initialize(p0, p1, dist); }
38373 }
38374};
38375PointPairDistance$2.prototype.initialize = function initialize () {
38376 if (arguments.length === 0) {
38377 this._isNull = true;
38378 } else if (arguments.length === 2) {
38379 var p0 = arguments[0];
38380 var p1 = arguments[1];
38381 this._pt[0].setCoordinate(p0);
38382 this._pt[1].setCoordinate(p1);
38383 this._distance = p0.distance(p1);
38384 this._isNull = false;
38385 } else if (arguments.length === 3) {
38386 var p0$1 = arguments[0];
38387 var p1$1 = arguments[1];
38388 var distance = arguments[2];
38389 this._pt[0].setCoordinate(p0$1);
38390 this._pt[1].setCoordinate(p1$1);
38391 this._distance = distance;
38392 this._isNull = false;
38393 }
38394};
38395PointPairDistance$2.prototype.toString = function toString () {
38396 return WKTWriter.toLineString(this._pt[0], this._pt[1])
38397};
38398PointPairDistance$2.prototype.getDistance = function getDistance () {
38399 return this._distance
38400};
38401PointPairDistance$2.prototype.setMaximum = function setMaximum () {
38402 if (arguments.length === 1) {
38403 var ptDist = arguments[0];
38404 this.setMaximum(ptDist._pt[0], ptDist._pt[1]);
38405 } else if (arguments.length === 2) {
38406 var p0 = arguments[0];
38407 var p1 = arguments[1];
38408 if (this._isNull) {
38409 this.initialize(p0, p1);
38410 return null
38411 }
38412 var dist = p0.distance(p1);
38413 if (dist > this._distance) { this.initialize(p0, p1, dist); }
38414 }
38415};
38416PointPairDistance$2.prototype.interfaces_ = function interfaces_ () {
38417 return []
38418};
38419PointPairDistance$2.prototype.getClass = function getClass () {
38420 return PointPairDistance$2
38421};
38422
38423var DistanceToPoint = function DistanceToPoint () {};
38424
38425DistanceToPoint.prototype.interfaces_ = function interfaces_ () {
38426 return []
38427};
38428DistanceToPoint.prototype.getClass = function getClass () {
38429 return DistanceToPoint
38430};
38431DistanceToPoint.computeDistance = function computeDistance () {
38432 if (arguments[2] instanceof PointPairDistance$2 && (arguments[0] instanceof LineString$1 && arguments[1] instanceof Coordinate)) {
38433 var line = arguments[0];
38434 var pt = arguments[1];
38435 var ptDist = arguments[2];
38436 var tempSegment = new LineSegment();
38437 var coords = line.getCoordinates();
38438 for (var i = 0; i < coords.length - 1; i++) {
38439 tempSegment.setCoordinates(coords[i], coords[i + 1]);
38440 var closestPt = tempSegment.closestPoint(pt);
38441 ptDist.setMinimum(closestPt, pt);
38442 }
38443 } else if (arguments[2] instanceof PointPairDistance$2 && (arguments[0] instanceof Polygon && arguments[1] instanceof Coordinate)) {
38444 var poly = arguments[0];
38445 var pt$1 = arguments[1];
38446 var ptDist$1 = arguments[2];
38447 DistanceToPoint.computeDistance(poly.getExteriorRing(), pt$1, ptDist$1);
38448 for (var i$1 = 0; i$1 < poly.getNumInteriorRing(); i$1++) {
38449 DistanceToPoint.computeDistance(poly.getInteriorRingN(i$1), pt$1, ptDist$1);
38450 }
38451 } else if (arguments[2] instanceof PointPairDistance$2 && (arguments[0] instanceof Geometry && arguments[1] instanceof Coordinate)) {
38452 var geom = arguments[0];
38453 var pt$2 = arguments[1];
38454 var ptDist$2 = arguments[2];
38455 if (geom instanceof LineString$1) {
38456 DistanceToPoint.computeDistance(geom, pt$2, ptDist$2);
38457 } else if (geom instanceof Polygon) {
38458 DistanceToPoint.computeDistance(geom, pt$2, ptDist$2);
38459 } else if (geom instanceof GeometryCollection) {
38460 var gc = geom;
38461 for (var i$2 = 0; i$2 < gc.getNumGeometries(); i$2++) {
38462 var g = gc.getGeometryN(i$2);
38463 DistanceToPoint.computeDistance(g, pt$2, ptDist$2);
38464 }
38465 } else {
38466 ptDist$2.setMinimum(geom.getCoordinate(), pt$2);
38467 }
38468 } else if (arguments[2] instanceof PointPairDistance$2 && (arguments[0] instanceof LineSegment && arguments[1] instanceof Coordinate)) {
38469 var segment = arguments[0];
38470 var pt$3 = arguments[1];
38471 var ptDist$3 = arguments[2];
38472 var closestPt$1 = segment.closestPoint(pt$3);
38473 ptDist$3.setMinimum(closestPt$1, pt$3);
38474 }
38475};
38476
38477var DiscreteHausdorffDistance = function DiscreteHausdorffDistance () {
38478 this._g0 = null;
38479 this._g1 = null;
38480 this._ptDist = new PointPairDistance$2();
38481 this._densifyFrac = 0.0;
38482 var g0 = arguments[0];
38483 var g1 = arguments[1];
38484 this._g0 = g0;
38485 this._g1 = g1;
38486};
38487
38488var staticAccessors$39 = { MaxPointDistanceFilter: { configurable: true },MaxDensifiedByFractionDistanceFilter: { configurable: true } };
38489DiscreteHausdorffDistance.prototype.getCoordinates = function getCoordinates () {
38490 return this._ptDist.getCoordinates()
38491};
38492DiscreteHausdorffDistance.prototype.setDensifyFraction = function setDensifyFraction (densifyFrac) {
38493 if (densifyFrac > 1.0 || densifyFrac <= 0.0) { throw new IllegalArgumentException('Fraction is not in range (0.0 - 1.0]') }
38494 this._densifyFrac = densifyFrac;
38495};
38496DiscreteHausdorffDistance.prototype.compute = function compute (g0, g1) {
38497 this.computeOrientedDistance(g0, g1, this._ptDist);
38498 this.computeOrientedDistance(g1, g0, this._ptDist);
38499};
38500DiscreteHausdorffDistance.prototype.distance = function distance () {
38501 this.compute(this._g0, this._g1);
38502 return this._ptDist.getDistance()
38503};
38504DiscreteHausdorffDistance.prototype.computeOrientedDistance = function computeOrientedDistance (discreteGeom, geom, ptDist) {
38505 var distFilter = new MaxPointDistanceFilter$1(geom);
38506 discreteGeom.apply(distFilter);
38507 ptDist.setMaximum(distFilter.getMaxPointDistance());
38508 if (this._densifyFrac > 0) {
38509 var fracFilter = new MaxDensifiedByFractionDistanceFilter(geom, this._densifyFrac);
38510 discreteGeom.apply(fracFilter);
38511 ptDist.setMaximum(fracFilter.getMaxPointDistance());
38512 }
38513};
38514DiscreteHausdorffDistance.prototype.orientedDistance = function orientedDistance () {
38515 this.computeOrientedDistance(this._g0, this._g1, this._ptDist);
38516 return this._ptDist.getDistance()
38517};
38518DiscreteHausdorffDistance.prototype.interfaces_ = function interfaces_ () {
38519 return []
38520};
38521DiscreteHausdorffDistance.prototype.getClass = function getClass () {
38522 return DiscreteHausdorffDistance
38523};
38524DiscreteHausdorffDistance.distance = function distance () {
38525 if (arguments.length === 2) {
38526 var g0 = arguments[0];
38527 var g1 = arguments[1];
38528 var dist = new DiscreteHausdorffDistance(g0, g1);
38529 return dist.distance()
38530 } else if (arguments.length === 3) {
38531 var g0$1 = arguments[0];
38532 var g1$1 = arguments[1];
38533 var densifyFrac = arguments[2];
38534 var dist$1 = new DiscreteHausdorffDistance(g0$1, g1$1);
38535 dist$1.setDensifyFraction(densifyFrac);
38536 return dist$1.distance()
38537 }
38538};
38539staticAccessors$39.MaxPointDistanceFilter.get = function () { return MaxPointDistanceFilter$1 };
38540staticAccessors$39.MaxDensifiedByFractionDistanceFilter.get = function () { return MaxDensifiedByFractionDistanceFilter };
38541
38542Object.defineProperties( DiscreteHausdorffDistance, staticAccessors$39 );
38543
38544var MaxPointDistanceFilter$1 = function MaxPointDistanceFilter () {
38545 this._maxPtDist = new PointPairDistance$2();
38546 this._minPtDist = new PointPairDistance$2();
38547 this._euclideanDist = new DistanceToPoint();
38548 this._geom = null;
38549 var geom = arguments[0];
38550 this._geom = geom;
38551};
38552MaxPointDistanceFilter$1.prototype.filter = function filter (pt) {
38553 this._minPtDist.initialize();
38554 DistanceToPoint.computeDistance(this._geom, pt, this._minPtDist);
38555 this._maxPtDist.setMaximum(this._minPtDist);
38556};
38557MaxPointDistanceFilter$1.prototype.getMaxPointDistance = function getMaxPointDistance () {
38558 return this._maxPtDist
38559};
38560MaxPointDistanceFilter$1.prototype.interfaces_ = function interfaces_ () {
38561 return [CoordinateFilter]
38562};
38563MaxPointDistanceFilter$1.prototype.getClass = function getClass () {
38564 return MaxPointDistanceFilter$1
38565};
38566
38567var MaxDensifiedByFractionDistanceFilter = function MaxDensifiedByFractionDistanceFilter () {
38568 this._maxPtDist = new PointPairDistance$2();
38569 this._minPtDist = new PointPairDistance$2();
38570 this._geom = null;
38571 this._numSubSegs = 0;
38572 var geom = arguments[0];
38573 var fraction = arguments[1];
38574 this._geom = geom;
38575 this._numSubSegs = Math.trunc(Math.round(1.0 / fraction));
38576};
38577MaxDensifiedByFractionDistanceFilter.prototype.filter = function filter (seq, index) {
38578 var this$1 = this;
38579
38580 if (index === 0) { return null }
38581 var p0 = seq.getCoordinate(index - 1);
38582 var p1 = seq.getCoordinate(index);
38583 var delx = (p1.x - p0.x) / this._numSubSegs;
38584 var dely = (p1.y - p0.y) / this._numSubSegs;
38585 for (var i = 0; i < this._numSubSegs; i++) {
38586 var x = p0.x + i * delx;
38587 var y = p0.y + i * dely;
38588 var pt = new Coordinate(x, y);
38589 this$1._minPtDist.initialize();
38590 DistanceToPoint.computeDistance(this$1._geom, pt, this$1._minPtDist);
38591 this$1._maxPtDist.setMaximum(this$1._minPtDist);
38592 }
38593};
38594MaxDensifiedByFractionDistanceFilter.prototype.isDone = function isDone () {
38595 return false
38596};
38597MaxDensifiedByFractionDistanceFilter.prototype.isGeometryChanged = function isGeometryChanged () {
38598 return false
38599};
38600MaxDensifiedByFractionDistanceFilter.prototype.getMaxPointDistance = function getMaxPointDistance () {
38601 return this._maxPtDist
38602};
38603MaxDensifiedByFractionDistanceFilter.prototype.interfaces_ = function interfaces_ () {
38604 return [CoordinateSequenceFilter]
38605};
38606MaxDensifiedByFractionDistanceFilter.prototype.getClass = function getClass () {
38607 return MaxDensifiedByFractionDistanceFilter
38608};
38609
38610var BufferDistanceValidator = function BufferDistanceValidator (input, bufDistance, result) {
38611 this._minValidDistance = null;
38612 this._maxValidDistance = null;
38613 this._minDistanceFound = null;
38614 this._maxDistanceFound = null;
38615 this._isValid = true;
38616 this._errMsg = null;
38617 this._errorLocation = null;
38618 this._errorIndicator = null;
38619 this._input = input || null;
38620 this._bufDistance = bufDistance || null;
38621 this._result = result || null;
38622};
38623
38624var staticAccessors$37 = { VERBOSE: { configurable: true },MAX_DISTANCE_DIFF_FRAC: { configurable: true } };
38625BufferDistanceValidator.prototype.checkMaximumDistance = function checkMaximumDistance (input, bufCurve, maxDist) {
38626 var haus = new DiscreteHausdorffDistance(bufCurve, input);
38627 haus.setDensifyFraction(0.25);
38628 this._maxDistanceFound = haus.orientedDistance();
38629 if (this._maxDistanceFound > maxDist) {
38630 this._isValid = false;
38631 var pts = haus.getCoordinates();
38632 this._errorLocation = pts[1];
38633 this._errorIndicator = input.getFactory().createLineString(pts);
38634 this._errMsg = 'Distance between buffer curve and input is too large (' + this._maxDistanceFound + ' at ' + WKTWriter.toLineString(pts[0], pts[1]) + ')';
38635 }
38636};
38637BufferDistanceValidator.prototype.isValid = function isValid () {
38638 var posDistance = Math.abs(this._bufDistance);
38639 var distDelta = BufferDistanceValidator.MAX_DISTANCE_DIFF_FRAC * posDistance;
38640 this._minValidDistance = posDistance - distDelta;
38641 this._maxValidDistance = posDistance + distDelta;
38642 if (this._input.isEmpty() || this._result.isEmpty()) { return true }
38643 if (this._bufDistance > 0.0) {
38644 this.checkPositiveValid();
38645 } else {
38646 this.checkNegativeValid();
38647 }
38648 if (BufferDistanceValidator.VERBOSE) {
38649 System.out.println('Min Dist= ' + this._minDistanceFound + ' err= ' + (1.0 - this._minDistanceFound / this._bufDistance) + ' Max Dist= ' + this._maxDistanceFound + ' err= ' + (this._maxDistanceFound / this._bufDistance - 1.0));
38650 }
38651 return this._isValid
38652};
38653BufferDistanceValidator.prototype.checkNegativeValid = function checkNegativeValid () {
38654 if (!(this._input instanceof Polygon || this._input instanceof MultiPolygon || this._input instanceof GeometryCollection)) {
38655 return null
38656 }
38657 var inputCurve = this.getPolygonLines(this._input);
38658 this.checkMinimumDistance(inputCurve, this._result, this._minValidDistance);
38659 if (!this._isValid) { return null }
38660 this.checkMaximumDistance(inputCurve, this._result, this._maxValidDistance);
38661};
38662BufferDistanceValidator.prototype.getErrorIndicator = function getErrorIndicator () {
38663 return this._errorIndicator
38664};
38665BufferDistanceValidator.prototype.checkMinimumDistance = function checkMinimumDistance (g1, g2, minDist) {
38666 var distOp = new DistanceOp(g1, g2, minDist);
38667 this._minDistanceFound = distOp.distance();
38668 if (this._minDistanceFound < minDist) {
38669 this._isValid = false;
38670 var pts = distOp.nearestPoints();
38671 this._errorLocation = distOp.nearestPoints()[1];
38672 this._errorIndicator = g1.getFactory().createLineString(pts);
38673 this._errMsg = 'Distance between buffer curve and input is too small (' + this._minDistanceFound + ' at ' + WKTWriter.toLineString(pts[0], pts[1]) + ' )';
38674 }
38675};
38676BufferDistanceValidator.prototype.checkPositiveValid = function checkPositiveValid () {
38677 var bufCurve = this._result.getBoundary();
38678 this.checkMinimumDistance(this._input, bufCurve, this._minValidDistance);
38679 if (!this._isValid) { return null }
38680 this.checkMaximumDistance(this._input, bufCurve, this._maxValidDistance);
38681};
38682BufferDistanceValidator.prototype.getErrorLocation = function getErrorLocation () {
38683 return this._errorLocation
38684};
38685BufferDistanceValidator.prototype.getPolygonLines = function getPolygonLines (g) {
38686 var lines = new ArrayList();
38687 var lineExtracter = new LinearComponentExtracter(lines);
38688 var polys = PolygonExtracter.getPolygons(g);
38689 for (var i = polys.iterator(); i.hasNext();) {
38690 var poly = i.next();
38691 poly.apply(lineExtracter);
38692 }
38693 return g.getFactory().buildGeometry(lines)
38694};
38695BufferDistanceValidator.prototype.getErrorMessage = function getErrorMessage () {
38696 return this._errMsg
38697};
38698BufferDistanceValidator.prototype.interfaces_ = function interfaces_ () {
38699 return []
38700};
38701BufferDistanceValidator.prototype.getClass = function getClass () {
38702 return BufferDistanceValidator
38703};
38704staticAccessors$37.VERBOSE.get = function () { return false };
38705staticAccessors$37.MAX_DISTANCE_DIFF_FRAC.get = function () { return 0.012 };
38706
38707Object.defineProperties( BufferDistanceValidator, staticAccessors$37 );
38708
38709var BufferResultValidator = function BufferResultValidator (input, distance, result) {
38710 this._isValid = true;
38711 this._errorMsg = null;
38712 this._errorLocation = null;
38713 this._errorIndicator = null;
38714 this._input = input || null;
38715 this._distance = distance || null;
38716 this._result = result || null;
38717};
38718
38719var staticAccessors$40 = { VERBOSE: { configurable: true },MAX_ENV_DIFF_FRAC: { configurable: true } };
38720BufferResultValidator.prototype.isValid = function isValid () {
38721 this.checkPolygonal();
38722 if (!this._isValid) { return this._isValid }
38723 this.checkExpectedEmpty();
38724 if (!this._isValid) { return this._isValid }
38725 this.checkEnvelope();
38726 if (!this._isValid) { return this._isValid }
38727 this.checkArea();
38728 if (!this._isValid) { return this._isValid }
38729 this.checkDistance();
38730 return this._isValid
38731};
38732BufferResultValidator.prototype.checkEnvelope = function checkEnvelope () {
38733 if (this._distance < 0.0) { return null }
38734 var padding = this._distance * BufferResultValidator.MAX_ENV_DIFF_FRAC;
38735 if (padding === 0.0) { padding = 0.001; }
38736 var expectedEnv = new Envelope(this._input.getEnvelopeInternal());
38737 expectedEnv.expandBy(this._distance);
38738 var bufEnv = new Envelope(this._result.getEnvelopeInternal());
38739 bufEnv.expandBy(padding);
38740 if (!bufEnv.contains(expectedEnv)) {
38741 this._isValid = false;
38742 this._errorMsg = 'Buffer envelope is incorrect';
38743 this._errorIndicator = this._input.getFactory().toGeometry(bufEnv);
38744 }
38745 this.report('Envelope');
38746};
38747BufferResultValidator.prototype.checkDistance = function checkDistance () {
38748 var distValid = new BufferDistanceValidator(this._input, this._distance, this._result);
38749 if (!distValid.isValid()) {
38750 this._isValid = false;
38751 this._errorMsg = distValid.getErrorMessage();
38752 this._errorLocation = distValid.getErrorLocation();
38753 this._errorIndicator = distValid.getErrorIndicator();
38754 }
38755 this.report('Distance');
38756};
38757BufferResultValidator.prototype.checkArea = function checkArea () {
38758 var inputArea = this._input.getArea();
38759 var resultArea = this._result.getArea();
38760 if (this._distance > 0.0 && inputArea > resultArea) {
38761 this._isValid = false;
38762 this._errorMsg = 'Area of positive buffer is smaller than input';
38763 this._errorIndicator = this._result;
38764 }
38765 if (this._distance < 0.0 && inputArea < resultArea) {
38766 this._isValid = false;
38767 this._errorMsg = 'Area of negative buffer is larger than input';
38768 this._errorIndicator = this._result;
38769 }
38770 this.report('Area');
38771};
38772BufferResultValidator.prototype.checkPolygonal = function checkPolygonal () {
38773 if (!(this._result instanceof Polygon || this._result instanceof MultiPolygon)) { this._isValid = false; }
38774 this._errorMsg = 'Result is not polygonal';
38775 this._errorIndicator = this._result;
38776 this.report('Polygonal');
38777};
38778BufferResultValidator.prototype.getErrorIndicator = function getErrorIndicator () {
38779 return this._errorIndicator
38780};
38781BufferResultValidator.prototype.getErrorLocation = function getErrorLocation () {
38782 return this._errorLocation
38783};
38784BufferResultValidator.prototype.checkExpectedEmpty = function checkExpectedEmpty () {
38785 if (this._input.getDimension() >= 2) { return null }
38786 if (this._distance > 0.0) { return null }
38787 if (!this._result.isEmpty()) {
38788 this._isValid = false;
38789 this._errorMsg = 'Result is non-empty';
38790 this._errorIndicator = this._result;
38791 }
38792 this.report('ExpectedEmpty');
38793};
38794BufferResultValidator.prototype.report = function report (checkName) {
38795 if (!BufferResultValidator.VERBOSE) { return null }
38796 System.out.println('Check ' + checkName + ': ' + (this._isValid ? 'passed' : 'FAILED'));
38797};
38798BufferResultValidator.prototype.getErrorMessage = function getErrorMessage () {
38799 return this._errorMsg
38800};
38801BufferResultValidator.prototype.interfaces_ = function interfaces_ () {
38802 return []
38803};
38804BufferResultValidator.prototype.getClass = function getClass () {
38805 return BufferResultValidator
38806};
38807BufferResultValidator.isValidMsg = function isValidMsg (g, distance, result) {
38808 var validator = new BufferResultValidator(g, distance, result);
38809 if (!validator.isValid()) { return validator.getErrorMessage() }
38810 return null
38811};
38812BufferResultValidator.isValid = function isValid (g, distance, result) {
38813 var validator = new BufferResultValidator(g, distance, result);
38814 if (validator.isValid()) { return true }
38815 return false
38816};
38817staticAccessors$40.VERBOSE.get = function () { return false };
38818staticAccessors$40.MAX_ENV_DIFF_FRAC.get = function () { return 0.012 };
38819
38820Object.defineProperties( BufferResultValidator, staticAccessors$40 );
38821
38822// operation.buffer
38823
38824var BasicSegmentString = function BasicSegmentString () {
38825 this._pts = null;
38826 this._data = null;
38827 var pts = arguments[0];
38828 var data = arguments[1];
38829 this._pts = pts;
38830 this._data = data;
38831};
38832BasicSegmentString.prototype.getCoordinates = function getCoordinates () {
38833 return this._pts
38834};
38835BasicSegmentString.prototype.size = function size () {
38836 return this._pts.length
38837};
38838BasicSegmentString.prototype.getCoordinate = function getCoordinate (i) {
38839 return this._pts[i]
38840};
38841BasicSegmentString.prototype.isClosed = function isClosed () {
38842 return this._pts[0].equals(this._pts[this._pts.length - 1])
38843};
38844BasicSegmentString.prototype.getSegmentOctant = function getSegmentOctant (index) {
38845 if (index === this._pts.length - 1) { return -1 }
38846 return Octant.octant(this.getCoordinate(index), this.getCoordinate(index + 1))
38847};
38848BasicSegmentString.prototype.setData = function setData (data) {
38849 this._data = data;
38850};
38851BasicSegmentString.prototype.getData = function getData () {
38852 return this._data
38853};
38854BasicSegmentString.prototype.toString = function toString () {
38855 return WKTWriter.toLineString(new CoordinateArraySequence(this._pts))
38856};
38857BasicSegmentString.prototype.interfaces_ = function interfaces_ () {
38858 return [SegmentString]
38859};
38860BasicSegmentString.prototype.getClass = function getClass () {
38861 return BasicSegmentString
38862};
38863
38864var InteriorIntersectionFinder = function InteriorIntersectionFinder () {
38865 this._findAllIntersections = false;
38866 this._isCheckEndSegmentsOnly = false;
38867 this._li = null;
38868 this._interiorIntersection = null;
38869 this._intSegments = null;
38870 this._intersections = new ArrayList();
38871 this._intersectionCount = 0;
38872 this._keepIntersections = true;
38873 var li = arguments[0];
38874 this._li = li;
38875 this._interiorIntersection = null;
38876};
38877InteriorIntersectionFinder.prototype.getInteriorIntersection = function getInteriorIntersection () {
38878 return this._interiorIntersection
38879};
38880InteriorIntersectionFinder.prototype.setCheckEndSegmentsOnly = function setCheckEndSegmentsOnly (isCheckEndSegmentsOnly) {
38881 this._isCheckEndSegmentsOnly = isCheckEndSegmentsOnly;
38882};
38883InteriorIntersectionFinder.prototype.getIntersectionSegments = function getIntersectionSegments () {
38884 return this._intSegments
38885};
38886InteriorIntersectionFinder.prototype.count = function count () {
38887 return this._intersectionCount
38888};
38889InteriorIntersectionFinder.prototype.getIntersections = function getIntersections () {
38890 return this._intersections
38891};
38892InteriorIntersectionFinder.prototype.setFindAllIntersections = function setFindAllIntersections (findAllIntersections) {
38893 this._findAllIntersections = findAllIntersections;
38894};
38895InteriorIntersectionFinder.prototype.setKeepIntersections = function setKeepIntersections (keepIntersections) {
38896 this._keepIntersections = keepIntersections;
38897};
38898InteriorIntersectionFinder.prototype.processIntersections = function processIntersections (e0, segIndex0, e1, segIndex1) {
38899 if (!this._findAllIntersections && this.hasIntersection()) { return null }
38900 if (e0 === e1 && segIndex0 === segIndex1) { return null }
38901 if (this._isCheckEndSegmentsOnly) {
38902 var isEndSegPresent = this.isEndSegment(e0, segIndex0) || this.isEndSegment(e1, segIndex1);
38903 if (!isEndSegPresent) { return null }
38904 }
38905 var p00 = e0.getCoordinates()[segIndex0];
38906 var p01 = e0.getCoordinates()[segIndex0 + 1];
38907 var p10 = e1.getCoordinates()[segIndex1];
38908 var p11 = e1.getCoordinates()[segIndex1 + 1];
38909 this._li.computeIntersection(p00, p01, p10, p11);
38910 if (this._li.hasIntersection()) {
38911 if (this._li.isInteriorIntersection()) {
38912 this._intSegments = new Array(4).fill(null);
38913 this._intSegments[0] = p00;
38914 this._intSegments[1] = p01;
38915 this._intSegments[2] = p10;
38916 this._intSegments[3] = p11;
38917 this._interiorIntersection = this._li.getIntersection(0);
38918 if (this._keepIntersections) { this._intersections.add(this._interiorIntersection); }
38919 this._intersectionCount++;
38920 }
38921 }
38922};
38923InteriorIntersectionFinder.prototype.isEndSegment = function isEndSegment (segStr, index) {
38924 if (index === 0) { return true }
38925 if (index >= segStr.size() - 2) { return true }
38926 return false
38927};
38928InteriorIntersectionFinder.prototype.hasIntersection = function hasIntersection () {
38929 return this._interiorIntersection !== null
38930};
38931InteriorIntersectionFinder.prototype.isDone = function isDone () {
38932 if (this._findAllIntersections) { return false }
38933 return this._interiorIntersection !== null
38934};
38935InteriorIntersectionFinder.prototype.interfaces_ = function interfaces_ () {
38936 return [SegmentIntersector]
38937};
38938InteriorIntersectionFinder.prototype.getClass = function getClass () {
38939 return InteriorIntersectionFinder
38940};
38941InteriorIntersectionFinder.createAllIntersectionsFinder = function createAllIntersectionsFinder (li) {
38942 var finder = new InteriorIntersectionFinder(li);
38943 finder.setFindAllIntersections(true);
38944 return finder
38945};
38946InteriorIntersectionFinder.createAnyIntersectionFinder = function createAnyIntersectionFinder (li) {
38947 return new InteriorIntersectionFinder(li)
38948};
38949InteriorIntersectionFinder.createIntersectionCounter = function createIntersectionCounter (li) {
38950 var finder = new InteriorIntersectionFinder(li);
38951 finder.setFindAllIntersections(true);
38952 finder.setKeepIntersections(false);
38953 return finder
38954};
38955
38956var FastNodingValidator = function FastNodingValidator () {
38957 this._li = new RobustLineIntersector();
38958 this._segStrings = null;
38959 this._findAllIntersections = false;
38960 this._segInt = null;
38961 this._isValid = true;
38962 var segStrings = arguments[0];
38963 this._segStrings = segStrings;
38964};
38965FastNodingValidator.prototype.execute = function execute () {
38966 if (this._segInt !== null) { return null }
38967 this.checkInteriorIntersections();
38968};
38969FastNodingValidator.prototype.getIntersections = function getIntersections () {
38970 return this._segInt.getIntersections()
38971};
38972FastNodingValidator.prototype.isValid = function isValid () {
38973 this.execute();
38974 return this._isValid
38975};
38976FastNodingValidator.prototype.setFindAllIntersections = function setFindAllIntersections (findAllIntersections) {
38977 this._findAllIntersections = findAllIntersections;
38978};
38979FastNodingValidator.prototype.checkInteriorIntersections = function checkInteriorIntersections () {
38980 this._isValid = true;
38981 this._segInt = new InteriorIntersectionFinder(this._li);
38982 this._segInt.setFindAllIntersections(this._findAllIntersections);
38983 var noder = new MCIndexNoder();
38984 noder.setSegmentIntersector(this._segInt);
38985 noder.computeNodes(this._segStrings);
38986 if (this._segInt.hasIntersection()) {
38987 this._isValid = false;
38988 return null
38989 }
38990};
38991FastNodingValidator.prototype.checkValid = function checkValid () {
38992 this.execute();
38993 if (!this._isValid) { throw new TopologyException(this.getErrorMessage(), this._segInt.getInteriorIntersection()) }
38994};
38995FastNodingValidator.prototype.getErrorMessage = function getErrorMessage () {
38996 if (this._isValid) { return 'no intersections found' }
38997 var intSegs = this._segInt.getIntersectionSegments();
38998 return 'found non-noded intersection between ' + WKTWriter.toLineString(intSegs[0], intSegs[1]) + ' and ' + WKTWriter.toLineString(intSegs[2], intSegs[3])
38999};
39000FastNodingValidator.prototype.interfaces_ = function interfaces_ () {
39001 return []
39002};
39003FastNodingValidator.prototype.getClass = function getClass () {
39004 return FastNodingValidator
39005};
39006FastNodingValidator.computeIntersections = function computeIntersections (segStrings) {
39007 var nv = new FastNodingValidator(segStrings);
39008 nv.setFindAllIntersections(true);
39009 nv.isValid();
39010 return nv.getIntersections()
39011};
39012
39013var EdgeNodingValidator = function EdgeNodingValidator () {
39014 this._nv = null;
39015 var edges = arguments[0];
39016 this._nv = new FastNodingValidator(EdgeNodingValidator.toSegmentStrings(edges));
39017};
39018EdgeNodingValidator.prototype.checkValid = function checkValid () {
39019 this._nv.checkValid();
39020};
39021EdgeNodingValidator.prototype.interfaces_ = function interfaces_ () {
39022 return []
39023};
39024EdgeNodingValidator.prototype.getClass = function getClass () {
39025 return EdgeNodingValidator
39026};
39027EdgeNodingValidator.toSegmentStrings = function toSegmentStrings (edges) {
39028 var segStrings = new ArrayList();
39029 for (var i = edges.iterator(); i.hasNext();) {
39030 var e = i.next();
39031 segStrings.add(new BasicSegmentString(e.getCoordinates(), e));
39032 }
39033 return segStrings
39034};
39035EdgeNodingValidator.checkValid = function checkValid (edges) {
39036 var validator = new EdgeNodingValidator(edges);
39037 validator.checkValid();
39038};
39039
39040var GeometryCollectionMapper = function GeometryCollectionMapper (mapOp) {
39041 this._mapOp = mapOp;
39042};
39043GeometryCollectionMapper.prototype.map = function map (gc) {
39044 var this$1 = this;
39045
39046 var mapped = new ArrayList();
39047 for (var i = 0; i < gc.getNumGeometries(); i++) {
39048 var g = this$1._mapOp.map(gc.getGeometryN(i));
39049 if (!g.isEmpty()) { mapped.add(g); }
39050 }
39051 return gc.getFactory().createGeometryCollection(GeometryFactory.toGeometryArray(mapped))
39052};
39053GeometryCollectionMapper.prototype.interfaces_ = function interfaces_ () {
39054 return []
39055};
39056GeometryCollectionMapper.prototype.getClass = function getClass () {
39057 return GeometryCollectionMapper
39058};
39059GeometryCollectionMapper.map = function map (gc, op) {
39060 var mapper = new GeometryCollectionMapper(op);
39061 return mapper.map(gc)
39062};
39063
39064var LineBuilder = function LineBuilder () {
39065 this._op = null;
39066 this._geometryFactory = null;
39067 this._ptLocator = null;
39068 this._lineEdgesList = new ArrayList();
39069 this._resultLineList = new ArrayList();
39070 var op = arguments[0];
39071 var geometryFactory = arguments[1];
39072 var ptLocator = arguments[2];
39073 this._op = op;
39074 this._geometryFactory = geometryFactory;
39075 this._ptLocator = ptLocator;
39076};
39077LineBuilder.prototype.collectLines = function collectLines (opCode) {
39078 var this$1 = this;
39079
39080 for (var it = this._op.getGraph().getEdgeEnds().iterator(); it.hasNext();) {
39081 var de = it.next();
39082 this$1.collectLineEdge(de, opCode, this$1._lineEdgesList);
39083 this$1.collectBoundaryTouchEdge(de, opCode, this$1._lineEdgesList);
39084 }
39085};
39086LineBuilder.prototype.labelIsolatedLine = function labelIsolatedLine (e, targetIndex) {
39087 var loc = this._ptLocator.locate(e.getCoordinate(), this._op.getArgGeometry(targetIndex));
39088 e.getLabel().setLocation(targetIndex, loc);
39089};
39090LineBuilder.prototype.build = function build (opCode) {
39091 this.findCoveredLineEdges();
39092 this.collectLines(opCode);
39093 this.buildLines(opCode);
39094 return this._resultLineList
39095};
39096LineBuilder.prototype.collectLineEdge = function collectLineEdge (de, opCode, edges) {
39097 var label = de.getLabel();
39098 var e = de.getEdge();
39099 if (de.isLineEdge()) {
39100 if (!de.isVisited() && OverlayOp.isResultOfOp(label, opCode) && !e.isCovered()) {
39101 edges.add(e);
39102 de.setVisitedEdge(true);
39103 }
39104 }
39105};
39106LineBuilder.prototype.findCoveredLineEdges = function findCoveredLineEdges () {
39107 var this$1 = this;
39108
39109 for (var nodeit = this._op.getGraph().getNodes().iterator(); nodeit.hasNext();) {
39110 var node = nodeit.next();
39111 node.getEdges().findCoveredLineEdges();
39112 }
39113 for (var it = this._op.getGraph().getEdgeEnds().iterator(); it.hasNext();) {
39114 var de = it.next();
39115 var e = de.getEdge();
39116 if (de.isLineEdge() && !e.isCoveredSet()) {
39117 var isCovered = this$1._op.isCoveredByA(de.getCoordinate());
39118 e.setCovered(isCovered);
39119 }
39120 }
39121};
39122LineBuilder.prototype.labelIsolatedLines = function labelIsolatedLines (edgesList) {
39123 var this$1 = this;
39124
39125 for (var it = edgesList.iterator(); it.hasNext();) {
39126 var e = it.next();
39127 var label = e.getLabel();
39128 if (e.isIsolated()) {
39129 if (label.isNull(0)) { this$1.labelIsolatedLine(e, 0); } else { this$1.labelIsolatedLine(e, 1); }
39130 }
39131 }
39132};
39133LineBuilder.prototype.buildLines = function buildLines (opCode) {
39134 var this$1 = this;
39135
39136 for (var it = this._lineEdgesList.iterator(); it.hasNext();) {
39137 var e = it.next();
39138 // const label = e.getLabel()
39139 var line = this$1._geometryFactory.createLineString(e.getCoordinates());
39140 this$1._resultLineList.add(line);
39141 e.setInResult(true);
39142 }
39143};
39144LineBuilder.prototype.collectBoundaryTouchEdge = function collectBoundaryTouchEdge (de, opCode, edges) {
39145 var label = de.getLabel();
39146 if (de.isLineEdge()) { return null }
39147 if (de.isVisited()) { return null }
39148 if (de.isInteriorAreaEdge()) { return null }
39149 if (de.getEdge().isInResult()) { return null }
39150 Assert.isTrue(!(de.isInResult() || de.getSym().isInResult()) || !de.getEdge().isInResult());
39151 if (OverlayOp.isResultOfOp(label, opCode) && opCode === OverlayOp.INTERSECTION) {
39152 edges.add(de.getEdge());
39153 de.setVisitedEdge(true);
39154 }
39155};
39156LineBuilder.prototype.interfaces_ = function interfaces_ () {
39157 return []
39158};
39159LineBuilder.prototype.getClass = function getClass () {
39160 return LineBuilder
39161};
39162
39163var PointBuilder = function PointBuilder () {
39164 this._op = null;
39165 this._geometryFactory = null;
39166 this._resultPointList = new ArrayList();
39167 var op = arguments[0];
39168 var geometryFactory = arguments[1];
39169 // const ptLocator = arguments[2]
39170 this._op = op;
39171 this._geometryFactory = geometryFactory;
39172};
39173PointBuilder.prototype.filterCoveredNodeToPoint = function filterCoveredNodeToPoint (n) {
39174 var coord = n.getCoordinate();
39175 if (!this._op.isCoveredByLA(coord)) {
39176 var pt = this._geometryFactory.createPoint(coord);
39177 this._resultPointList.add(pt);
39178 }
39179};
39180PointBuilder.prototype.extractNonCoveredResultNodes = function extractNonCoveredResultNodes (opCode) {
39181 var this$1 = this;
39182
39183 for (var nodeit = this._op.getGraph().getNodes().iterator(); nodeit.hasNext();) {
39184 var n = nodeit.next();
39185 if (n.isInResult()) { continue }
39186 if (n.isIncidentEdgeInResult()) { continue }
39187 if (n.getEdges().getDegree() === 0 || opCode === OverlayOp.INTERSECTION) {
39188 var label = n.getLabel();
39189 if (OverlayOp.isResultOfOp(label, opCode)) {
39190 this$1.filterCoveredNodeToPoint(n);
39191 }
39192 }
39193 }
39194};
39195PointBuilder.prototype.build = function build (opCode) {
39196 this.extractNonCoveredResultNodes(opCode);
39197 return this._resultPointList
39198};
39199PointBuilder.prototype.interfaces_ = function interfaces_ () {
39200 return []
39201};
39202PointBuilder.prototype.getClass = function getClass () {
39203 return PointBuilder
39204};
39205
39206var GeometryTransformer = function GeometryTransformer () {
39207 this._inputGeom = null;
39208 this._factory = null;
39209 this._pruneEmptyGeometry = true;
39210 this._preserveGeometryCollectionType = true;
39211 this._preserveCollections = false;
39212 this._preserveType = false;
39213};
39214GeometryTransformer.prototype.transformPoint = function transformPoint (geom, parent) {
39215 return this._factory.createPoint(this.transformCoordinates(geom.getCoordinateSequence(), geom))
39216};
39217GeometryTransformer.prototype.transformPolygon = function transformPolygon (geom, parent) {
39218 var this$1 = this;
39219
39220 var isAllValidLinearRings = true;
39221 var shell = this.transformLinearRing(geom.getExteriorRing(), geom);
39222 if (shell === null || !(shell instanceof LinearRing) || shell.isEmpty()) { isAllValidLinearRings = false; }
39223 var holes = new ArrayList();
39224 for (var i = 0; i < geom.getNumInteriorRing(); i++) {
39225 var hole = this$1.transformLinearRing(geom.getInteriorRingN(i), geom);
39226 if (hole === null || hole.isEmpty()) {
39227 continue
39228 }
39229 if (!(hole instanceof LinearRing)) { isAllValidLinearRings = false; }
39230 holes.add(hole);
39231 }
39232 if (isAllValidLinearRings) { return this._factory.createPolygon(shell, holes.toArray([])); } else {
39233 var components = new ArrayList();
39234 if (shell !== null) { components.add(shell); }
39235 components.addAll(holes);
39236 return this._factory.buildGeometry(components)
39237 }
39238};
39239GeometryTransformer.prototype.createCoordinateSequence = function createCoordinateSequence (coords) {
39240 return this._factory.getCoordinateSequenceFactory().create(coords)
39241};
39242GeometryTransformer.prototype.getInputGeometry = function getInputGeometry () {
39243 return this._inputGeom
39244};
39245GeometryTransformer.prototype.transformMultiLineString = function transformMultiLineString (geom, parent) {
39246 var this$1 = this;
39247
39248 var transGeomList = new ArrayList();
39249 for (var i = 0; i < geom.getNumGeometries(); i++) {
39250 var transformGeom = this$1.transformLineString(geom.getGeometryN(i), geom);
39251 if (transformGeom === null) { continue }
39252 if (transformGeom.isEmpty()) { continue }
39253 transGeomList.add(transformGeom);
39254 }
39255 return this._factory.buildGeometry(transGeomList)
39256};
39257GeometryTransformer.prototype.transformCoordinates = function transformCoordinates (coords, parent) {
39258 return this.copy(coords)
39259};
39260GeometryTransformer.prototype.transformLineString = function transformLineString (geom, parent) {
39261 return this._factory.createLineString(this.transformCoordinates(geom.getCoordinateSequence(), geom))
39262};
39263GeometryTransformer.prototype.transformMultiPoint = function transformMultiPoint (geom, parent) {
39264 var this$1 = this;
39265
39266 var transGeomList = new ArrayList();
39267 for (var i = 0; i < geom.getNumGeometries(); i++) {
39268 var transformGeom = this$1.transformPoint(geom.getGeometryN(i), geom);
39269 if (transformGeom === null) { continue }
39270 if (transformGeom.isEmpty()) { continue }
39271 transGeomList.add(transformGeom);
39272 }
39273 return this._factory.buildGeometry(transGeomList)
39274};
39275GeometryTransformer.prototype.transformMultiPolygon = function transformMultiPolygon (geom, parent) {
39276 var this$1 = this;
39277
39278 var transGeomList = new ArrayList();
39279 for (var i = 0; i < geom.getNumGeometries(); i++) {
39280 var transformGeom = this$1.transformPolygon(geom.getGeometryN(i), geom);
39281 if (transformGeom === null) { continue }
39282 if (transformGeom.isEmpty()) { continue }
39283 transGeomList.add(transformGeom);
39284 }
39285 return this._factory.buildGeometry(transGeomList)
39286};
39287GeometryTransformer.prototype.copy = function copy (seq) {
39288 return seq.copy()
39289};
39290GeometryTransformer.prototype.transformGeometryCollection = function transformGeometryCollection (geom, parent) {
39291 var this$1 = this;
39292
39293 var transGeomList = new ArrayList();
39294 for (var i = 0; i < geom.getNumGeometries(); i++) {
39295 var transformGeom = this$1.transform(geom.getGeometryN(i));
39296 if (transformGeom === null) { continue }
39297 if (this$1._pruneEmptyGeometry && transformGeom.isEmpty()) { continue }
39298 transGeomList.add(transformGeom);
39299 }
39300 if (this._preserveGeometryCollectionType) { return this._factory.createGeometryCollection(GeometryFactory.toGeometryArray(transGeomList)) }
39301 return this._factory.buildGeometry(transGeomList)
39302};
39303GeometryTransformer.prototype.transform = function transform (inputGeom) {
39304 this._inputGeom = inputGeom;
39305 this._factory = inputGeom.getFactory();
39306 if (inputGeom instanceof Point) { return this.transformPoint(inputGeom, null) }
39307 if (inputGeom instanceof MultiPoint) { return this.transformMultiPoint(inputGeom, null) }
39308 if (inputGeom instanceof LinearRing) { return this.transformLinearRing(inputGeom, null) }
39309 if (inputGeom instanceof LineString$1) { return this.transformLineString(inputGeom, null) }
39310 if (inputGeom instanceof MultiLineString) { return this.transformMultiLineString(inputGeom, null) }
39311 if (inputGeom instanceof Polygon) { return this.transformPolygon(inputGeom, null) }
39312 if (inputGeom instanceof MultiPolygon) { return this.transformMultiPolygon(inputGeom, null) }
39313 if (inputGeom instanceof GeometryCollection) { return this.transformGeometryCollection(inputGeom, null) }
39314 throw new IllegalArgumentException('Unknown Geometry subtype: ' + inputGeom.getClass().getName())
39315};
39316GeometryTransformer.prototype.transformLinearRing = function transformLinearRing (geom, parent) {
39317 var seq = this.transformCoordinates(geom.getCoordinateSequence(), geom);
39318 if (seq === null) { return this._factory.createLinearRing(null) }
39319 var seqSize = seq.size();
39320 if (seqSize > 0 && seqSize < 4 && !this._preserveType) { return this._factory.createLineString(seq) }
39321 return this._factory.createLinearRing(seq)
39322};
39323GeometryTransformer.prototype.interfaces_ = function interfaces_ () {
39324 return []
39325};
39326GeometryTransformer.prototype.getClass = function getClass () {
39327 return GeometryTransformer
39328};
39329
39330var LineStringSnapper = function LineStringSnapper () {
39331 this._snapTolerance = 0.0;
39332 this._srcPts = null;
39333 this._seg = new LineSegment();
39334 this._allowSnappingToSourceVertices = false;
39335 this._isClosed = false;
39336 if (arguments[0] instanceof LineString$1 && typeof arguments[1] === 'number') {
39337 var srcLine = arguments[0];
39338 var snapTolerance = arguments[1];
39339 LineStringSnapper.call(this, srcLine.getCoordinates(), snapTolerance);
39340 } else if (arguments[0] instanceof Array && typeof arguments[1] === 'number') {
39341 var srcPts = arguments[0];
39342 var snapTolerance$1 = arguments[1];
39343 this._srcPts = srcPts;
39344 this._isClosed = LineStringSnapper.isClosed(srcPts);
39345 this._snapTolerance = snapTolerance$1;
39346 }
39347};
39348LineStringSnapper.prototype.snapVertices = function snapVertices (srcCoords, snapPts) {
39349 var this$1 = this;
39350
39351 var end = this._isClosed ? srcCoords.size() - 1 : srcCoords.size();
39352 for (var i = 0; i < end; i++) {
39353 var srcPt = srcCoords.get(i);
39354 var snapVert = this$1.findSnapForVertex(srcPt, snapPts);
39355 if (snapVert !== null) {
39356 srcCoords.set(i, new Coordinate(snapVert));
39357 if (i === 0 && this$1._isClosed) { srcCoords.set(srcCoords.size() - 1, new Coordinate(snapVert)); }
39358 }
39359 }
39360};
39361LineStringSnapper.prototype.findSnapForVertex = function findSnapForVertex (pt, snapPts) {
39362 var this$1 = this;
39363
39364 for (var i = 0; i < snapPts.length; i++) {
39365 if (pt.equals2D(snapPts[i])) { return null }
39366 if (pt.distance(snapPts[i]) < this$1._snapTolerance) { return snapPts[i] }
39367 }
39368 return null
39369};
39370LineStringSnapper.prototype.snapTo = function snapTo (snapPts) {
39371 var coordList = new CoordinateList(this._srcPts);
39372 this.snapVertices(coordList, snapPts);
39373 this.snapSegments(coordList, snapPts);
39374 var newPts = coordList.toCoordinateArray();
39375 return newPts
39376};
39377LineStringSnapper.prototype.snapSegments = function snapSegments (srcCoords, snapPts) {
39378 var this$1 = this;
39379
39380 if (snapPts.length === 0) { return null }
39381 var distinctPtCount = snapPts.length;
39382 if (snapPts[0].equals2D(snapPts[snapPts.length - 1])) { distinctPtCount = snapPts.length - 1; }
39383 for (var i = 0; i < distinctPtCount; i++) {
39384 var snapPt = snapPts[i];
39385 var index = this$1.findSegmentIndexToSnap(snapPt, srcCoords);
39386 if (index >= 0) {
39387 srcCoords.add(index + 1, new Coordinate(snapPt), false);
39388 }
39389 }
39390};
39391LineStringSnapper.prototype.findSegmentIndexToSnap = function findSegmentIndexToSnap (snapPt, srcCoords) {
39392 var this$1 = this;
39393
39394 var minDist = Double.MAX_VALUE;
39395 var snapIndex = -1;
39396 for (var i = 0; i < srcCoords.size() - 1; i++) {
39397 this$1._seg.p0 = srcCoords.get(i);
39398 this$1._seg.p1 = srcCoords.get(i + 1);
39399 if (this$1._seg.p0.equals2D(snapPt) || this$1._seg.p1.equals2D(snapPt)) {
39400 if (this$1._allowSnappingToSourceVertices) { continue; } else { return -1 }
39401 }
39402 var dist = this$1._seg.distance(snapPt);
39403 if (dist < this$1._snapTolerance && dist < minDist) {
39404 minDist = dist;
39405 snapIndex = i;
39406 }
39407 }
39408 return snapIndex
39409};
39410LineStringSnapper.prototype.setAllowSnappingToSourceVertices = function setAllowSnappingToSourceVertices (allowSnappingToSourceVertices) {
39411 this._allowSnappingToSourceVertices = allowSnappingToSourceVertices;
39412};
39413LineStringSnapper.prototype.interfaces_ = function interfaces_ () {
39414 return []
39415};
39416LineStringSnapper.prototype.getClass = function getClass () {
39417 return LineStringSnapper
39418};
39419LineStringSnapper.isClosed = function isClosed (pts) {
39420 if (pts.length <= 1) { return false }
39421 return pts[0].equals2D(pts[pts.length - 1])
39422};
39423
39424var GeometrySnapper = function GeometrySnapper (srcGeom) {
39425 this._srcGeom = srcGeom || null;
39426};
39427
39428var staticAccessors$41 = { SNAP_PRECISION_FACTOR: { configurable: true } };
39429GeometrySnapper.prototype.snapTo = function snapTo (snapGeom, snapTolerance) {
39430 var snapPts = this.extractTargetCoordinates(snapGeom);
39431 var snapTrans = new SnapTransformer(snapTolerance, snapPts);
39432 return snapTrans.transform(this._srcGeom)
39433};
39434GeometrySnapper.prototype.snapToSelf = function snapToSelf (snapTolerance, cleanResult) {
39435 var snapPts = this.extractTargetCoordinates(this._srcGeom);
39436 var snapTrans = new SnapTransformer(snapTolerance, snapPts, true);
39437 var snappedGeom = snapTrans.transform(this._srcGeom);
39438 var result = snappedGeom;
39439 if (cleanResult && hasInterface(result, Polygonal)) {
39440 result = snappedGeom.buffer(0);
39441 }
39442 return result
39443};
39444GeometrySnapper.prototype.computeSnapTolerance = function computeSnapTolerance (ringPts) {
39445 var minSegLen = this.computeMinimumSegmentLength(ringPts);
39446 var snapTol = minSegLen / 10;
39447 return snapTol
39448};
39449GeometrySnapper.prototype.extractTargetCoordinates = function extractTargetCoordinates (g) {
39450 var ptSet = new TreeSet();
39451 var pts = g.getCoordinates();
39452 for (var i = 0; i < pts.length; i++) {
39453 ptSet.add(pts[i]);
39454 }
39455 return ptSet.toArray(new Array(0).fill(null))
39456};
39457GeometrySnapper.prototype.computeMinimumSegmentLength = function computeMinimumSegmentLength (pts) {
39458 var minSegLen = Double.MAX_VALUE;
39459 for (var i = 0; i < pts.length - 1; i++) {
39460 var segLen = pts[i].distance(pts[i + 1]);
39461 if (segLen < minSegLen) { minSegLen = segLen; }
39462 }
39463 return minSegLen
39464};
39465GeometrySnapper.prototype.interfaces_ = function interfaces_ () {
39466 return []
39467};
39468GeometrySnapper.prototype.getClass = function getClass () {
39469 return GeometrySnapper
39470};
39471GeometrySnapper.snap = function snap (g0, g1, snapTolerance) {
39472 var snapGeom = new Array(2).fill(null);
39473 var snapper0 = new GeometrySnapper(g0);
39474 snapGeom[0] = snapper0.snapTo(g1, snapTolerance);
39475 var snapper1 = new GeometrySnapper(g1);
39476 snapGeom[1] = snapper1.snapTo(snapGeom[0], snapTolerance);
39477 return snapGeom
39478};
39479GeometrySnapper.computeOverlaySnapTolerance = function computeOverlaySnapTolerance () {
39480 if (arguments.length === 1) {
39481 var g = arguments[0];
39482 var snapTolerance = GeometrySnapper.computeSizeBasedSnapTolerance(g);
39483 var pm = g.getPrecisionModel();
39484 if (pm.getType() === PrecisionModel.FIXED) {
39485 var fixedSnapTol = 1 / pm.getScale() * 2 / 1.415;
39486 if (fixedSnapTol > snapTolerance) { snapTolerance = fixedSnapTol; }
39487 }
39488 return snapTolerance
39489 } else if (arguments.length === 2) {
39490 var g0 = arguments[0];
39491 var g1 = arguments[1];
39492 return Math.min(GeometrySnapper.computeOverlaySnapTolerance(g0), GeometrySnapper.computeOverlaySnapTolerance(g1))
39493 }
39494};
39495GeometrySnapper.computeSizeBasedSnapTolerance = function computeSizeBasedSnapTolerance (g) {
39496 var env = g.getEnvelopeInternal();
39497 var minDimension = Math.min(env.getHeight(), env.getWidth());
39498 var snapTol = minDimension * GeometrySnapper.SNAP_PRECISION_FACTOR;
39499 return snapTol
39500};
39501GeometrySnapper.snapToSelf = function snapToSelf (geom, snapTolerance, cleanResult) {
39502 var snapper0 = new GeometrySnapper(geom);
39503 return snapper0.snapToSelf(snapTolerance, cleanResult)
39504};
39505staticAccessors$41.SNAP_PRECISION_FACTOR.get = function () { return 1e-9 };
39506
39507Object.defineProperties( GeometrySnapper, staticAccessors$41 );
39508
39509var SnapTransformer = (function (GeometryTransformer$$1) {
39510 function SnapTransformer (snapTolerance, snapPts, isSelfSnap) {
39511 GeometryTransformer$$1.call(this);
39512 this._snapTolerance = snapTolerance || null;
39513 this._snapPts = snapPts || null;
39514 this._isSelfSnap = (isSelfSnap !== undefined) ? isSelfSnap : false;
39515 }
39516
39517 if ( GeometryTransformer$$1 ) SnapTransformer.__proto__ = GeometryTransformer$$1;
39518 SnapTransformer.prototype = Object.create( GeometryTransformer$$1 && GeometryTransformer$$1.prototype );
39519 SnapTransformer.prototype.constructor = SnapTransformer;
39520 SnapTransformer.prototype.snapLine = function snapLine (srcPts, snapPts) {
39521 var snapper = new LineStringSnapper(srcPts, this._snapTolerance);
39522 snapper.setAllowSnappingToSourceVertices(this._isSelfSnap);
39523 return snapper.snapTo(snapPts)
39524 };
39525 SnapTransformer.prototype.transformCoordinates = function transformCoordinates (coords, parent) {
39526 var srcPts = coords.toCoordinateArray();
39527 var newPts = this.snapLine(srcPts, this._snapPts);
39528 return this._factory.getCoordinateSequenceFactory().create(newPts)
39529 };
39530 SnapTransformer.prototype.interfaces_ = function interfaces_ () {
39531 return []
39532 };
39533 SnapTransformer.prototype.getClass = function getClass () {
39534 return SnapTransformer
39535 };
39536
39537 return SnapTransformer;
39538}(GeometryTransformer));
39539
39540var CommonBits = function CommonBits () {
39541 this._isFirst = true;
39542 this._commonMantissaBitsCount = 53;
39543 this._commonBits = 0;
39544 this._commonSignExp = null;
39545};
39546CommonBits.prototype.getCommon = function getCommon () {
39547 return Double.longBitsToDouble(this._commonBits)
39548};
39549CommonBits.prototype.add = function add (num) {
39550 var numBits = Double.doubleToLongBits(num);
39551 if (this._isFirst) {
39552 this._commonBits = numBits;
39553 this._commonSignExp = CommonBits.signExpBits(this._commonBits);
39554 this._isFirst = false;
39555 return null
39556 }
39557 var numSignExp = CommonBits.signExpBits(numBits);
39558 if (numSignExp !== this._commonSignExp) {
39559 this._commonBits = 0;
39560 return null
39561 }
39562 this._commonMantissaBitsCount = CommonBits.numCommonMostSigMantissaBits(this._commonBits, numBits);
39563 this._commonBits = CommonBits.zeroLowerBits(this._commonBits, 64 - (12 + this._commonMantissaBitsCount));
39564};
39565CommonBits.prototype.toString = function toString () {
39566 if (arguments.length === 1) {
39567 var bits = arguments[0];
39568 var x = Double.longBitsToDouble(bits);
39569 var numStr = Double.toBinaryString(bits);
39570 var padStr = '0000000000000000000000000000000000000000000000000000000000000000' + numStr;
39571 var bitStr = padStr.substring(padStr.length - 64);
39572 var str = bitStr.substring(0, 1) + ' ' + bitStr.substring(1, 12) + '(exp) ' + bitStr.substring(12) + ' [ ' + x + ' ]';
39573 return str
39574 }
39575};
39576CommonBits.prototype.interfaces_ = function interfaces_ () {
39577 return []
39578};
39579CommonBits.prototype.getClass = function getClass () {
39580 return CommonBits
39581};
39582CommonBits.getBit = function getBit (bits, i) {
39583 var mask = 1 << i;
39584 return (bits & mask) !== 0 ? 1 : 0
39585};
39586CommonBits.signExpBits = function signExpBits (num) {
39587 return num >> 52
39588};
39589CommonBits.zeroLowerBits = function zeroLowerBits (bits, nBits) {
39590 var invMask = (1 << nBits) - 1;
39591 var mask = ~invMask;
39592 var zeroed = bits & mask;
39593 return zeroed
39594};
39595CommonBits.numCommonMostSigMantissaBits = function numCommonMostSigMantissaBits (num1, num2) {
39596 var count = 0;
39597 for (var i = 52; i >= 0; i--) {
39598 if (CommonBits.getBit(num1, i) !== CommonBits.getBit(num2, i)) { return count }
39599 count++;
39600 }
39601 return 52
39602};
39603
39604var CommonBitsRemover = function CommonBitsRemover () {
39605 this._commonCoord = null;
39606 this._ccFilter = new CommonCoordinateFilter();
39607};
39608
39609var staticAccessors$42 = { CommonCoordinateFilter: { configurable: true },Translater: { configurable: true } };
39610CommonBitsRemover.prototype.addCommonBits = function addCommonBits (geom) {
39611 var trans = new Translater(this._commonCoord);
39612 geom.apply(trans);
39613 geom.geometryChanged();
39614};
39615CommonBitsRemover.prototype.removeCommonBits = function removeCommonBits (geom) {
39616 if (this._commonCoord.x === 0.0 && this._commonCoord.y === 0.0) { return geom }
39617 var invCoord = new Coordinate(this._commonCoord);
39618 invCoord.x = -invCoord.x;
39619 invCoord.y = -invCoord.y;
39620 var trans = new Translater(invCoord);
39621 geom.apply(trans);
39622 geom.geometryChanged();
39623 return geom
39624};
39625CommonBitsRemover.prototype.getCommonCoordinate = function getCommonCoordinate () {
39626 return this._commonCoord
39627};
39628CommonBitsRemover.prototype.add = function add (geom) {
39629 geom.apply(this._ccFilter);
39630 this._commonCoord = this._ccFilter.getCommonCoordinate();
39631};
39632CommonBitsRemover.prototype.interfaces_ = function interfaces_ () {
39633 return []
39634};
39635CommonBitsRemover.prototype.getClass = function getClass () {
39636 return CommonBitsRemover
39637};
39638staticAccessors$42.CommonCoordinateFilter.get = function () { return CommonCoordinateFilter };
39639staticAccessors$42.Translater.get = function () { return Translater };
39640
39641Object.defineProperties( CommonBitsRemover, staticAccessors$42 );
39642
39643var CommonCoordinateFilter = function CommonCoordinateFilter () {
39644 this._commonBitsX = new CommonBits();
39645 this._commonBitsY = new CommonBits();
39646};
39647CommonCoordinateFilter.prototype.filter = function filter (coord) {
39648 this._commonBitsX.add(coord.x);
39649 this._commonBitsY.add(coord.y);
39650};
39651CommonCoordinateFilter.prototype.getCommonCoordinate = function getCommonCoordinate () {
39652 return new Coordinate(this._commonBitsX.getCommon(), this._commonBitsY.getCommon())
39653};
39654CommonCoordinateFilter.prototype.interfaces_ = function interfaces_ () {
39655 return [CoordinateFilter]
39656};
39657CommonCoordinateFilter.prototype.getClass = function getClass () {
39658 return CommonCoordinateFilter
39659};
39660
39661var Translater = function Translater () {
39662 this.trans = null;
39663 var trans = arguments[0];
39664 this.trans = trans;
39665};
39666Translater.prototype.filter = function filter (seq, i) {
39667 var xp = seq.getOrdinate(i, 0) + this.trans.x;
39668 var yp = seq.getOrdinate(i, 1) + this.trans.y;
39669 seq.setOrdinate(i, 0, xp);
39670 seq.setOrdinate(i, 1, yp);
39671};
39672Translater.prototype.isDone = function isDone () {
39673 return false
39674};
39675Translater.prototype.isGeometryChanged = function isGeometryChanged () {
39676 return true
39677};
39678Translater.prototype.interfaces_ = function interfaces_ () {
39679 return [CoordinateSequenceFilter]
39680};
39681Translater.prototype.getClass = function getClass () {
39682 return Translater
39683};
39684
39685var SnapOverlayOp = function SnapOverlayOp (g1, g2) {
39686 this._geom = new Array(2).fill(null);
39687 this._snapTolerance = null;
39688 this._cbr = null;
39689 this._geom[0] = g1;
39690 this._geom[1] = g2;
39691 this.computeSnapTolerance();
39692};
39693SnapOverlayOp.prototype.selfSnap = function selfSnap (geom) {
39694 var snapper0 = new GeometrySnapper(geom);
39695 var snapGeom = snapper0.snapTo(geom, this._snapTolerance);
39696 return snapGeom
39697};
39698SnapOverlayOp.prototype.removeCommonBits = function removeCommonBits (geom) {
39699 this._cbr = new CommonBitsRemover();
39700 this._cbr.add(geom[0]);
39701 this._cbr.add(geom[1]);
39702 var remGeom = new Array(2).fill(null);
39703 remGeom[0] = this._cbr.removeCommonBits(geom[0].copy());
39704 remGeom[1] = this._cbr.removeCommonBits(geom[1].copy());
39705 return remGeom
39706};
39707SnapOverlayOp.prototype.prepareResult = function prepareResult (geom) {
39708 this._cbr.addCommonBits(geom);
39709 return geom
39710};
39711SnapOverlayOp.prototype.getResultGeometry = function getResultGeometry (opCode) {
39712 var prepGeom = this.snap(this._geom);
39713 var result = OverlayOp.overlayOp(prepGeom[0], prepGeom[1], opCode);
39714 return this.prepareResult(result)
39715};
39716SnapOverlayOp.prototype.checkValid = function checkValid (g) {
39717 if (!g.isValid()) {
39718 System.out.println('Snapped geometry is invalid');
39719 }
39720};
39721SnapOverlayOp.prototype.computeSnapTolerance = function computeSnapTolerance () {
39722 this._snapTolerance = GeometrySnapper.computeOverlaySnapTolerance(this._geom[0], this._geom[1]);
39723};
39724SnapOverlayOp.prototype.snap = function snap (geom) {
39725 var remGeom = this.removeCommonBits(geom);
39726 var snapGeom = GeometrySnapper.snap(remGeom[0], remGeom[1], this._snapTolerance);
39727 return snapGeom
39728};
39729SnapOverlayOp.prototype.interfaces_ = function interfaces_ () {
39730 return []
39731};
39732SnapOverlayOp.prototype.getClass = function getClass () {
39733 return SnapOverlayOp
39734};
39735SnapOverlayOp.overlayOp = function overlayOp (g0, g1, opCode) {
39736 var op = new SnapOverlayOp(g0, g1);
39737 return op.getResultGeometry(opCode)
39738};
39739SnapOverlayOp.union = function union (g0, g1) {
39740 return SnapOverlayOp.overlayOp(g0, g1, OverlayOp.UNION)
39741};
39742SnapOverlayOp.intersection = function intersection (g0, g1) {
39743 return SnapOverlayOp.overlayOp(g0, g1, OverlayOp.INTERSECTION)
39744};
39745SnapOverlayOp.symDifference = function symDifference (g0, g1) {
39746 return SnapOverlayOp.overlayOp(g0, g1, OverlayOp.SYMDIFFERENCE)
39747};
39748SnapOverlayOp.difference = function difference (g0, g1) {
39749 return SnapOverlayOp.overlayOp(g0, g1, OverlayOp.DIFFERENCE)
39750};
39751
39752var SnapIfNeededOverlayOp = function SnapIfNeededOverlayOp (g1, g2) {
39753 this._geom = new Array(2).fill(null);
39754 this._geom[0] = g1;
39755 this._geom[1] = g2;
39756};
39757SnapIfNeededOverlayOp.prototype.getResultGeometry = function getResultGeometry (opCode) {
39758 var result = null;
39759 var isSuccess = false;
39760 var savedException = null;
39761 try {
39762 result = OverlayOp.overlayOp(this._geom[0], this._geom[1], opCode);
39763 var isValid = true;
39764 if (isValid) { isSuccess = true; }
39765 } catch (ex) {
39766 if (ex instanceof RuntimeException) {
39767 savedException = ex;
39768 } else { throw ex }
39769 } finally {}
39770 if (!isSuccess) {
39771 try {
39772 result = SnapOverlayOp.overlayOp(this._geom[0], this._geom[1], opCode);
39773 } catch (ex) {
39774 if (ex instanceof RuntimeException) {
39775 throw savedException
39776 } else { throw ex }
39777 } finally {}
39778 }
39779 return result
39780};
39781SnapIfNeededOverlayOp.prototype.interfaces_ = function interfaces_ () {
39782 return []
39783};
39784SnapIfNeededOverlayOp.prototype.getClass = function getClass () {
39785 return SnapIfNeededOverlayOp
39786};
39787SnapIfNeededOverlayOp.overlayOp = function overlayOp (g0, g1, opCode) {
39788 var op = new SnapIfNeededOverlayOp(g0, g1);
39789 return op.getResultGeometry(opCode)
39790};
39791SnapIfNeededOverlayOp.union = function union (g0, g1) {
39792 return SnapIfNeededOverlayOp.overlayOp(g0, g1, OverlayOp.UNION)
39793};
39794SnapIfNeededOverlayOp.intersection = function intersection (g0, g1) {
39795 return SnapIfNeededOverlayOp.overlayOp(g0, g1, OverlayOp.INTERSECTION)
39796};
39797SnapIfNeededOverlayOp.symDifference = function symDifference (g0, g1) {
39798 return SnapIfNeededOverlayOp.overlayOp(g0, g1, OverlayOp.SYMDIFFERENCE)
39799};
39800SnapIfNeededOverlayOp.difference = function difference (g0, g1) {
39801 return SnapIfNeededOverlayOp.overlayOp(g0, g1, OverlayOp.DIFFERENCE)
39802};
39803
39804var MonotoneChain$2 = function MonotoneChain () {
39805 this.mce = null;
39806 this.chainIndex = null;
39807 var mce = arguments[0];
39808 var chainIndex = arguments[1];
39809 this.mce = mce;
39810 this.chainIndex = chainIndex;
39811};
39812MonotoneChain$2.prototype.computeIntersections = function computeIntersections (mc, si) {
39813 this.mce.computeIntersectsForChain(this.chainIndex, mc.mce, mc.chainIndex, si);
39814};
39815MonotoneChain$2.prototype.interfaces_ = function interfaces_ () {
39816 return []
39817};
39818MonotoneChain$2.prototype.getClass = function getClass () {
39819 return MonotoneChain$2
39820};
39821
39822var SweepLineEvent = function SweepLineEvent () {
39823 this._label = null;
39824 this._xValue = null;
39825 this._eventType = null;
39826 this._insertEvent = null;
39827 this._deleteEventIndex = null;
39828 this._obj = null;
39829 if (arguments.length === 2) {
39830 var x = arguments[0];
39831 var insertEvent = arguments[1];
39832 this._eventType = SweepLineEvent.DELETE;
39833 this._xValue = x;
39834 this._insertEvent = insertEvent;
39835 } else if (arguments.length === 3) {
39836 var label = arguments[0];
39837 var x$1 = arguments[1];
39838 var obj = arguments[2];
39839 this._eventType = SweepLineEvent.INSERT;
39840 this._label = label;
39841 this._xValue = x$1;
39842 this._obj = obj;
39843 }
39844};
39845
39846var staticAccessors$43 = { INSERT: { configurable: true },DELETE: { configurable: true } };
39847SweepLineEvent.prototype.isDelete = function isDelete () {
39848 return this._eventType === SweepLineEvent.DELETE
39849};
39850SweepLineEvent.prototype.setDeleteEventIndex = function setDeleteEventIndex (deleteEventIndex) {
39851 this._deleteEventIndex = deleteEventIndex;
39852};
39853SweepLineEvent.prototype.getObject = function getObject () {
39854 return this._obj
39855};
39856SweepLineEvent.prototype.compareTo = function compareTo (o) {
39857 var pe = o;
39858 if (this._xValue < pe._xValue) { return -1 }
39859 if (this._xValue > pe._xValue) { return 1 }
39860 if (this._eventType < pe._eventType) { return -1 }
39861 if (this._eventType > pe._eventType) { return 1 }
39862 return 0
39863};
39864SweepLineEvent.prototype.getInsertEvent = function getInsertEvent () {
39865 return this._insertEvent
39866};
39867SweepLineEvent.prototype.isInsert = function isInsert () {
39868 return this._eventType === SweepLineEvent.INSERT
39869};
39870SweepLineEvent.prototype.isSameLabel = function isSameLabel (ev) {
39871 if (this._label === null) { return false }
39872 return this._label === ev._label
39873};
39874SweepLineEvent.prototype.getDeleteEventIndex = function getDeleteEventIndex () {
39875 return this._deleteEventIndex
39876};
39877SweepLineEvent.prototype.interfaces_ = function interfaces_ () {
39878 return [Comparable]
39879};
39880SweepLineEvent.prototype.getClass = function getClass () {
39881 return SweepLineEvent
39882};
39883staticAccessors$43.INSERT.get = function () { return 1 };
39884staticAccessors$43.DELETE.get = function () { return 2 };
39885
39886Object.defineProperties( SweepLineEvent, staticAccessors$43 );
39887
39888var EdgeSetIntersector = function EdgeSetIntersector () {};
39889
39890EdgeSetIntersector.prototype.interfaces_ = function interfaces_ () {
39891 return []
39892};
39893EdgeSetIntersector.prototype.getClass = function getClass () {
39894 return EdgeSetIntersector
39895};
39896
39897var SegmentIntersector$2 = function SegmentIntersector () {
39898 this._hasIntersection = false;
39899 this._hasProper = false;
39900 this._hasProperInterior = false;
39901 this._properIntersectionPoint = null;
39902 this._li = null;
39903 this._includeProper = null;
39904 this._recordIsolated = null;
39905 this._isSelfIntersection = null;
39906 this._numIntersections = 0;
39907 this.numTests = 0;
39908 this._bdyNodes = null;
39909 this._isDone = false;
39910 this._isDoneWhenProperInt = false;
39911 var li = arguments[0];
39912 var includeProper = arguments[1];
39913 var recordIsolated = arguments[2];
39914 this._li = li;
39915 this._includeProper = includeProper;
39916 this._recordIsolated = recordIsolated;
39917};
39918SegmentIntersector$2.prototype.isTrivialIntersection = function isTrivialIntersection (e0, segIndex0, e1, segIndex1) {
39919 if (e0 === e1) {
39920 if (this._li.getIntersectionNum() === 1) {
39921 if (SegmentIntersector$2.isAdjacentSegments(segIndex0, segIndex1)) { return true }
39922 if (e0.isClosed()) {
39923 var maxSegIndex = e0.getNumPoints() - 1;
39924 if ((segIndex0 === 0 && segIndex1 === maxSegIndex) ||
39925 (segIndex1 === 0 && segIndex0 === maxSegIndex)) {
39926 return true
39927 }
39928 }
39929 }
39930 }
39931 return false
39932};
39933SegmentIntersector$2.prototype.getProperIntersectionPoint = function getProperIntersectionPoint () {
39934 return this._properIntersectionPoint
39935};
39936SegmentIntersector$2.prototype.setIsDoneIfProperInt = function setIsDoneIfProperInt (isDoneWhenProperInt) {
39937 this._isDoneWhenProperInt = isDoneWhenProperInt;
39938};
39939SegmentIntersector$2.prototype.hasProperInteriorIntersection = function hasProperInteriorIntersection () {
39940 return this._hasProperInterior
39941};
39942SegmentIntersector$2.prototype.isBoundaryPointInternal = function isBoundaryPointInternal (li, bdyNodes) {
39943 for (var i = bdyNodes.iterator(); i.hasNext();) {
39944 var node = i.next();
39945 var pt = node.getCoordinate();
39946 if (li.isIntersection(pt)) { return true }
39947 }
39948 return false
39949};
39950SegmentIntersector$2.prototype.hasProperIntersection = function hasProperIntersection () {
39951 return this._hasProper
39952};
39953SegmentIntersector$2.prototype.hasIntersection = function hasIntersection () {
39954 return this._hasIntersection
39955};
39956SegmentIntersector$2.prototype.isDone = function isDone () {
39957 return this._isDone
39958};
39959SegmentIntersector$2.prototype.isBoundaryPoint = function isBoundaryPoint (li, bdyNodes) {
39960 if (bdyNodes === null) { return false }
39961 if (this.isBoundaryPointInternal(li, bdyNodes[0])) { return true }
39962 if (this.isBoundaryPointInternal(li, bdyNodes[1])) { return true }
39963 return false
39964};
39965SegmentIntersector$2.prototype.setBoundaryNodes = function setBoundaryNodes (bdyNodes0, bdyNodes1) {
39966 this._bdyNodes = new Array(2).fill(null);
39967 this._bdyNodes[0] = bdyNodes0;
39968 this._bdyNodes[1] = bdyNodes1;
39969};
39970SegmentIntersector$2.prototype.addIntersections = function addIntersections (e0, segIndex0, e1, segIndex1) {
39971 if (e0 === e1 && segIndex0 === segIndex1) { return null }
39972 this.numTests++;
39973 var p00 = e0.getCoordinates()[segIndex0];
39974 var p01 = e0.getCoordinates()[segIndex0 + 1];
39975 var p10 = e1.getCoordinates()[segIndex1];
39976 var p11 = e1.getCoordinates()[segIndex1 + 1];
39977 this._li.computeIntersection(p00, p01, p10, p11);
39978 if (this._li.hasIntersection()) {
39979 if (this._recordIsolated) {
39980 e0.setIsolated(false);
39981 e1.setIsolated(false);
39982 }
39983 this._numIntersections++;
39984 if (!this.isTrivialIntersection(e0, segIndex0, e1, segIndex1)) {
39985 this._hasIntersection = true;
39986 if (this._includeProper || !this._li.isProper()) {
39987 e0.addIntersections(this._li, segIndex0, 0);
39988 e1.addIntersections(this._li, segIndex1, 1);
39989 }
39990 if (this._li.isProper()) {
39991 this._properIntersectionPoint = this._li.getIntersection(0).copy();
39992 this._hasProper = true;
39993 if (this._isDoneWhenProperInt) {
39994 this._isDone = true;
39995 }
39996 if (!this.isBoundaryPoint(this._li, this._bdyNodes)) { this._hasProperInterior = true; }
39997 }
39998 }
39999 }
40000};
40001SegmentIntersector$2.prototype.interfaces_ = function interfaces_ () {
40002 return []
40003};
40004SegmentIntersector$2.prototype.getClass = function getClass () {
40005 return SegmentIntersector$2
40006};
40007SegmentIntersector$2.isAdjacentSegments = function isAdjacentSegments (i1, i2) {
40008 return Math.abs(i1 - i2) === 1
40009};
40010
40011var SimpleMCSweepLineIntersector = (function (EdgeSetIntersector$$1) {
40012 function SimpleMCSweepLineIntersector () {
40013 EdgeSetIntersector$$1.call(this);
40014 this.events = new ArrayList();
40015 this.nOverlaps = null;
40016 }
40017
40018 if ( EdgeSetIntersector$$1 ) SimpleMCSweepLineIntersector.__proto__ = EdgeSetIntersector$$1;
40019 SimpleMCSweepLineIntersector.prototype = Object.create( EdgeSetIntersector$$1 && EdgeSetIntersector$$1.prototype );
40020 SimpleMCSweepLineIntersector.prototype.constructor = SimpleMCSweepLineIntersector;
40021 SimpleMCSweepLineIntersector.prototype.prepareEvents = function prepareEvents () {
40022 var this$1 = this;
40023
40024 Collections.sort(this.events);
40025 for (var i = 0; i < this.events.size(); i++) {
40026 var ev = this$1.events.get(i);
40027 if (ev.isDelete()) {
40028 ev.getInsertEvent().setDeleteEventIndex(i);
40029 }
40030 }
40031 };
40032 SimpleMCSweepLineIntersector.prototype.computeIntersections = function computeIntersections () {
40033 var this$1 = this;
40034
40035 if (arguments.length === 1) {
40036 var si = arguments[0];
40037 this.nOverlaps = 0;
40038 this.prepareEvents();
40039 for (var i = 0; i < this.events.size(); i++) {
40040 var ev = this$1.events.get(i);
40041 if (ev.isInsert()) {
40042 this$1.processOverlaps(i, ev.getDeleteEventIndex(), ev, si);
40043 }
40044 if (si.isDone()) {
40045 break
40046 }
40047 }
40048 } else if (arguments.length === 3) {
40049 if (arguments[2] instanceof SegmentIntersector$2 && (hasInterface(arguments[0], List) && hasInterface(arguments[1], List))) {
40050 var edges0 = arguments[0];
40051 var edges1 = arguments[1];
40052 var si$1 = arguments[2];
40053 this.addEdges(edges0, edges0);
40054 this.addEdges(edges1, edges1);
40055 this.computeIntersections(si$1);
40056 } else if (typeof arguments[2] === 'boolean' && (hasInterface(arguments[0], List) && arguments[1] instanceof SegmentIntersector$2)) {
40057 var edges = arguments[0];
40058 var si$2 = arguments[1];
40059 var testAllSegments = arguments[2];
40060 if (testAllSegments) { this.addEdges(edges, null); } else { this.addEdges(edges); }
40061 this.computeIntersections(si$2);
40062 }
40063 }
40064 };
40065 SimpleMCSweepLineIntersector.prototype.addEdge = function addEdge (edge, edgeSet) {
40066 var this$1 = this;
40067
40068 var mce = edge.getMonotoneChainEdge();
40069 var startIndex = mce.getStartIndexes();
40070 for (var i = 0; i < startIndex.length - 1; i++) {
40071 var mc = new MonotoneChain$2(mce, i);
40072 var insertEvent = new SweepLineEvent(edgeSet, mce.getMinX(i), mc);
40073 this$1.events.add(insertEvent);
40074 this$1.events.add(new SweepLineEvent(mce.getMaxX(i), insertEvent));
40075 }
40076 };
40077 SimpleMCSweepLineIntersector.prototype.processOverlaps = function processOverlaps (start, end, ev0, si) {
40078 var this$1 = this;
40079
40080 var mc0 = ev0.getObject();
40081 for (var i = start; i < end; i++) {
40082 var ev1 = this$1.events.get(i);
40083 if (ev1.isInsert()) {
40084 var mc1 = ev1.getObject();
40085 if (!ev0.isSameLabel(ev1)) {
40086 mc0.computeIntersections(mc1, si);
40087 this$1.nOverlaps++;
40088 }
40089 }
40090 }
40091 };
40092 SimpleMCSweepLineIntersector.prototype.addEdges = function addEdges () {
40093 var this$1 = this;
40094
40095 if (arguments.length === 1) {
40096 var edges = arguments[0];
40097 for (var i = edges.iterator(); i.hasNext();) {
40098 var edge = i.next();
40099 this$1.addEdge(edge, edge);
40100 }
40101 } else if (arguments.length === 2) {
40102 var edges$1 = arguments[0];
40103 var edgeSet = arguments[1];
40104 for (var i$1 = edges$1.iterator(); i$1.hasNext();) {
40105 var edge$1 = i$1.next();
40106 this$1.addEdge(edge$1, edgeSet);
40107 }
40108 }
40109 };
40110 SimpleMCSweepLineIntersector.prototype.interfaces_ = function interfaces_ () {
40111 return []
40112 };
40113 SimpleMCSweepLineIntersector.prototype.getClass = function getClass () {
40114 return SimpleMCSweepLineIntersector
40115 };
40116
40117 return SimpleMCSweepLineIntersector;
40118}(EdgeSetIntersector));
40119
40120var IntervalRTreeNode = function IntervalRTreeNode () {
40121 this._min = Double.POSITIVE_INFINITY;
40122 this._max = Double.NEGATIVE_INFINITY;
40123};
40124
40125var staticAccessors$45 = { NodeComparator: { configurable: true } };
40126IntervalRTreeNode.prototype.getMin = function getMin () {
40127 return this._min
40128};
40129IntervalRTreeNode.prototype.intersects = function intersects (queryMin, queryMax) {
40130 if (this._min > queryMax || this._max < queryMin) { return false }
40131 return true
40132};
40133IntervalRTreeNode.prototype.getMax = function getMax () {
40134 return this._max
40135};
40136IntervalRTreeNode.prototype.toString = function toString () {
40137 return WKTWriter.toLineString(new Coordinate(this._min, 0), new Coordinate(this._max, 0))
40138};
40139IntervalRTreeNode.prototype.interfaces_ = function interfaces_ () {
40140 return []
40141};
40142IntervalRTreeNode.prototype.getClass = function getClass () {
40143 return IntervalRTreeNode
40144};
40145staticAccessors$45.NodeComparator.get = function () { return NodeComparator };
40146
40147Object.defineProperties( IntervalRTreeNode, staticAccessors$45 );
40148
40149var NodeComparator = function NodeComparator () {};
40150
40151NodeComparator.prototype.compare = function compare (o1, o2) {
40152 var n1 = o1;
40153 var n2 = o2;
40154 var mid1 = (n1._min + n1._max) / 2;
40155 var mid2 = (n2._min + n2._max) / 2;
40156 if (mid1 < mid2) { return -1 }
40157 if (mid1 > mid2) { return 1 }
40158 return 0
40159};
40160NodeComparator.prototype.interfaces_ = function interfaces_ () {
40161 return [Comparator]
40162};
40163NodeComparator.prototype.getClass = function getClass () {
40164 return NodeComparator
40165};
40166
40167var IntervalRTreeLeafNode = (function (IntervalRTreeNode$$1) {
40168 function IntervalRTreeLeafNode () {
40169 IntervalRTreeNode$$1.call(this);
40170 this._item = null;
40171 var min = arguments[0];
40172 var max = arguments[1];
40173 var item = arguments[2];
40174 this._min = min;
40175 this._max = max;
40176 this._item = item;
40177 }
40178
40179 if ( IntervalRTreeNode$$1 ) IntervalRTreeLeafNode.__proto__ = IntervalRTreeNode$$1;
40180 IntervalRTreeLeafNode.prototype = Object.create( IntervalRTreeNode$$1 && IntervalRTreeNode$$1.prototype );
40181 IntervalRTreeLeafNode.prototype.constructor = IntervalRTreeLeafNode;
40182 IntervalRTreeLeafNode.prototype.query = function query (queryMin, queryMax, visitor) {
40183 if (!this.intersects(queryMin, queryMax)) { return null }
40184 visitor.visitItem(this._item);
40185 };
40186 IntervalRTreeLeafNode.prototype.interfaces_ = function interfaces_ () {
40187 return []
40188 };
40189 IntervalRTreeLeafNode.prototype.getClass = function getClass () {
40190 return IntervalRTreeLeafNode
40191 };
40192
40193 return IntervalRTreeLeafNode;
40194}(IntervalRTreeNode));
40195
40196var IntervalRTreeBranchNode = (function (IntervalRTreeNode$$1) {
40197 function IntervalRTreeBranchNode () {
40198 IntervalRTreeNode$$1.call(this);
40199 this._node1 = null;
40200 this._node2 = null;
40201 var n1 = arguments[0];
40202 var n2 = arguments[1];
40203 this._node1 = n1;
40204 this._node2 = n2;
40205 this.buildExtent(this._node1, this._node2);
40206 }
40207
40208 if ( IntervalRTreeNode$$1 ) IntervalRTreeBranchNode.__proto__ = IntervalRTreeNode$$1;
40209 IntervalRTreeBranchNode.prototype = Object.create( IntervalRTreeNode$$1 && IntervalRTreeNode$$1.prototype );
40210 IntervalRTreeBranchNode.prototype.constructor = IntervalRTreeBranchNode;
40211 IntervalRTreeBranchNode.prototype.buildExtent = function buildExtent (n1, n2) {
40212 this._min = Math.min(n1._min, n2._min);
40213 this._max = Math.max(n1._max, n2._max);
40214 };
40215 IntervalRTreeBranchNode.prototype.query = function query (queryMin, queryMax, visitor) {
40216 if (!this.intersects(queryMin, queryMax)) {
40217 return null
40218 }
40219 if (this._node1 !== null) { this._node1.query(queryMin, queryMax, visitor); }
40220 if (this._node2 !== null) { this._node2.query(queryMin, queryMax, visitor); }
40221 };
40222 IntervalRTreeBranchNode.prototype.interfaces_ = function interfaces_ () {
40223 return []
40224 };
40225 IntervalRTreeBranchNode.prototype.getClass = function getClass () {
40226 return IntervalRTreeBranchNode
40227 };
40228
40229 return IntervalRTreeBranchNode;
40230}(IntervalRTreeNode));
40231
40232var SortedPackedIntervalRTree = function SortedPackedIntervalRTree () {
40233 this._leaves = new ArrayList();
40234 this._root = null;
40235 this._level = 0;
40236};
40237SortedPackedIntervalRTree.prototype.buildTree = function buildTree () {
40238 var this$1 = this;
40239
40240 Collections.sort(this._leaves, new IntervalRTreeNode.NodeComparator());
40241 var src = this._leaves;
40242 var temp = null;
40243 var dest = new ArrayList();
40244 while (true) {
40245 this$1.buildLevel(src, dest);
40246 if (dest.size() === 1) { return dest.get(0) }
40247 temp = src;
40248 src = dest;
40249 dest = temp;
40250 }
40251};
40252SortedPackedIntervalRTree.prototype.insert = function insert (min, max, item) {
40253 if (this._root !== null) { throw new Error('Index cannot be added to once it has been queried') }
40254 this._leaves.add(new IntervalRTreeLeafNode(min, max, item));
40255};
40256SortedPackedIntervalRTree.prototype.query = function query (min, max, visitor) {
40257 this.init();
40258 this._root.query(min, max, visitor);
40259};
40260SortedPackedIntervalRTree.prototype.buildRoot = function buildRoot () {
40261 if (this._root !== null) { return null }
40262 this._root = this.buildTree();
40263};
40264SortedPackedIntervalRTree.prototype.printNode = function printNode (node) {
40265 System.out.println(WKTWriter.toLineString(new Coordinate(node._min, this._level), new Coordinate(node._max, this._level)));
40266};
40267SortedPackedIntervalRTree.prototype.init = function init () {
40268 if (this._root !== null) { return null }
40269 this.buildRoot();
40270};
40271SortedPackedIntervalRTree.prototype.buildLevel = function buildLevel (src, dest) {
40272 this._level++;
40273 dest.clear();
40274 for (var i = 0; i < src.size(); i += 2) {
40275 var n1 = src.get(i);
40276 var n2 = i + 1 < src.size() ? src.get(i) : null;
40277 if (n2 === null) {
40278 dest.add(n1);
40279 } else {
40280 var node = new IntervalRTreeBranchNode(src.get(i), src.get(i + 1));
40281 dest.add(node);
40282 }
40283 }
40284};
40285SortedPackedIntervalRTree.prototype.interfaces_ = function interfaces_ () {
40286 return []
40287};
40288SortedPackedIntervalRTree.prototype.getClass = function getClass () {
40289 return SortedPackedIntervalRTree
40290};
40291
40292var ArrayListVisitor = function ArrayListVisitor () {
40293 this._items = new ArrayList();
40294};
40295ArrayListVisitor.prototype.visitItem = function visitItem (item) {
40296 this._items.add(item);
40297};
40298ArrayListVisitor.prototype.getItems = function getItems () {
40299 return this._items
40300};
40301ArrayListVisitor.prototype.interfaces_ = function interfaces_ () {
40302 return [ItemVisitor]
40303};
40304ArrayListVisitor.prototype.getClass = function getClass () {
40305 return ArrayListVisitor
40306};
40307
40308var IndexedPointInAreaLocator = function IndexedPointInAreaLocator () {
40309 this._index = null;
40310 var g = arguments[0];
40311 if (!hasInterface(g, Polygonal)) { throw new IllegalArgumentException('Argument must be Polygonal') }
40312 this._index = new IntervalIndexedGeometry(g);
40313};
40314
40315var staticAccessors$44 = { SegmentVisitor: { configurable: true },IntervalIndexedGeometry: { configurable: true } };
40316IndexedPointInAreaLocator.prototype.locate = function locate (p) {
40317 var rcc = new RayCrossingCounter(p);
40318 var visitor = new SegmentVisitor(rcc);
40319 this._index.query(p.y, p.y, visitor);
40320 return rcc.getLocation()
40321};
40322IndexedPointInAreaLocator.prototype.interfaces_ = function interfaces_ () {
40323 return [PointOnGeometryLocator]
40324};
40325IndexedPointInAreaLocator.prototype.getClass = function getClass () {
40326 return IndexedPointInAreaLocator
40327};
40328staticAccessors$44.SegmentVisitor.get = function () { return SegmentVisitor };
40329staticAccessors$44.IntervalIndexedGeometry.get = function () { return IntervalIndexedGeometry };
40330
40331Object.defineProperties( IndexedPointInAreaLocator, staticAccessors$44 );
40332
40333var SegmentVisitor = function SegmentVisitor () {
40334 this._counter = null;
40335 var counter = arguments[0];
40336 this._counter = counter;
40337};
40338SegmentVisitor.prototype.visitItem = function visitItem (item) {
40339 var seg = item;
40340 this._counter.countSegment(seg.getCoordinate(0), seg.getCoordinate(1));
40341};
40342SegmentVisitor.prototype.interfaces_ = function interfaces_ () {
40343 return [ItemVisitor]
40344};
40345SegmentVisitor.prototype.getClass = function getClass () {
40346 return SegmentVisitor
40347};
40348
40349var IntervalIndexedGeometry = function IntervalIndexedGeometry () {
40350 this._index = new SortedPackedIntervalRTree();
40351 var geom = arguments[0];
40352 this.init(geom);
40353};
40354IntervalIndexedGeometry.prototype.init = function init (geom) {
40355 var this$1 = this;
40356
40357 var lines = LinearComponentExtracter.getLines(geom);
40358 for (var i = lines.iterator(); i.hasNext();) {
40359 var line = i.next();
40360 var pts = line.getCoordinates();
40361 this$1.addLine(pts);
40362 }
40363};
40364IntervalIndexedGeometry.prototype.addLine = function addLine (pts) {
40365 var this$1 = this;
40366
40367 for (var i = 1; i < pts.length; i++) {
40368 var seg = new LineSegment(pts[i - 1], pts[i]);
40369 var min = Math.min(seg.p0.y, seg.p1.y);
40370 var max = Math.max(seg.p0.y, seg.p1.y);
40371 this$1._index.insert(min, max, seg);
40372 }
40373};
40374IntervalIndexedGeometry.prototype.query = function query () {
40375 if (arguments.length === 2) {
40376 var min = arguments[0];
40377 var max = arguments[1];
40378 var visitor = new ArrayListVisitor();
40379 this._index.query(min, max, visitor);
40380 return visitor.getItems()
40381 } else if (arguments.length === 3) {
40382 var min$1 = arguments[0];
40383 var max$1 = arguments[1];
40384 var visitor$1 = arguments[2];
40385 this._index.query(min$1, max$1, visitor$1);
40386 }
40387};
40388IntervalIndexedGeometry.prototype.interfaces_ = function interfaces_ () {
40389 return []
40390};
40391IntervalIndexedGeometry.prototype.getClass = function getClass () {
40392 return IntervalIndexedGeometry
40393};
40394
40395var GeometryGraph = (function (PlanarGraph$$1) {
40396 function GeometryGraph () {
40397 PlanarGraph$$1.call(this);
40398 this._parentGeom = null;
40399 this._lineEdgeMap = new HashMap();
40400 this._boundaryNodeRule = null;
40401 this._useBoundaryDeterminationRule = true;
40402 this._argIndex = null;
40403 this._boundaryNodes = null;
40404 this._hasTooFewPoints = false;
40405 this._invalidPoint = null;
40406 this._areaPtLocator = null;
40407 this._ptLocator = new PointLocator();
40408 if (arguments.length === 2) {
40409 var argIndex = arguments[0];
40410 var parentGeom = arguments[1];
40411 var boundaryNodeRule = BoundaryNodeRule.OGC_SFS_BOUNDARY_RULE;
40412 this._argIndex = argIndex;
40413 this._parentGeom = parentGeom;
40414 this._boundaryNodeRule = boundaryNodeRule;
40415 if (parentGeom !== null) {
40416 this.add(parentGeom);
40417 }
40418 } else if (arguments.length === 3) {
40419 var argIndex$1 = arguments[0];
40420 var parentGeom$1 = arguments[1];
40421 var boundaryNodeRule$1 = arguments[2];
40422 this._argIndex = argIndex$1;
40423 this._parentGeom = parentGeom$1;
40424 this._boundaryNodeRule = boundaryNodeRule$1;
40425 if (parentGeom$1 !== null) {
40426 this.add(parentGeom$1);
40427 }
40428 }
40429 }
40430
40431 if ( PlanarGraph$$1 ) GeometryGraph.__proto__ = PlanarGraph$$1;
40432 GeometryGraph.prototype = Object.create( PlanarGraph$$1 && PlanarGraph$$1.prototype );
40433 GeometryGraph.prototype.constructor = GeometryGraph;
40434 GeometryGraph.prototype.insertBoundaryPoint = function insertBoundaryPoint (argIndex, coord) {
40435 var n = this._nodes.addNode(coord);
40436 var lbl = n.getLabel();
40437 var boundaryCount = 1;
40438 var loc = Location.NONE;
40439 loc = lbl.getLocation(argIndex, Position.ON);
40440 if (loc === Location.BOUNDARY) { boundaryCount++; }
40441 var newLoc = GeometryGraph.determineBoundary(this._boundaryNodeRule, boundaryCount);
40442 lbl.setLocation(argIndex, newLoc);
40443 };
40444 GeometryGraph.prototype.computeSelfNodes = function computeSelfNodes () {
40445 if (arguments.length === 2) {
40446 var li = arguments[0];
40447 var computeRingSelfNodes = arguments[1];
40448 return this.computeSelfNodes(li, computeRingSelfNodes, false)
40449 } else if (arguments.length === 3) {
40450 var li$1 = arguments[0];
40451 var computeRingSelfNodes$1 = arguments[1];
40452 var isDoneIfProperInt = arguments[2];
40453 var si = new SegmentIntersector$2(li$1, true, false);
40454 si.setIsDoneIfProperInt(isDoneIfProperInt);
40455 var esi = this.createEdgeSetIntersector();
40456 var isRings = this._parentGeom instanceof LinearRing || this._parentGeom instanceof Polygon || this._parentGeom instanceof MultiPolygon;
40457 var computeAllSegments = computeRingSelfNodes$1 || !isRings;
40458 esi.computeIntersections(this._edges, si, computeAllSegments);
40459 this.addSelfIntersectionNodes(this._argIndex);
40460 return si
40461 }
40462 };
40463 GeometryGraph.prototype.computeSplitEdges = function computeSplitEdges (edgelist) {
40464 for (var i = this._edges.iterator(); i.hasNext();) {
40465 var e = i.next();
40466 e.eiList.addSplitEdges(edgelist);
40467 }
40468 };
40469 GeometryGraph.prototype.computeEdgeIntersections = function computeEdgeIntersections (g, li, includeProper) {
40470 var si = new SegmentIntersector$2(li, includeProper, true);
40471 si.setBoundaryNodes(this.getBoundaryNodes(), g.getBoundaryNodes());
40472 var esi = this.createEdgeSetIntersector();
40473 esi.computeIntersections(this._edges, g._edges, si);
40474 return si
40475 };
40476 GeometryGraph.prototype.getGeometry = function getGeometry () {
40477 return this._parentGeom
40478 };
40479 GeometryGraph.prototype.getBoundaryNodeRule = function getBoundaryNodeRule () {
40480 return this._boundaryNodeRule
40481 };
40482 GeometryGraph.prototype.hasTooFewPoints = function hasTooFewPoints () {
40483 return this._hasTooFewPoints
40484 };
40485 GeometryGraph.prototype.addPoint = function addPoint () {
40486 if (arguments[0] instanceof Point) {
40487 var p = arguments[0];
40488 var coord = p.getCoordinate();
40489 this.insertPoint(this._argIndex, coord, Location.INTERIOR);
40490 } else if (arguments[0] instanceof Coordinate) {
40491 var pt = arguments[0];
40492 this.insertPoint(this._argIndex, pt, Location.INTERIOR);
40493 }
40494 };
40495 GeometryGraph.prototype.addPolygon = function addPolygon (p) {
40496 var this$1 = this;
40497
40498 this.addPolygonRing(p.getExteriorRing(), Location.EXTERIOR, Location.INTERIOR);
40499 for (var i = 0; i < p.getNumInteriorRing(); i++) {
40500 var hole = p.getInteriorRingN(i);
40501 this$1.addPolygonRing(hole, Location.INTERIOR, Location.EXTERIOR);
40502 }
40503 };
40504 GeometryGraph.prototype.addEdge = function addEdge (e) {
40505 this.insertEdge(e);
40506 var coord = e.getCoordinates();
40507 this.insertPoint(this._argIndex, coord[0], Location.BOUNDARY);
40508 this.insertPoint(this._argIndex, coord[coord.length - 1], Location.BOUNDARY);
40509 };
40510 GeometryGraph.prototype.addLineString = function addLineString (line) {
40511 var coord = CoordinateArrays.removeRepeatedPoints(line.getCoordinates());
40512 if (coord.length < 2) {
40513 this._hasTooFewPoints = true;
40514 this._invalidPoint = coord[0];
40515 return null
40516 }
40517 var e = new Edge$1(coord, new Label(this._argIndex, Location.INTERIOR));
40518 this._lineEdgeMap.put(line, e);
40519 this.insertEdge(e);
40520 Assert.isTrue(coord.length >= 2, 'found LineString with single point');
40521 this.insertBoundaryPoint(this._argIndex, coord[0]);
40522 this.insertBoundaryPoint(this._argIndex, coord[coord.length - 1]);
40523 };
40524 GeometryGraph.prototype.getInvalidPoint = function getInvalidPoint () {
40525 return this._invalidPoint
40526 };
40527 GeometryGraph.prototype.getBoundaryPoints = function getBoundaryPoints () {
40528 var coll = this.getBoundaryNodes();
40529 var pts = new Array(coll.size()).fill(null);
40530 var i = 0;
40531 for (var it = coll.iterator(); it.hasNext();) {
40532 var node = it.next();
40533 pts[i++] = node.getCoordinate().copy();
40534 }
40535 return pts
40536 };
40537 GeometryGraph.prototype.getBoundaryNodes = function getBoundaryNodes () {
40538 if (this._boundaryNodes === null) { this._boundaryNodes = this._nodes.getBoundaryNodes(this._argIndex); }
40539 return this._boundaryNodes
40540 };
40541 GeometryGraph.prototype.addSelfIntersectionNode = function addSelfIntersectionNode (argIndex, coord, loc) {
40542 if (this.isBoundaryNode(argIndex, coord)) { return null }
40543 if (loc === Location.BOUNDARY && this._useBoundaryDeterminationRule) { this.insertBoundaryPoint(argIndex, coord); } else { this.insertPoint(argIndex, coord, loc); }
40544 };
40545 GeometryGraph.prototype.addPolygonRing = function addPolygonRing (lr, cwLeft, cwRight) {
40546 if (lr.isEmpty()) { return null }
40547 var coord = CoordinateArrays.removeRepeatedPoints(lr.getCoordinates());
40548 if (coord.length < 4) {
40549 this._hasTooFewPoints = true;
40550 this._invalidPoint = coord[0];
40551 return null
40552 }
40553 var left = cwLeft;
40554 var right = cwRight;
40555 if (CGAlgorithms.isCCW(coord)) {
40556 left = cwRight;
40557 right = cwLeft;
40558 }
40559 var e = new Edge$1(coord, new Label(this._argIndex, Location.BOUNDARY, left, right));
40560 this._lineEdgeMap.put(lr, e);
40561 this.insertEdge(e);
40562 this.insertPoint(this._argIndex, coord[0], Location.BOUNDARY);
40563 };
40564 GeometryGraph.prototype.insertPoint = function insertPoint (argIndex, coord, onLocation) {
40565 var n = this._nodes.addNode(coord);
40566 var lbl = n.getLabel();
40567 if (lbl === null) {
40568 n._label = new Label(argIndex, onLocation);
40569 } else { lbl.setLocation(argIndex, onLocation); }
40570 };
40571 GeometryGraph.prototype.createEdgeSetIntersector = function createEdgeSetIntersector () {
40572 return new SimpleMCSweepLineIntersector()
40573 };
40574 GeometryGraph.prototype.addSelfIntersectionNodes = function addSelfIntersectionNodes (argIndex) {
40575 var this$1 = this;
40576
40577 for (var i = this._edges.iterator(); i.hasNext();) {
40578 var e = i.next();
40579 var eLoc = e.getLabel().getLocation(argIndex);
40580 for (var eiIt = e.eiList.iterator(); eiIt.hasNext();) {
40581 var ei = eiIt.next();
40582 this$1.addSelfIntersectionNode(argIndex, ei.coord, eLoc);
40583 }
40584 }
40585 };
40586 GeometryGraph.prototype.add = function add () {
40587 if (arguments.length === 1) {
40588 var g = arguments[0];
40589 if (g.isEmpty()) { return null }
40590 if (g instanceof MultiPolygon) { this._useBoundaryDeterminationRule = false; }
40591 if (g instanceof Polygon) { this.addPolygon(g); }
40592 else if (g instanceof LineString$1) { this.addLineString(g); }
40593 else if (g instanceof Point) { this.addPoint(g); }
40594 else if (g instanceof MultiPoint) { this.addCollection(g); }
40595 else if (g instanceof MultiLineString) { this.addCollection(g); }
40596 else if (g instanceof MultiPolygon) { this.addCollection(g); }
40597 else if (g instanceof GeometryCollection) { this.addCollection(g); }
40598 else { throw new Error(g.getClass().getName()) }
40599 } else { return PlanarGraph$$1.prototype.add.apply(this, arguments) }
40600 };
40601 GeometryGraph.prototype.addCollection = function addCollection (gc) {
40602 var this$1 = this;
40603
40604 for (var i = 0; i < gc.getNumGeometries(); i++) {
40605 var g = gc.getGeometryN(i);
40606 this$1.add(g);
40607 }
40608 };
40609 GeometryGraph.prototype.locate = function locate (pt) {
40610 if (hasInterface(this._parentGeom, Polygonal) && this._parentGeom.getNumGeometries() > 50) {
40611 if (this._areaPtLocator === null) {
40612 this._areaPtLocator = new IndexedPointInAreaLocator(this._parentGeom);
40613 }
40614 return this._areaPtLocator.locate(pt)
40615 }
40616 return this._ptLocator.locate(pt, this._parentGeom)
40617 };
40618 GeometryGraph.prototype.findEdge = function findEdge () {
40619 if (arguments.length === 1) {
40620 var line = arguments[0];
40621 return this._lineEdgeMap.get(line)
40622 } else { return PlanarGraph$$1.prototype.findEdge.apply(this, arguments) }
40623 };
40624 GeometryGraph.prototype.interfaces_ = function interfaces_ () {
40625 return []
40626 };
40627 GeometryGraph.prototype.getClass = function getClass () {
40628 return GeometryGraph
40629 };
40630 GeometryGraph.determineBoundary = function determineBoundary (boundaryNodeRule, boundaryCount) {
40631 return boundaryNodeRule.isInBoundary(boundaryCount) ? Location.BOUNDARY : Location.INTERIOR
40632 };
40633
40634 return GeometryGraph;
40635}(PlanarGraph));
40636
40637var GeometryGraphOp = function GeometryGraphOp () {
40638 this._li = new RobustLineIntersector();
40639 this._resultPrecisionModel = null;
40640 this._arg = null;
40641 if (arguments.length === 1) {
40642 var g0 = arguments[0];
40643 this.setComputationPrecision(g0.getPrecisionModel());
40644 this._arg = new Array(1).fill(null);
40645 this._arg[0] = new GeometryGraph(0, g0);
40646 } else if (arguments.length === 2) {
40647 var g0$1 = arguments[0];
40648 var g1 = arguments[1];
40649 var boundaryNodeRule = BoundaryNodeRule.OGC_SFS_BOUNDARY_RULE;
40650 if (g0$1.getPrecisionModel().compareTo(g1.getPrecisionModel()) >= 0) { this.setComputationPrecision(g0$1.getPrecisionModel()); } else { this.setComputationPrecision(g1.getPrecisionModel()); }
40651 this._arg = new Array(2).fill(null);
40652 this._arg[0] = new GeometryGraph(0, g0$1, boundaryNodeRule);
40653 this._arg[1] = new GeometryGraph(1, g1, boundaryNodeRule);
40654 } else if (arguments.length === 3) {
40655 var g0$2 = arguments[0];
40656 var g1$1 = arguments[1];
40657 var boundaryNodeRule$1 = arguments[2];
40658 if (g0$2.getPrecisionModel().compareTo(g1$1.getPrecisionModel()) >= 0) { this.setComputationPrecision(g0$2.getPrecisionModel()); } else { this.setComputationPrecision(g1$1.getPrecisionModel()); }
40659 this._arg = new Array(2).fill(null);
40660 this._arg[0] = new GeometryGraph(0, g0$2, boundaryNodeRule$1);
40661 this._arg[1] = new GeometryGraph(1, g1$1, boundaryNodeRule$1);
40662 }
40663};
40664GeometryGraphOp.prototype.getArgGeometry = function getArgGeometry (i) {
40665 return this._arg[i].getGeometry()
40666};
40667GeometryGraphOp.prototype.setComputationPrecision = function setComputationPrecision (pm) {
40668 this._resultPrecisionModel = pm;
40669 this._li.setPrecisionModel(this._resultPrecisionModel);
40670};
40671GeometryGraphOp.prototype.interfaces_ = function interfaces_ () {
40672 return []
40673};
40674GeometryGraphOp.prototype.getClass = function getClass () {
40675 return GeometryGraphOp
40676};
40677
40678// operation.geometrygraph
40679
40680var GeometryMapper = function GeometryMapper () {};
40681
40682GeometryMapper.prototype.interfaces_ = function interfaces_ () {
40683 return []
40684};
40685GeometryMapper.prototype.getClass = function getClass () {
40686 return GeometryMapper
40687};
40688GeometryMapper.map = function map () {
40689 if (arguments[0] instanceof Geometry && hasInterface(arguments[1], GeometryMapper.MapOp)) {
40690 var geom = arguments[0];
40691 var op = arguments[1];
40692 var mapped = new ArrayList();
40693 for (var i = 0; i < geom.getNumGeometries(); i++) {
40694 var g = op.map(geom.getGeometryN(i));
40695 if (g !== null) { mapped.add(g); }
40696 }
40697 return geom.getFactory().buildGeometry(mapped)
40698 } else if (hasInterface(arguments[0], Collection) && hasInterface(arguments[1], GeometryMapper.MapOp)) {
40699 var geoms = arguments[0];
40700 var op$1 = arguments[1];
40701 var mapped$1 = new ArrayList();
40702 for (var i$1 = geoms.iterator(); i$1.hasNext();) {
40703 var g$1 = i$1.next();
40704 var gr = op$1.map(g$1);
40705 if (gr !== null) { mapped$1.add(gr); }
40706 }
40707 return mapped$1
40708 }
40709};
40710GeometryMapper.MapOp = function MapOp () {};
40711
40712var OverlayOp = (function (GeometryGraphOp) {
40713 function OverlayOp () {
40714 var g0 = arguments[0];
40715 var g1 = arguments[1];
40716 GeometryGraphOp.call(this, g0, g1);
40717 this._ptLocator = new PointLocator();
40718 this._geomFact = null;
40719 this._resultGeom = null;
40720 this._graph = null;
40721 this._edgeList = new EdgeList();
40722 this._resultPolyList = new ArrayList();
40723 this._resultLineList = new ArrayList();
40724 this._resultPointList = new ArrayList();
40725 this._graph = new PlanarGraph(new OverlayNodeFactory());
40726 this._geomFact = g0.getFactory();
40727 }
40728
40729 if ( GeometryGraphOp ) OverlayOp.__proto__ = GeometryGraphOp;
40730 OverlayOp.prototype = Object.create( GeometryGraphOp && GeometryGraphOp.prototype );
40731 OverlayOp.prototype.constructor = OverlayOp;
40732 OverlayOp.prototype.insertUniqueEdge = function insertUniqueEdge (e) {
40733 var existingEdge = this._edgeList.findEqualEdge(e);
40734 if (existingEdge !== null) {
40735 var existingLabel = existingEdge.getLabel();
40736 var labelToMerge = e.getLabel();
40737 if (!existingEdge.isPointwiseEqual(e)) {
40738 labelToMerge = new Label(e.getLabel());
40739 labelToMerge.flip();
40740 }
40741 var depth = existingEdge.getDepth();
40742 if (depth.isNull()) {
40743 depth.add(existingLabel);
40744 }
40745 depth.add(labelToMerge);
40746 existingLabel.merge(labelToMerge);
40747 } else {
40748 this._edgeList.add(e);
40749 }
40750 };
40751 OverlayOp.prototype.getGraph = function getGraph () {
40752 return this._graph
40753 };
40754 OverlayOp.prototype.cancelDuplicateResultEdges = function cancelDuplicateResultEdges () {
40755 for (var it = this._graph.getEdgeEnds().iterator(); it.hasNext();) {
40756 var de = it.next();
40757 var sym = de.getSym();
40758 if (de.isInResult() && sym.isInResult()) {
40759 de.setInResult(false);
40760 sym.setInResult(false);
40761 }
40762 }
40763 };
40764 OverlayOp.prototype.isCoveredByLA = function isCoveredByLA (coord) {
40765 if (this.isCovered(coord, this._resultLineList)) { return true }
40766 if (this.isCovered(coord, this._resultPolyList)) { return true }
40767 return false
40768 };
40769 OverlayOp.prototype.computeGeometry = function computeGeometry (resultPointList, resultLineList, resultPolyList, opcode) {
40770 var geomList = new ArrayList();
40771 geomList.addAll(resultPointList);
40772 geomList.addAll(resultLineList);
40773 geomList.addAll(resultPolyList);
40774 if (geomList.isEmpty()) { return OverlayOp.createEmptyResult(opcode, this._arg[0].getGeometry(), this._arg[1].getGeometry(), this._geomFact) }
40775 return this._geomFact.buildGeometry(geomList)
40776 };
40777 OverlayOp.prototype.mergeSymLabels = function mergeSymLabels () {
40778 for (var nodeit = this._graph.getNodes().iterator(); nodeit.hasNext();) {
40779 var node = nodeit.next();
40780 node.getEdges().mergeSymLabels();
40781 }
40782 };
40783 OverlayOp.prototype.isCovered = function isCovered (coord, geomList) {
40784 var this$1 = this;
40785
40786 for (var it = geomList.iterator(); it.hasNext();) {
40787 var geom = it.next();
40788 var loc = this$1._ptLocator.locate(coord, geom);
40789 if (loc !== Location.EXTERIOR) { return true }
40790 }
40791 return false
40792 };
40793 OverlayOp.prototype.replaceCollapsedEdges = function replaceCollapsedEdges () {
40794 var newEdges = new ArrayList();
40795 for (var it = this._edgeList.iterator(); it.hasNext();) {
40796 var e = it.next();
40797 if (e.isCollapsed()) {
40798 it.remove();
40799 newEdges.add(e.getCollapsedEdge());
40800 }
40801 }
40802 this._edgeList.addAll(newEdges);
40803 };
40804 OverlayOp.prototype.updateNodeLabelling = function updateNodeLabelling () {
40805 for (var nodeit = this._graph.getNodes().iterator(); nodeit.hasNext();) {
40806 var node = nodeit.next();
40807 var lbl = node.getEdges().getLabel();
40808 node.getLabel().merge(lbl);
40809 }
40810 };
40811 OverlayOp.prototype.getResultGeometry = function getResultGeometry (overlayOpCode) {
40812 this.computeOverlay(overlayOpCode);
40813 return this._resultGeom
40814 };
40815 OverlayOp.prototype.insertUniqueEdges = function insertUniqueEdges (edges) {
40816 var this$1 = this;
40817
40818 for (var i = edges.iterator(); i.hasNext();) {
40819 var e = i.next();
40820 this$1.insertUniqueEdge(e);
40821 }
40822 };
40823 OverlayOp.prototype.computeOverlay = function computeOverlay (opCode) {
40824 this.copyPoints(0);
40825 this.copyPoints(1);
40826 this._arg[0].computeSelfNodes(this._li, false);
40827 this._arg[1].computeSelfNodes(this._li, false);
40828 this._arg[0].computeEdgeIntersections(this._arg[1], this._li, true);
40829 var baseSplitEdges = new ArrayList();
40830 this._arg[0].computeSplitEdges(baseSplitEdges);
40831 this._arg[1].computeSplitEdges(baseSplitEdges);
40832 // const splitEdges = baseSplitEdges
40833 this.insertUniqueEdges(baseSplitEdges);
40834 this.computeLabelsFromDepths();
40835 this.replaceCollapsedEdges();
40836 EdgeNodingValidator.checkValid(this._edgeList.getEdges());
40837 this._graph.addEdges(this._edgeList.getEdges());
40838 this.computeLabelling();
40839 this.labelIncompleteNodes();
40840 this.findResultAreaEdges(opCode);
40841 this.cancelDuplicateResultEdges();
40842 var polyBuilder = new PolygonBuilder(this._geomFact);
40843 polyBuilder.add(this._graph);
40844 this._resultPolyList = polyBuilder.getPolygons();
40845 var lineBuilder = new LineBuilder(this, this._geomFact, this._ptLocator);
40846 this._resultLineList = lineBuilder.build(opCode);
40847 var pointBuilder = new PointBuilder(this, this._geomFact, this._ptLocator);
40848 this._resultPointList = pointBuilder.build(opCode);
40849 this._resultGeom = this.computeGeometry(this._resultPointList, this._resultLineList, this._resultPolyList, opCode);
40850 };
40851 OverlayOp.prototype.labelIncompleteNode = function labelIncompleteNode (n, targetIndex) {
40852 var loc = this._ptLocator.locate(n.getCoordinate(), this._arg[targetIndex].getGeometry());
40853 n.getLabel().setLocation(targetIndex, loc);
40854 };
40855 OverlayOp.prototype.copyPoints = function copyPoints (argIndex) {
40856 var this$1 = this;
40857
40858 for (var i = this._arg[argIndex].getNodeIterator(); i.hasNext();) {
40859 var graphNode = i.next();
40860 var newNode = this$1._graph.addNode(graphNode.getCoordinate());
40861 newNode.setLabel(argIndex, graphNode.getLabel().getLocation(argIndex));
40862 }
40863 };
40864 OverlayOp.prototype.findResultAreaEdges = function findResultAreaEdges (opCode) {
40865 for (var it = this._graph.getEdgeEnds().iterator(); it.hasNext();) {
40866 var de = it.next();
40867 var label = de.getLabel();
40868 if (label.isArea() && !de.isInteriorAreaEdge() && OverlayOp.isResultOfOp(label.getLocation(0, Position.RIGHT), label.getLocation(1, Position.RIGHT), opCode)) {
40869 de.setInResult(true);
40870 }
40871 }
40872 };
40873 OverlayOp.prototype.computeLabelsFromDepths = function computeLabelsFromDepths () {
40874 for (var it = this._edgeList.iterator(); it.hasNext();) {
40875 var e = it.next();
40876 var lbl = e.getLabel();
40877 var depth = e.getDepth();
40878 if (!depth.isNull()) {
40879 depth.normalize();
40880 for (var i = 0; i < 2; i++) {
40881 if (!lbl.isNull(i) && lbl.isArea() && !depth.isNull(i)) {
40882 if (depth.getDelta(i) === 0) {
40883 lbl.toLine(i);
40884 } else {
40885 Assert.isTrue(!depth.isNull(i, Position.LEFT), 'depth of LEFT side has not been initialized');
40886 lbl.setLocation(i, Position.LEFT, depth.getLocation(i, Position.LEFT));
40887 Assert.isTrue(!depth.isNull(i, Position.RIGHT), 'depth of RIGHT side has not been initialized');
40888 lbl.setLocation(i, Position.RIGHT, depth.getLocation(i, Position.RIGHT));
40889 }
40890 }
40891 }
40892 }
40893 }
40894 };
40895 OverlayOp.prototype.computeLabelling = function computeLabelling () {
40896 var this$1 = this;
40897
40898 for (var nodeit = this._graph.getNodes().iterator(); nodeit.hasNext();) {
40899 var node = nodeit.next();
40900 node.getEdges().computeLabelling(this$1._arg);
40901 }
40902 this.mergeSymLabels();
40903 this.updateNodeLabelling();
40904 };
40905 OverlayOp.prototype.labelIncompleteNodes = function labelIncompleteNodes () {
40906 var this$1 = this;
40907
40908 // let nodeCount = 0
40909 for (var ni = this._graph.getNodes().iterator(); ni.hasNext();) {
40910 var n = ni.next();
40911 var label = n.getLabel();
40912 if (n.isIsolated()) {
40913 // nodeCount++
40914 if (label.isNull(0)) { this$1.labelIncompleteNode(n, 0); } else { this$1.labelIncompleteNode(n, 1); }
40915 }
40916 n.getEdges().updateLabelling(label);
40917 }
40918 };
40919 OverlayOp.prototype.isCoveredByA = function isCoveredByA (coord) {
40920 if (this.isCovered(coord, this._resultPolyList)) { return true }
40921 return false
40922 };
40923 OverlayOp.prototype.interfaces_ = function interfaces_ () {
40924 return []
40925 };
40926 OverlayOp.prototype.getClass = function getClass () {
40927 return OverlayOp
40928 };
40929
40930 return OverlayOp;
40931}(GeometryGraphOp));
40932
40933OverlayOp.overlayOp = function (geom0, geom1, opCode) {
40934 var gov = new OverlayOp(geom0, geom1);
40935 var geomOv = gov.getResultGeometry(opCode);
40936 return geomOv
40937};
40938OverlayOp.intersection = function (g, other) {
40939 if (g.isEmpty() || other.isEmpty()) { return OverlayOp.createEmptyResult(OverlayOp.INTERSECTION, g, other, g.getFactory()) }
40940 if (g.isGeometryCollection()) {
40941 var g2 = other;
40942 return GeometryCollectionMapper.map(g, {
40943 interfaces_: function () {
40944 return [GeometryMapper.MapOp]
40945 },
40946 map: function (g) {
40947 return g.intersection(g2)
40948 }
40949 })
40950 }
40951 g.checkNotGeometryCollection(g);
40952 g.checkNotGeometryCollection(other);
40953 return SnapIfNeededOverlayOp.overlayOp(g, other, OverlayOp.INTERSECTION)
40954};
40955OverlayOp.symDifference = function (g, other) {
40956 if (g.isEmpty() || other.isEmpty()) {
40957 if (g.isEmpty() && other.isEmpty()) { return OverlayOp.createEmptyResult(OverlayOp.SYMDIFFERENCE, g, other, g.getFactory()) }
40958 if (g.isEmpty()) { return other.copy() }
40959 if (other.isEmpty()) { return g.copy() }
40960 }
40961 g.checkNotGeometryCollection(g);
40962 g.checkNotGeometryCollection(other);
40963 return SnapIfNeededOverlayOp.overlayOp(g, other, OverlayOp.SYMDIFFERENCE)
40964};
40965OverlayOp.resultDimension = function (opCode, g0, g1) {
40966 var dim0 = g0.getDimension();
40967 var dim1 = g1.getDimension();
40968 var resultDimension = -1;
40969 switch (opCode) {
40970 case OverlayOp.INTERSECTION:
40971 resultDimension = Math.min(dim0, dim1);
40972 break
40973 case OverlayOp.UNION:
40974 resultDimension = Math.max(dim0, dim1);
40975 break
40976 case OverlayOp.DIFFERENCE:
40977 resultDimension = dim0;
40978 break
40979 case OverlayOp.SYMDIFFERENCE:
40980 resultDimension = Math.max(dim0, dim1);
40981 break
40982 default:
40983 }
40984 return resultDimension
40985};
40986OverlayOp.createEmptyResult = function (overlayOpCode, a, b, geomFact) {
40987 var result = null;
40988 switch (OverlayOp.resultDimension(overlayOpCode, a, b)) {
40989 case -1:
40990 result = geomFact.createGeometryCollection(new Array(0).fill(null));
40991 break
40992 case 0:
40993 result = geomFact.createPoint();
40994 break
40995 case 1:
40996 result = geomFact.createLineString();
40997 break
40998 case 2:
40999 result = geomFact.createPolygon();
41000 break
41001 default:
41002 }
41003 return result
41004};
41005OverlayOp.difference = function (g, other) {
41006 if (g.isEmpty()) { return OverlayOp.createEmptyResult(OverlayOp.DIFFERENCE, g, other, g.getFactory()) }
41007 if (other.isEmpty()) { return g.copy() }
41008 g.checkNotGeometryCollection(g);
41009 g.checkNotGeometryCollection(other);
41010 return SnapIfNeededOverlayOp.overlayOp(g, other, OverlayOp.DIFFERENCE)
41011};
41012OverlayOp.isResultOfOp = function () {
41013 if (arguments.length === 2) {
41014 var label = arguments[0];
41015 var opCode = arguments[1];
41016 var loc0 = label.getLocation(0);
41017 var loc1 = label.getLocation(1);
41018 return OverlayOp.isResultOfOp(loc0, loc1, opCode)
41019 } else if (arguments.length === 3) {
41020 var loc0$1 = arguments[0];
41021 var loc1$1 = arguments[1];
41022 var overlayOpCode = arguments[2];
41023 if (loc0$1 === Location.BOUNDARY) { loc0$1 = Location.INTERIOR; }
41024 if (loc1$1 === Location.BOUNDARY) { loc1$1 = Location.INTERIOR; }
41025 switch (overlayOpCode) {
41026 case OverlayOp.INTERSECTION:
41027 return loc0$1 === Location.INTERIOR && loc1$1 === Location.INTERIOR
41028 case OverlayOp.UNION:
41029 return loc0$1 === Location.INTERIOR || loc1$1 === Location.INTERIOR
41030 case OverlayOp.DIFFERENCE:
41031 return loc0$1 === Location.INTERIOR && loc1$1 !== Location.INTERIOR
41032 case OverlayOp.SYMDIFFERENCE:
41033 return (loc0$1 === Location.INTERIOR && loc1$1 !== Location.INTERIOR) || (loc0$1 !== Location.INTERIOR && loc1$1 === Location.INTERIOR)
41034 default:
41035 }
41036 return false
41037 }
41038};
41039OverlayOp.INTERSECTION = 1;
41040OverlayOp.UNION = 2;
41041OverlayOp.DIFFERENCE = 3;
41042OverlayOp.SYMDIFFERENCE = 4;
41043
41044var FuzzyPointLocator = function FuzzyPointLocator () {
41045 this._g = null;
41046 this._boundaryDistanceTolerance = null;
41047 this._linework = null;
41048 this._ptLocator = new PointLocator();
41049 this._seg = new LineSegment();
41050 var g = arguments[0];
41051 var boundaryDistanceTolerance = arguments[1];
41052 this._g = g;
41053 this._boundaryDistanceTolerance = boundaryDistanceTolerance;
41054 this._linework = this.extractLinework(g);
41055};
41056FuzzyPointLocator.prototype.isWithinToleranceOfBoundary = function isWithinToleranceOfBoundary (pt) {
41057 var this$1 = this;
41058
41059 for (var i = 0; i < this._linework.getNumGeometries(); i++) {
41060 var line = this$1._linework.getGeometryN(i);
41061 var seq = line.getCoordinateSequence();
41062 for (var j = 0; j < seq.size() - 1; j++) {
41063 seq.getCoordinate(j, this$1._seg.p0);
41064 seq.getCoordinate(j + 1, this$1._seg.p1);
41065 var dist = this$1._seg.distance(pt);
41066 if (dist <= this$1._boundaryDistanceTolerance) { return true }
41067 }
41068 }
41069 return false
41070};
41071FuzzyPointLocator.prototype.getLocation = function getLocation (pt) {
41072 if (this.isWithinToleranceOfBoundary(pt)) { return Location.BOUNDARY }
41073 return this._ptLocator.locate(pt, this._g)
41074};
41075FuzzyPointLocator.prototype.extractLinework = function extractLinework (g) {
41076 var extracter = new PolygonalLineworkExtracter();
41077 g.apply(extracter);
41078 var linework = extracter.getLinework();
41079 var lines = GeometryFactory.toLineStringArray(linework);
41080 return g.getFactory().createMultiLineString(lines)
41081};
41082FuzzyPointLocator.prototype.interfaces_ = function interfaces_ () {
41083 return []
41084};
41085FuzzyPointLocator.prototype.getClass = function getClass () {
41086 return FuzzyPointLocator
41087};
41088
41089var PolygonalLineworkExtracter = function PolygonalLineworkExtracter () {
41090 this._linework = null;
41091 this._linework = new ArrayList();
41092};
41093PolygonalLineworkExtracter.prototype.getLinework = function getLinework () {
41094 return this._linework
41095};
41096PolygonalLineworkExtracter.prototype.filter = function filter (g) {
41097 var this$1 = this;
41098
41099 if (g instanceof Polygon) {
41100 var poly = g;
41101 this._linework.add(poly.getExteriorRing());
41102 for (var i = 0; i < poly.getNumInteriorRing(); i++) {
41103 this$1._linework.add(poly.getInteriorRingN(i));
41104 }
41105 }
41106};
41107PolygonalLineworkExtracter.prototype.interfaces_ = function interfaces_ () {
41108 return [GeometryFilter]
41109};
41110PolygonalLineworkExtracter.prototype.getClass = function getClass () {
41111 return PolygonalLineworkExtracter
41112};
41113
41114var OffsetPointGenerator = function OffsetPointGenerator () {
41115 this._g = null;
41116 this._doLeft = true;
41117 this._doRight = true;
41118 var g = arguments[0];
41119 this._g = g;
41120};
41121OffsetPointGenerator.prototype.extractPoints = function extractPoints (line, offsetDistance, offsetPts) {
41122 var this$1 = this;
41123
41124 var pts = line.getCoordinates();
41125 for (var i = 0; i < pts.length - 1; i++) {
41126 this$1.computeOffsetPoints(pts[i], pts[i + 1], offsetDistance, offsetPts);
41127 }
41128};
41129OffsetPointGenerator.prototype.setSidesToGenerate = function setSidesToGenerate (doLeft, doRight) {
41130 this._doLeft = doLeft;
41131 this._doRight = doRight;
41132};
41133OffsetPointGenerator.prototype.getPoints = function getPoints (offsetDistance) {
41134 var this$1 = this;
41135
41136 var offsetPts = new ArrayList();
41137 var lines = LinearComponentExtracter.getLines(this._g);
41138 for (var i = lines.iterator(); i.hasNext();) {
41139 var line = i.next();
41140 this$1.extractPoints(line, offsetDistance, offsetPts);
41141 }
41142 return offsetPts
41143};
41144OffsetPointGenerator.prototype.computeOffsetPoints = function computeOffsetPoints (p0, p1, offsetDistance, offsetPts) {
41145 var dx = p1.x - p0.x;
41146 var dy = p1.y - p0.y;
41147 var len = Math.sqrt(dx * dx + dy * dy);
41148 var ux = offsetDistance * dx / len;
41149 var uy = offsetDistance * dy / len;
41150 var midX = (p1.x + p0.x) / 2;
41151 var midY = (p1.y + p0.y) / 2;
41152 if (this._doLeft) {
41153 var offsetLeft = new Coordinate(midX - uy, midY + ux);
41154 offsetPts.add(offsetLeft);
41155 }
41156 if (this._doRight) {
41157 var offsetRight = new Coordinate(midX + uy, midY - ux);
41158 offsetPts.add(offsetRight);
41159 }
41160};
41161OffsetPointGenerator.prototype.interfaces_ = function interfaces_ () {
41162 return []
41163};
41164OffsetPointGenerator.prototype.getClass = function getClass () {
41165 return OffsetPointGenerator
41166};
41167
41168var OverlayResultValidator = function OverlayResultValidator () {
41169 this._geom = null;
41170 this._locFinder = null;
41171 this._location = new Array(3).fill(null);
41172 this._invalidLocation = null;
41173 this._boundaryDistanceTolerance = OverlayResultValidator.TOLERANCE;
41174 this._testCoords = new ArrayList();
41175 var a = arguments[0];
41176 var b = arguments[1];
41177 var result = arguments[2];
41178 this._boundaryDistanceTolerance = OverlayResultValidator.computeBoundaryDistanceTolerance(a, b);
41179 this._geom = [a, b, result];
41180 this._locFinder = [new FuzzyPointLocator(this._geom[0], this._boundaryDistanceTolerance), new FuzzyPointLocator(this._geom[1], this._boundaryDistanceTolerance), new FuzzyPointLocator(this._geom[2], this._boundaryDistanceTolerance)];
41181};
41182
41183var staticAccessors$46 = { TOLERANCE: { configurable: true } };
41184OverlayResultValidator.prototype.reportResult = function reportResult (overlayOp, location, expectedInterior) {
41185 System.out.println('Overlay result invalid - A:' + Location.toLocationSymbol(location[0]) + ' B:' + Location.toLocationSymbol(location[1]) + ' expected:' + (expectedInterior ? 'i' : 'e') + ' actual:' + Location.toLocationSymbol(location[2]));
41186};
41187OverlayResultValidator.prototype.isValid = function isValid (overlayOp) {
41188 this.addTestPts(this._geom[0]);
41189 this.addTestPts(this._geom[1]);
41190 var isValid = this.checkValid(overlayOp);
41191 return isValid
41192};
41193OverlayResultValidator.prototype.checkValid = function checkValid () {
41194 var this$1 = this;
41195
41196 if (arguments.length === 1) {
41197 var overlayOp = arguments[0];
41198 for (var i = 0; i < this._testCoords.size(); i++) {
41199 var pt = this$1._testCoords.get(i);
41200 if (!this$1.checkValid(overlayOp, pt)) {
41201 this$1._invalidLocation = pt;
41202 return false
41203 }
41204 }
41205 return true
41206 } else if (arguments.length === 2) {
41207 var overlayOp$1 = arguments[0];
41208 var pt$1 = arguments[1];
41209 this._location[0] = this._locFinder[0].getLocation(pt$1);
41210 this._location[1] = this._locFinder[1].getLocation(pt$1);
41211 this._location[2] = this._locFinder[2].getLocation(pt$1);
41212 if (OverlayResultValidator.hasLocation(this._location, Location.BOUNDARY)) { return true }
41213 return this.isValidResult(overlayOp$1, this._location)
41214 }
41215};
41216OverlayResultValidator.prototype.addTestPts = function addTestPts (g) {
41217 var ptGen = new OffsetPointGenerator(g);
41218 this._testCoords.addAll(ptGen.getPoints(5 * this._boundaryDistanceTolerance));
41219};
41220OverlayResultValidator.prototype.isValidResult = function isValidResult (overlayOp, location) {
41221 var expectedInterior = OverlayOp.isResultOfOp(location[0], location[1], overlayOp);
41222 var resultInInterior = location[2] === Location.INTERIOR;
41223 var isValid = !(expectedInterior ^ resultInInterior);
41224 if (!isValid) { this.reportResult(overlayOp, location, expectedInterior); }
41225 return isValid
41226};
41227OverlayResultValidator.prototype.getInvalidLocation = function getInvalidLocation () {
41228 return this._invalidLocation
41229};
41230OverlayResultValidator.prototype.interfaces_ = function interfaces_ () {
41231 return []
41232};
41233OverlayResultValidator.prototype.getClass = function getClass () {
41234 return OverlayResultValidator
41235};
41236OverlayResultValidator.hasLocation = function hasLocation (location, loc) {
41237 for (var i = 0; i < 3; i++) {
41238 if (location[i] === loc) { return true }
41239 }
41240 return false
41241};
41242OverlayResultValidator.computeBoundaryDistanceTolerance = function computeBoundaryDistanceTolerance (g0, g1) {
41243 return Math.min(GeometrySnapper.computeSizeBasedSnapTolerance(g0), GeometrySnapper.computeSizeBasedSnapTolerance(g1))
41244};
41245OverlayResultValidator.isValid = function isValid (a, b, overlayOp, result) {
41246 var validator = new OverlayResultValidator(a, b, result);
41247 return validator.isValid(overlayOp)
41248};
41249staticAccessors$46.TOLERANCE.get = function () { return 0.000001 };
41250
41251Object.defineProperties( OverlayResultValidator, staticAccessors$46 );
41252
41253// operation.overlay
41254
41255var GeometryCombiner = function GeometryCombiner (geoms) {
41256 this._geomFactory = null;
41257 this._skipEmpty = false;
41258 this._inputGeoms = null;
41259 this._geomFactory = GeometryCombiner.extractFactory(geoms);
41260 this._inputGeoms = geoms;
41261};
41262GeometryCombiner.prototype.extractElements = function extractElements (geom, elems) {
41263 var this$1 = this;
41264
41265 if (geom === null) { return null }
41266 for (var i = 0; i < geom.getNumGeometries(); i++) {
41267 var elemGeom = geom.getGeometryN(i);
41268 if (this$1._skipEmpty && elemGeom.isEmpty()) { continue }
41269 elems.add(elemGeom);
41270 }
41271};
41272GeometryCombiner.prototype.combine = function combine () {
41273 var this$1 = this;
41274
41275 var elems = new ArrayList();
41276 for (var i = this._inputGeoms.iterator(); i.hasNext();) {
41277 var g = i.next();
41278 this$1.extractElements(g, elems);
41279 }
41280 if (elems.size() === 0) {
41281 if (this._geomFactory !== null) {
41282 return this._geomFactory.createGeometryCollection(null)
41283 }
41284 return null
41285 }
41286 return this._geomFactory.buildGeometry(elems)
41287};
41288GeometryCombiner.prototype.interfaces_ = function interfaces_ () {
41289 return []
41290};
41291GeometryCombiner.prototype.getClass = function getClass () {
41292 return GeometryCombiner
41293};
41294GeometryCombiner.combine = function combine () {
41295 if (arguments.length === 1) {
41296 var geoms = arguments[0];
41297 var combiner = new GeometryCombiner(geoms);
41298 return combiner.combine()
41299 } else if (arguments.length === 2) {
41300 var g0 = arguments[0];
41301 var g1 = arguments[1];
41302 var combiner$1 = new GeometryCombiner(GeometryCombiner.createList(g0, g1));
41303 return combiner$1.combine()
41304 } else if (arguments.length === 3) {
41305 var g0$1 = arguments[0];
41306 var g1$1 = arguments[1];
41307 var g2 = arguments[2];
41308 var combiner$2 = new GeometryCombiner(GeometryCombiner.createList(g0$1, g1$1, g2));
41309 return combiner$2.combine()
41310 }
41311};
41312GeometryCombiner.extractFactory = function extractFactory (geoms) {
41313 if (geoms.isEmpty()) { return null }
41314 return geoms.iterator().next().getFactory()
41315};
41316GeometryCombiner.createList = function createList () {
41317 if (arguments.length === 2) {
41318 var obj0 = arguments[0];
41319 var obj1 = arguments[1];
41320 var list = new ArrayList();
41321 list.add(obj0);
41322 list.add(obj1);
41323 return list
41324 } else if (arguments.length === 3) {
41325 var obj0$1 = arguments[0];
41326 var obj1$1 = arguments[1];
41327 var obj2 = arguments[2];
41328 var list$1 = new ArrayList();
41329 list$1.add(obj0$1);
41330 list$1.add(obj1$1);
41331 list$1.add(obj2);
41332 return list$1
41333 }
41334};
41335
41336var CascadedPolygonUnion = function CascadedPolygonUnion () {
41337 this._inputPolys = null;
41338 this._geomFactory = null;
41339 var polys = arguments[0];
41340 this._inputPolys = polys;
41341 if (this._inputPolys === null) { this._inputPolys = new ArrayList(); }
41342};
41343
41344var staticAccessors$47 = { STRTREE_NODE_CAPACITY: { configurable: true } };
41345CascadedPolygonUnion.prototype.reduceToGeometries = function reduceToGeometries (geomTree) {
41346 var this$1 = this;
41347
41348 var geoms = new ArrayList();
41349 for (var i = geomTree.iterator(); i.hasNext();) {
41350 var o = i.next();
41351 var geom = null;
41352 if (hasInterface(o, List)) {
41353 geom = this$1.unionTree(o);
41354 } else if (o instanceof Geometry) {
41355 geom = o;
41356 }
41357 geoms.add(geom);
41358 }
41359 return geoms
41360};
41361CascadedPolygonUnion.prototype.extractByEnvelope = function extractByEnvelope (env, geom, disjointGeoms) {
41362 var intersectingGeoms = new ArrayList();
41363 for (var i = 0; i < geom.getNumGeometries(); i++) {
41364 var elem = geom.getGeometryN(i);
41365 if (elem.getEnvelopeInternal().intersects(env)) { intersectingGeoms.add(elem); } else { disjointGeoms.add(elem); }
41366 }
41367 return this._geomFactory.buildGeometry(intersectingGeoms)
41368};
41369CascadedPolygonUnion.prototype.unionOptimized = function unionOptimized (g0, g1) {
41370 var g0Env = g0.getEnvelopeInternal();
41371 var g1Env = g1.getEnvelopeInternal();
41372 if (!g0Env.intersects(g1Env)) {
41373 var combo = GeometryCombiner.combine(g0, g1);
41374 return combo
41375 }
41376 if (g0.getNumGeometries() <= 1 && g1.getNumGeometries() <= 1) { return this.unionActual(g0, g1) }
41377 var commonEnv = g0Env.intersection(g1Env);
41378 return this.unionUsingEnvelopeIntersection(g0, g1, commonEnv)
41379};
41380CascadedPolygonUnion.prototype.union = function union () {
41381 if (this._inputPolys === null) { throw new Error('union() method cannot be called twice') }
41382 if (this._inputPolys.isEmpty()) { return null }
41383 this._geomFactory = this._inputPolys.iterator().next().getFactory();
41384 var index = new STRtree(CascadedPolygonUnion.STRTREE_NODE_CAPACITY);
41385 for (var i = this._inputPolys.iterator(); i.hasNext();) {
41386 var item = i.next();
41387 index.insert(item.getEnvelopeInternal(), item);
41388 }
41389 this._inputPolys = null;
41390 var itemTree = index.itemsTree();
41391 var unionAll = this.unionTree(itemTree);
41392 return unionAll
41393};
41394CascadedPolygonUnion.prototype.binaryUnion = function binaryUnion () {
41395 if (arguments.length === 1) {
41396 var geoms = arguments[0];
41397 return this.binaryUnion(geoms, 0, geoms.size())
41398 } else if (arguments.length === 3) {
41399 var geoms$1 = arguments[0];
41400 var start = arguments[1];
41401 var end = arguments[2];
41402 if (end - start <= 1) {
41403 var g0 = CascadedPolygonUnion.getGeometry(geoms$1, start);
41404 return this.unionSafe(g0, null)
41405 } else if (end - start === 2) {
41406 return this.unionSafe(CascadedPolygonUnion.getGeometry(geoms$1, start), CascadedPolygonUnion.getGeometry(geoms$1, start + 1))
41407 } else {
41408 var mid = Math.trunc((end + start) / 2);
41409 var g0$1 = this.binaryUnion(geoms$1, start, mid);
41410 var g1 = this.binaryUnion(geoms$1, mid, end);
41411 return this.unionSafe(g0$1, g1)
41412 }
41413 }
41414};
41415CascadedPolygonUnion.prototype.repeatedUnion = function repeatedUnion (geoms) {
41416 var union = null;
41417 for (var i = geoms.iterator(); i.hasNext();) {
41418 var g = i.next();
41419 if (union === null) { union = g.copy(); } else { union = union.union(g); }
41420 }
41421 return union
41422};
41423CascadedPolygonUnion.prototype.unionSafe = function unionSafe (g0, g1) {
41424 if (g0 === null && g1 === null) { return null }
41425 if (g0 === null) { return g1.copy() }
41426 if (g1 === null) { return g0.copy() }
41427 return this.unionOptimized(g0, g1)
41428};
41429CascadedPolygonUnion.prototype.unionActual = function unionActual (g0, g1) {
41430 return CascadedPolygonUnion.restrictToPolygons(g0.union(g1))
41431};
41432CascadedPolygonUnion.prototype.unionTree = function unionTree (geomTree) {
41433 var geoms = this.reduceToGeometries(geomTree);
41434 var union = this.binaryUnion(geoms);
41435 return union
41436};
41437CascadedPolygonUnion.prototype.unionUsingEnvelopeIntersection = function unionUsingEnvelopeIntersection (g0, g1, common) {
41438 var disjointPolys = new ArrayList();
41439 var g0Int = this.extractByEnvelope(common, g0, disjointPolys);
41440 var g1Int = this.extractByEnvelope(common, g1, disjointPolys);
41441 var union = this.unionActual(g0Int, g1Int);
41442 disjointPolys.add(union);
41443 var overallUnion = GeometryCombiner.combine(disjointPolys);
41444 return overallUnion
41445};
41446CascadedPolygonUnion.prototype.bufferUnion = function bufferUnion () {
41447 if (arguments.length === 1) {
41448 var geoms = arguments[0];
41449 var factory = geoms.get(0).getFactory();
41450 var gColl = factory.buildGeometry(geoms);
41451 var unionAll = gColl.buffer(0.0);
41452 return unionAll
41453 } else if (arguments.length === 2) {
41454 var g0 = arguments[0];
41455 var g1 = arguments[1];
41456 var factory$1 = g0.getFactory();
41457 var gColl$1 = factory$1.createGeometryCollection([g0, g1]);
41458 var unionAll$1 = gColl$1.buffer(0.0);
41459 return unionAll$1
41460 }
41461};
41462CascadedPolygonUnion.prototype.interfaces_ = function interfaces_ () {
41463 return []
41464};
41465CascadedPolygonUnion.prototype.getClass = function getClass () {
41466 return CascadedPolygonUnion
41467};
41468CascadedPolygonUnion.restrictToPolygons = function restrictToPolygons (g) {
41469 if (hasInterface(g, Polygonal)) {
41470 return g
41471 }
41472 var polygons = PolygonExtracter.getPolygons(g);
41473 if (polygons.size() === 1) { return polygons.get(0) }
41474 return g.getFactory().createMultiPolygon(GeometryFactory.toPolygonArray(polygons))
41475};
41476CascadedPolygonUnion.getGeometry = function getGeometry (list, index) {
41477 if (index >= list.size()) { return null }
41478 return list.get(index)
41479};
41480CascadedPolygonUnion.union = function union (polys) {
41481 var op = new CascadedPolygonUnion(polys);
41482 return op.union()
41483};
41484staticAccessors$47.STRTREE_NODE_CAPACITY.get = function () { return 4 };
41485
41486Object.defineProperties( CascadedPolygonUnion, staticAccessors$47 );
41487
41488var UnionOp = function UnionOp () {};
41489
41490UnionOp.prototype.interfaces_ = function interfaces_ () {
41491 return []
41492};
41493UnionOp.prototype.getClass = function getClass () {
41494 return UnionOp
41495};
41496UnionOp.union = function union (g, other) {
41497 if (g.isEmpty() || other.isEmpty()) {
41498 if (g.isEmpty() && other.isEmpty()) { return OverlayOp.createEmptyResult(OverlayOp.UNION, g, other, g.getFactory()) }
41499 if (g.isEmpty()) { return other.copy() }
41500 if (other.isEmpty()) { return g.copy() }
41501 }
41502 g.checkNotGeometryCollection(g);
41503 g.checkNotGeometryCollection(other);
41504 return SnapIfNeededOverlayOp.overlayOp(g, other, OverlayOp.UNION)
41505};
41506
41507/**
41508 * Finds the difference between two {@link Polygon|polygons} by clipping the second polygon from the first.
41509 *
41510 * @name difference
41511 * @param {Feature<Polygon|MultiPolygon>} polygon1 input Polygon feature
41512 * @param {Feature<Polygon|MultiPolygon>} polygon2 Polygon feature to difference from polygon1
41513 * @returns {Feature<Polygon|MultiPolygon>|null} a Polygon or MultiPolygon feature showing the area of `polygon1` excluding the area of `polygon2` (if empty returns `null`)
41514 * @example
41515 * var polygon1 = turf.polygon([[
41516 * [128, -26],
41517 * [141, -26],
41518 * [141, -21],
41519 * [128, -21],
41520 * [128, -26]
41521 * ]], {
41522 * "fill": "#F00",
41523 * "fill-opacity": 0.1
41524 * });
41525 * var polygon2 = turf.polygon([[
41526 * [126, -28],
41527 * [140, -28],
41528 * [140, -20],
41529 * [126, -20],
41530 * [126, -28]
41531 * ]], {
41532 * "fill": "#00F",
41533 * "fill-opacity": 0.1
41534 * });
41535 *
41536 * var difference = turf.difference(polygon1, polygon2);
41537 *
41538 * //addToMap
41539 * var addToMap = [polygon1, polygon2, difference];
41540 */
41541function difference(polygon1, polygon2) {
41542 var geom1 = getGeom(polygon1);
41543 var geom2 = getGeom(polygon2);
41544 var properties = polygon1.properties || {};
41545
41546 // Issue #721 - JSTS can't handle empty polygons
41547 geom1 = removeEmptyPolygon(geom1);
41548 geom2 = removeEmptyPolygon(geom2);
41549 if (!geom1) return null;
41550 if (!geom2) return feature(geom1, properties);
41551
41552 // JSTS difference operation
41553 var reader = new GeoJSONReader();
41554 var a = reader.read(geom1);
41555 var b = reader.read(geom2);
41556 var differenced = OverlayOp.difference(a, b);
41557 if (differenced.isEmpty()) return null;
41558 var writer = new GeoJSONWriter();
41559 var geom = writer.write(differenced);
41560
41561 return feature(geom, properties);
41562}
41563
41564/**
41565 * Detect Empty Polygon
41566 *
41567 * @private
41568 * @param {Geometry<Polygon|MultiPolygon>} geom Geometry Object
41569 * @returns {Geometry<Polygon|MultiPolygon>|null} removed any polygons with no areas
41570 */
41571function removeEmptyPolygon(geom) {
41572 switch (geom.type) {
41573 case 'Polygon':
41574 if (area$1(geom) > 1) return geom;
41575 return null;
41576 case 'MultiPolygon':
41577 var coordinates = [];
41578 flattenEach(geom, function (feature$$1) {
41579 if (area$1(feature$$1) > 1) coordinates.push(feature$$1.geometry.coordinates);
41580 });
41581 if (coordinates.length) return {type: 'MultiPolygon', coordinates: coordinates};
41582 }
41583}
41584
41585// Adds floating point numbers with twice the normal precision.
41586// Reference: J. R. Shewchuk, Adaptive Precision Floating-Point Arithmetic and
41587// Fast Robust Geometric Predicates, Discrete & Computational Geometry 18(3)
41588// 305–363 (1997).
41589// Code adapted from GeographicLib by Charles F. F. Karney,
41590// http://geographiclib.sourceforge.net/
41591
41592var adder = function() {
41593 return new Adder;
41594};
41595
41596function Adder() {
41597 this.reset();
41598}
41599
41600Adder.prototype = {
41601 constructor: Adder,
41602 reset: function() {
41603 this.s = // rounded value
41604 this.t = 0; // exact error
41605 },
41606 add: function(y) {
41607 add$1(temp, y, this.t);
41608 add$1(this, temp.s, this.s);
41609 if (this.s) this.t += temp.t;
41610 else this.s = temp.t;
41611 },
41612 valueOf: function() {
41613 return this.s;
41614 }
41615};
41616
41617var temp = new Adder;
41618
41619function add$1(adder, a, b) {
41620 var x = adder.s = a + b,
41621 bv = x - a,
41622 av = x - bv;
41623 adder.t = (a - av) + (b - bv);
41624}
41625
41626var epsilon$1 = 1e-6;
41627
41628var pi = Math.PI;
41629var halfPi = pi / 2;
41630var quarterPi = pi / 4;
41631var tau = pi * 2;
41632
41633var degrees = 180 / pi;
41634var radians = pi / 180;
41635
41636var abs = Math.abs;
41637var atan = Math.atan;
41638var atan2 = Math.atan2;
41639var cos = Math.cos;
41640
41641var exp = Math.exp;
41642
41643var log = Math.log;
41644
41645var sin = Math.sin;
41646
41647var sqrt = Math.sqrt;
41648var tan = Math.tan;
41649
41650function acos(x) {
41651 return x > 1 ? 0 : x < -1 ? pi : Math.acos(x);
41652}
41653
41654function asin(x) {
41655 return x > 1 ? halfPi : x < -1 ? -halfPi : Math.asin(x);
41656}
41657
41658function noop() {}
41659
41660function streamGeometry(geometry, stream) {
41661 if (geometry && streamGeometryType.hasOwnProperty(geometry.type)) {
41662 streamGeometryType[geometry.type](geometry, stream);
41663 }
41664}
41665
41666var streamObjectType = {
41667 Feature: function(object, stream) {
41668 streamGeometry(object.geometry, stream);
41669 },
41670 FeatureCollection: function(object, stream) {
41671 var features = object.features, i = -1, n = features.length;
41672 while (++i < n) streamGeometry(features[i].geometry, stream);
41673 }
41674};
41675
41676var streamGeometryType = {
41677 Sphere: function(object, stream) {
41678 stream.sphere();
41679 },
41680 Point: function(object, stream) {
41681 object = object.coordinates;
41682 stream.point(object[0], object[1], object[2]);
41683 },
41684 MultiPoint: function(object, stream) {
41685 var coordinates = object.coordinates, i = -1, n = coordinates.length;
41686 while (++i < n) object = coordinates[i], stream.point(object[0], object[1], object[2]);
41687 },
41688 LineString: function(object, stream) {
41689 streamLine(object.coordinates, stream, 0);
41690 },
41691 MultiLineString: function(object, stream) {
41692 var coordinates = object.coordinates, i = -1, n = coordinates.length;
41693 while (++i < n) streamLine(coordinates[i], stream, 0);
41694 },
41695 Polygon: function(object, stream) {
41696 streamPolygon(object.coordinates, stream);
41697 },
41698 MultiPolygon: function(object, stream) {
41699 var coordinates = object.coordinates, i = -1, n = coordinates.length;
41700 while (++i < n) streamPolygon(coordinates[i], stream);
41701 },
41702 GeometryCollection: function(object, stream) {
41703 var geometries = object.geometries, i = -1, n = geometries.length;
41704 while (++i < n) streamGeometry(geometries[i], stream);
41705 }
41706};
41707
41708function streamLine(coordinates, stream, closed) {
41709 var i = -1, n = coordinates.length - closed, coordinate;
41710 stream.lineStart();
41711 while (++i < n) coordinate = coordinates[i], stream.point(coordinate[0], coordinate[1], coordinate[2]);
41712 stream.lineEnd();
41713}
41714
41715function streamPolygon(coordinates, stream) {
41716 var i = -1, n = coordinates.length;
41717 stream.polygonStart();
41718 while (++i < n) streamLine(coordinates[i], stream, 1);
41719 stream.polygonEnd();
41720}
41721
41722var geoStream = function(object, stream) {
41723 if (object && streamObjectType.hasOwnProperty(object.type)) {
41724 streamObjectType[object.type](object, stream);
41725 } else {
41726 streamGeometry(object, stream);
41727 }
41728};
41729
41730var areaRingSum = adder();
41731
41732var areaSum = adder();
41733
41734function spherical(cartesian) {
41735 return [atan2(cartesian[1], cartesian[0]), asin(cartesian[2])];
41736}
41737
41738function cartesian(spherical) {
41739 var lambda = spherical[0], phi = spherical[1], cosPhi = cos(phi);
41740 return [cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi)];
41741}
41742
41743function cartesianDot(a, b) {
41744 return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
41745}
41746
41747function cartesianCross(a, b) {
41748 return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
41749}
41750
41751// TODO return a
41752function cartesianAddInPlace(a, b) {
41753 a[0] += b[0], a[1] += b[1], a[2] += b[2];
41754}
41755
41756function cartesianScale(vector, k) {
41757 return [vector[0] * k, vector[1] * k, vector[2] * k];
41758}
41759
41760// TODO return d
41761function cartesianNormalizeInPlace(d) {
41762 var l = sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
41763 d[0] /= l, d[1] /= l, d[2] /= l;
41764}
41765
41766var deltaSum = adder();
41767
41768var compose = function(a, b) {
41769
41770 function compose(x, y) {
41771 return x = a(x, y), b(x[0], x[1]);
41772 }
41773
41774 if (a.invert && b.invert) compose.invert = function(x, y) {
41775 return x = b.invert(x, y), x && a.invert(x[0], x[1]);
41776 };
41777
41778 return compose;
41779};
41780
41781function rotationIdentity(lambda, phi) {
41782 return [lambda > pi ? lambda - tau : lambda < -pi ? lambda + tau : lambda, phi];
41783}
41784
41785rotationIdentity.invert = rotationIdentity;
41786
41787function rotateRadians(deltaLambda, deltaPhi, deltaGamma) {
41788 return (deltaLambda %= tau) ? (deltaPhi || deltaGamma ? compose(rotationLambda(deltaLambda), rotationPhiGamma(deltaPhi, deltaGamma))
41789 : rotationLambda(deltaLambda))
41790 : (deltaPhi || deltaGamma ? rotationPhiGamma(deltaPhi, deltaGamma)
41791 : rotationIdentity);
41792}
41793
41794function forwardRotationLambda(deltaLambda) {
41795 return function(lambda, phi) {
41796 return lambda += deltaLambda, [lambda > pi ? lambda - tau : lambda < -pi ? lambda + tau : lambda, phi];
41797 };
41798}
41799
41800function rotationLambda(deltaLambda) {
41801 var rotation = forwardRotationLambda(deltaLambda);
41802 rotation.invert = forwardRotationLambda(-deltaLambda);
41803 return rotation;
41804}
41805
41806function rotationPhiGamma(deltaPhi, deltaGamma) {
41807 var cosDeltaPhi = cos(deltaPhi),
41808 sinDeltaPhi = sin(deltaPhi),
41809 cosDeltaGamma = cos(deltaGamma),
41810 sinDeltaGamma = sin(deltaGamma);
41811
41812 function rotation(lambda, phi) {
41813 var cosPhi = cos(phi),
41814 x = cos(lambda) * cosPhi,
41815 y = sin(lambda) * cosPhi,
41816 z = sin(phi),
41817 k = z * cosDeltaPhi + x * sinDeltaPhi;
41818 return [
41819 atan2(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi),
41820 asin(k * cosDeltaGamma + y * sinDeltaGamma)
41821 ];
41822 }
41823
41824 rotation.invert = function(lambda, phi) {
41825 var cosPhi = cos(phi),
41826 x = cos(lambda) * cosPhi,
41827 y = sin(lambda) * cosPhi,
41828 z = sin(phi),
41829 k = z * cosDeltaGamma - y * sinDeltaGamma;
41830 return [
41831 atan2(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi),
41832 asin(k * cosDeltaPhi - x * sinDeltaPhi)
41833 ];
41834 };
41835
41836 return rotation;
41837}
41838
41839var rotation = function(rotate) {
41840 rotate = rotateRadians(rotate[0] * radians, rotate[1] * radians, rotate.length > 2 ? rotate[2] * radians : 0);
41841
41842 function forward(coordinates) {
41843 coordinates = rotate(coordinates[0] * radians, coordinates[1] * radians);
41844 return coordinates[0] *= degrees, coordinates[1] *= degrees, coordinates;
41845 }
41846
41847 forward.invert = function(coordinates) {
41848 coordinates = rotate.invert(coordinates[0] * radians, coordinates[1] * radians);
41849 return coordinates[0] *= degrees, coordinates[1] *= degrees, coordinates;
41850 };
41851
41852 return forward;
41853};
41854
41855// Generates a circle centered at [0°, 0°], with a given radius and precision.
41856function circleStream(stream, radius, delta, direction, t0, t1) {
41857 if (!delta) return;
41858 var cosRadius = cos(radius),
41859 sinRadius = sin(radius),
41860 step = direction * delta;
41861 if (t0 == null) {
41862 t0 = radius + direction * tau;
41863 t1 = radius - step / 2;
41864 } else {
41865 t0 = circleRadius(cosRadius, t0);
41866 t1 = circleRadius(cosRadius, t1);
41867 if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau;
41868 }
41869 for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
41870 point = spherical([cosRadius, -sinRadius * cos(t), -sinRadius * sin(t)]);
41871 stream.point(point[0], point[1]);
41872 }
41873}
41874
41875// Returns the signed angle of a cartesian point relative to [cosRadius, 0, 0].
41876function circleRadius(cosRadius, point) {
41877 point = cartesian(point), point[0] -= cosRadius;
41878 cartesianNormalizeInPlace(point);
41879 var radius = acos(-point[1]);
41880 return ((-point[2] < 0 ? -radius : radius) + tau - epsilon$1) % tau;
41881}
41882
41883var clipBuffer = function() {
41884 var lines = [],
41885 line;
41886 return {
41887 point: function(x, y) {
41888 line.push([x, y]);
41889 },
41890 lineStart: function() {
41891 lines.push(line = []);
41892 },
41893 lineEnd: noop,
41894 rejoin: function() {
41895 if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
41896 },
41897 result: function() {
41898 var result = lines;
41899 lines = [];
41900 line = null;
41901 return result;
41902 }
41903 };
41904};
41905
41906var clipLine = function(a, b, x0, y0, x1, y1) {
41907 var ax = a[0],
41908 ay = a[1],
41909 bx = b[0],
41910 by = b[1],
41911 t0 = 0,
41912 t1 = 1,
41913 dx = bx - ax,
41914 dy = by - ay,
41915 r;
41916
41917 r = x0 - ax;
41918 if (!dx && r > 0) return;
41919 r /= dx;
41920 if (dx < 0) {
41921 if (r < t0) return;
41922 if (r < t1) t1 = r;
41923 } else if (dx > 0) {
41924 if (r > t1) return;
41925 if (r > t0) t0 = r;
41926 }
41927
41928 r = x1 - ax;
41929 if (!dx && r < 0) return;
41930 r /= dx;
41931 if (dx < 0) {
41932 if (r > t1) return;
41933 if (r > t0) t0 = r;
41934 } else if (dx > 0) {
41935 if (r < t0) return;
41936 if (r < t1) t1 = r;
41937 }
41938
41939 r = y0 - ay;
41940 if (!dy && r > 0) return;
41941 r /= dy;
41942 if (dy < 0) {
41943 if (r < t0) return;
41944 if (r < t1) t1 = r;
41945 } else if (dy > 0) {
41946 if (r > t1) return;
41947 if (r > t0) t0 = r;
41948 }
41949
41950 r = y1 - ay;
41951 if (!dy && r < 0) return;
41952 r /= dy;
41953 if (dy < 0) {
41954 if (r > t1) return;
41955 if (r > t0) t0 = r;
41956 } else if (dy > 0) {
41957 if (r < t0) return;
41958 if (r < t1) t1 = r;
41959 }
41960
41961 if (t0 > 0) a[0] = ax + t0 * dx, a[1] = ay + t0 * dy;
41962 if (t1 < 1) b[0] = ax + t1 * dx, b[1] = ay + t1 * dy;
41963 return true;
41964};
41965
41966var pointEqual = function(a, b) {
41967 return abs(a[0] - b[0]) < epsilon$1 && abs(a[1] - b[1]) < epsilon$1;
41968};
41969
41970function Intersection(point, points, other, entry) {
41971 this.x = point;
41972 this.z = points;
41973 this.o = other; // another intersection
41974 this.e = entry; // is an entry?
41975 this.v = false; // visited
41976 this.n = this.p = null; // next & previous
41977}
41978
41979// A generalized polygon clipping algorithm: given a polygon that has been cut
41980// into its visible line segments, and rejoins the segments by interpolating
41981// along the clip edge.
41982var clipPolygon$1 = function(segments, compareIntersection, startInside, interpolate, stream) {
41983 var subject = [],
41984 clip = [],
41985 i,
41986 n;
41987
41988 segments.forEach(function(segment) {
41989 if ((n = segment.length - 1) <= 0) return;
41990 var n, p0 = segment[0], p1 = segment[n], x;
41991
41992 // If the first and last points of a segment are coincident, then treat as a
41993 // closed ring. TODO if all rings are closed, then the winding order of the
41994 // exterior ring should be checked.
41995 if (pointEqual(p0, p1)) {
41996 stream.lineStart();
41997 for (i = 0; i < n; ++i) stream.point((p0 = segment[i])[0], p0[1]);
41998 stream.lineEnd();
41999 return;
42000 }
42001
42002 subject.push(x = new Intersection(p0, segment, null, true));
42003 clip.push(x.o = new Intersection(p0, null, x, false));
42004 subject.push(x = new Intersection(p1, segment, null, false));
42005 clip.push(x.o = new Intersection(p1, null, x, true));
42006 });
42007
42008 if (!subject.length) return;
42009
42010 clip.sort(compareIntersection);
42011 link(subject);
42012 link(clip);
42013
42014 for (i = 0, n = clip.length; i < n; ++i) {
42015 clip[i].e = startInside = !startInside;
42016 }
42017
42018 var start = subject[0],
42019 points,
42020 point;
42021
42022 while (1) {
42023 // Find first unvisited intersection.
42024 var current = start,
42025 isSubject = true;
42026 while (current.v) if ((current = current.n) === start) return;
42027 points = current.z;
42028 stream.lineStart();
42029 do {
42030 current.v = current.o.v = true;
42031 if (current.e) {
42032 if (isSubject) {
42033 for (i = 0, n = points.length; i < n; ++i) stream.point((point = points[i])[0], point[1]);
42034 } else {
42035 interpolate(current.x, current.n.x, 1, stream);
42036 }
42037 current = current.n;
42038 } else {
42039 if (isSubject) {
42040 points = current.p.z;
42041 for (i = points.length - 1; i >= 0; --i) stream.point((point = points[i])[0], point[1]);
42042 } else {
42043 interpolate(current.x, current.p.x, -1, stream);
42044 }
42045 current = current.p;
42046 }
42047 current = current.o;
42048 points = current.z;
42049 isSubject = !isSubject;
42050 } while (!current.v);
42051 stream.lineEnd();
42052 }
42053};
42054
42055function link(array) {
42056 if (!(n = array.length)) return;
42057 var n,
42058 i = 0,
42059 a = array[0],
42060 b;
42061 while (++i < n) {
42062 a.n = b = array[i];
42063 b.p = a;
42064 a = b;
42065 }
42066 a.n = b = array[0];
42067 b.p = a;
42068}
42069
42070var ascending = function(a, b) {
42071 return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
42072};
42073
42074var bisector = function(compare) {
42075 if (compare.length === 1) compare = ascendingComparator(compare);
42076 return {
42077 left: function(a, x, lo, hi) {
42078 if (lo == null) lo = 0;
42079 if (hi == null) hi = a.length;
42080 while (lo < hi) {
42081 var mid = lo + hi >>> 1;
42082 if (compare(a[mid], x) < 0) lo = mid + 1;
42083 else hi = mid;
42084 }
42085 return lo;
42086 },
42087 right: function(a, x, lo, hi) {
42088 if (lo == null) lo = 0;
42089 if (hi == null) hi = a.length;
42090 while (lo < hi) {
42091 var mid = lo + hi >>> 1;
42092 if (compare(a[mid], x) > 0) hi = mid;
42093 else lo = mid + 1;
42094 }
42095 return lo;
42096 }
42097 };
42098};
42099
42100function ascendingComparator(f) {
42101 return function(d, x) {
42102 return ascending(f(d), x);
42103 };
42104}
42105
42106var ascendingBisect = bisector(ascending);
42107
42108var merge$1 = function(arrays) {
42109 var n = arrays.length,
42110 m,
42111 i = -1,
42112 j = 0,
42113 merged,
42114 array;
42115
42116 while (++i < n) j += arrays[i].length;
42117 merged = new Array(j);
42118
42119 while (--n >= 0) {
42120 array = arrays[n];
42121 m = array.length;
42122 while (--m >= 0) {
42123 merged[--j] = array[m];
42124 }
42125 }
42126
42127 return merged;
42128};
42129
42130var clipMax = 1e9;
42131var clipMin = -clipMax;
42132
42133// TODO Use d3-polygon’s polygonContains here for the ring check?
42134// TODO Eliminate duplicate buffering in clipBuffer and polygon.push?
42135
42136function clipExtent(x0, y0, x1, y1) {
42137
42138 function visible(x, y) {
42139 return x0 <= x && x <= x1 && y0 <= y && y <= y1;
42140 }
42141
42142 function interpolate(from, to, direction, stream) {
42143 var a = 0, a1 = 0;
42144 if (from == null
42145 || (a = corner(from, direction)) !== (a1 = corner(to, direction))
42146 || comparePoint(from, to) < 0 ^ direction > 0) {
42147 do stream.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
42148 while ((a = (a + direction + 4) % 4) !== a1);
42149 } else {
42150 stream.point(to[0], to[1]);
42151 }
42152 }
42153
42154 function corner(p, direction) {
42155 return abs(p[0] - x0) < epsilon$1 ? direction > 0 ? 0 : 3
42156 : abs(p[0] - x1) < epsilon$1 ? direction > 0 ? 2 : 1
42157 : abs(p[1] - y0) < epsilon$1 ? direction > 0 ? 1 : 0
42158 : direction > 0 ? 3 : 2; // abs(p[1] - y1) < epsilon
42159 }
42160
42161 function compareIntersection(a, b) {
42162 return comparePoint(a.x, b.x);
42163 }
42164
42165 function comparePoint(a, b) {
42166 var ca = corner(a, 1),
42167 cb = corner(b, 1);
42168 return ca !== cb ? ca - cb
42169 : ca === 0 ? b[1] - a[1]
42170 : ca === 1 ? a[0] - b[0]
42171 : ca === 2 ? a[1] - b[1]
42172 : b[0] - a[0];
42173 }
42174
42175 return function(stream) {
42176 var activeStream = stream,
42177 bufferStream = clipBuffer(),
42178 segments,
42179 polygon,
42180 ring,
42181 x__, y__, v__, // first point
42182 x_, y_, v_, // previous point
42183 first,
42184 clean;
42185
42186 var clipStream = {
42187 point: point,
42188 lineStart: lineStart,
42189 lineEnd: lineEnd,
42190 polygonStart: polygonStart,
42191 polygonEnd: polygonEnd
42192 };
42193
42194 function point(x, y) {
42195 if (visible(x, y)) activeStream.point(x, y);
42196 }
42197
42198 function polygonInside() {
42199 var winding = 0;
42200
42201 for (var i = 0, n = polygon.length; i < n; ++i) {
42202 for (var ring = polygon[i], j = 1, m = ring.length, point = ring[0], a0, a1, b0 = point[0], b1 = point[1]; j < m; ++j) {
42203 a0 = b0, a1 = b1, point = ring[j], b0 = point[0], b1 = point[1];
42204 if (a1 <= y1) { if (b1 > y1 && (b0 - a0) * (y1 - a1) > (b1 - a1) * (x0 - a0)) ++winding; }
42205 else { if (b1 <= y1 && (b0 - a0) * (y1 - a1) < (b1 - a1) * (x0 - a0)) --winding; }
42206 }
42207 }
42208
42209 return winding;
42210 }
42211
42212 // Buffer geometry within a polygon and then clip it en masse.
42213 function polygonStart() {
42214 activeStream = bufferStream, segments = [], polygon = [], clean = true;
42215 }
42216
42217 function polygonEnd() {
42218 var startInside = polygonInside(),
42219 cleanInside = clean && startInside,
42220 visible = (segments = merge$1(segments)).length;
42221 if (cleanInside || visible) {
42222 stream.polygonStart();
42223 if (cleanInside) {
42224 stream.lineStart();
42225 interpolate(null, null, 1, stream);
42226 stream.lineEnd();
42227 }
42228 if (visible) {
42229 clipPolygon$1(segments, compareIntersection, startInside, interpolate, stream);
42230 }
42231 stream.polygonEnd();
42232 }
42233 activeStream = stream, segments = polygon = ring = null;
42234 }
42235
42236 function lineStart() {
42237 clipStream.point = linePoint;
42238 if (polygon) polygon.push(ring = []);
42239 first = true;
42240 v_ = false;
42241 x_ = y_ = NaN;
42242 }
42243
42244 // TODO rather than special-case polygons, simply handle them separately.
42245 // Ideally, coincident intersection points should be jittered to avoid
42246 // clipping issues.
42247 function lineEnd() {
42248 if (segments) {
42249 linePoint(x__, y__);
42250 if (v__ && v_) bufferStream.rejoin();
42251 segments.push(bufferStream.result());
42252 }
42253 clipStream.point = point;
42254 if (v_) activeStream.lineEnd();
42255 }
42256
42257 function linePoint(x, y) {
42258 var v = visible(x, y);
42259 if (polygon) ring.push([x, y]);
42260 if (first) {
42261 x__ = x, y__ = y, v__ = v;
42262 first = false;
42263 if (v) {
42264 activeStream.lineStart();
42265 activeStream.point(x, y);
42266 }
42267 } else {
42268 if (v && v_) activeStream.point(x, y);
42269 else {
42270 var a = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))],
42271 b = [x = Math.max(clipMin, Math.min(clipMax, x)), y = Math.max(clipMin, Math.min(clipMax, y))];
42272 if (clipLine(a, b, x0, y0, x1, y1)) {
42273 if (!v_) {
42274 activeStream.lineStart();
42275 activeStream.point(a[0], a[1]);
42276 }
42277 activeStream.point(b[0], b[1]);
42278 if (!v) activeStream.lineEnd();
42279 clean = false;
42280 } else if (v) {
42281 activeStream.lineStart();
42282 activeStream.point(x, y);
42283 clean = false;
42284 }
42285 }
42286 }
42287 x_ = x, y_ = y, v_ = v;
42288 }
42289
42290 return clipStream;
42291 };
42292}
42293
42294var sum$1 = adder();
42295
42296var polygonContains = function(polygon, point) {
42297 var lambda = point[0],
42298 phi = point[1],
42299 normal = [sin(lambda), -cos(lambda), 0],
42300 angle = 0,
42301 winding = 0;
42302
42303 sum$1.reset();
42304
42305 for (var i = 0, n = polygon.length; i < n; ++i) {
42306 if (!(m = (ring = polygon[i]).length)) continue;
42307 var ring,
42308 m,
42309 point0 = ring[m - 1],
42310 lambda0 = point0[0],
42311 phi0 = point0[1] / 2 + quarterPi,
42312 sinPhi0 = sin(phi0),
42313 cosPhi0 = cos(phi0);
42314
42315 for (var j = 0; j < m; ++j, lambda0 = lambda1, sinPhi0 = sinPhi1, cosPhi0 = cosPhi1, point0 = point1) {
42316 var point1 = ring[j],
42317 lambda1 = point1[0],
42318 phi1 = point1[1] / 2 + quarterPi,
42319 sinPhi1 = sin(phi1),
42320 cosPhi1 = cos(phi1),
42321 delta = lambda1 - lambda0,
42322 sign = delta >= 0 ? 1 : -1,
42323 absDelta = sign * delta,
42324 antimeridian = absDelta > pi,
42325 k = sinPhi0 * sinPhi1;
42326
42327 sum$1.add(atan2(k * sign * sin(absDelta), cosPhi0 * cosPhi1 + k * cos(absDelta)));
42328 angle += antimeridian ? delta + sign * tau : delta;
42329
42330 // Are the longitudes either side of the point’s meridian (lambda),
42331 // and are the latitudes smaller than the parallel (phi)?
42332 if (antimeridian ^ lambda0 >= lambda ^ lambda1 >= lambda) {
42333 var arc = cartesianCross(cartesian(point0), cartesian(point1));
42334 cartesianNormalizeInPlace(arc);
42335 var intersection = cartesianCross(normal, arc);
42336 cartesianNormalizeInPlace(intersection);
42337 var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin(intersection[2]);
42338 if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) {
42339 winding += antimeridian ^ delta >= 0 ? 1 : -1;
42340 }
42341 }
42342 }
42343 }
42344
42345 // First, determine whether the South pole is inside or outside:
42346 //
42347 // It is inside if:
42348 // * the polygon winds around it in a clockwise direction.
42349 // * the polygon does not (cumulatively) wind around it, but has a negative
42350 // (counter-clockwise) area.
42351 //
42352 // Second, count the (signed) number of times a segment crosses a lambda
42353 // from the point to the South pole. If it is zero, then the point is the
42354 // same side as the South pole.
42355
42356 return (angle < -epsilon$1 || angle < epsilon$1 && sum$1 < -epsilon$1) ^ (winding & 1);
42357};
42358
42359var lengthSum = adder();
42360
42361var identity$2 = function(x) {
42362 return x;
42363};
42364
42365var areaSum$1 = adder();
42366var areaRingSum$1 = adder();
42367
42368var x0$2 = Infinity;
42369var y0$2 = x0$2;
42370var x1 = -x0$2;
42371var y1 = x1;
42372
42373var boundsStream$1 = {
42374 point: boundsPoint$1,
42375 lineStart: noop,
42376 lineEnd: noop,
42377 polygonStart: noop,
42378 polygonEnd: noop,
42379 result: function() {
42380 var bounds = [[x0$2, y0$2], [x1, y1]];
42381 x1 = y1 = -(y0$2 = x0$2 = Infinity);
42382 return bounds;
42383 }
42384};
42385
42386function boundsPoint$1(x, y) {
42387 if (x < x0$2) x0$2 = x;
42388 if (x > x1) x1 = x;
42389 if (y < y0$2) y0$2 = y;
42390 if (y > y1) y1 = y;
42391}
42392
42393var lengthSum$1 = adder();
42394
42395var clip = function(pointVisible, clipLine, interpolate, start) {
42396 return function(rotate, sink) {
42397 var line = clipLine(sink),
42398 rotatedStart = rotate.invert(start[0], start[1]),
42399 ringBuffer = clipBuffer(),
42400 ringSink = clipLine(ringBuffer),
42401 polygonStarted = false,
42402 polygon,
42403 segments,
42404 ring;
42405
42406 var clip = {
42407 point: point,
42408 lineStart: lineStart,
42409 lineEnd: lineEnd,
42410 polygonStart: function() {
42411 clip.point = pointRing;
42412 clip.lineStart = ringStart;
42413 clip.lineEnd = ringEnd;
42414 segments = [];
42415 polygon = [];
42416 },
42417 polygonEnd: function() {
42418 clip.point = point;
42419 clip.lineStart = lineStart;
42420 clip.lineEnd = lineEnd;
42421 segments = merge$1(segments);
42422 var startInside = polygonContains(polygon, rotatedStart);
42423 if (segments.length) {
42424 if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
42425 clipPolygon$1(segments, compareIntersection, startInside, interpolate, sink);
42426 } else if (startInside) {
42427 if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
42428 sink.lineStart();
42429 interpolate(null, null, 1, sink);
42430 sink.lineEnd();
42431 }
42432 if (polygonStarted) sink.polygonEnd(), polygonStarted = false;
42433 segments = polygon = null;
42434 },
42435 sphere: function() {
42436 sink.polygonStart();
42437 sink.lineStart();
42438 interpolate(null, null, 1, sink);
42439 sink.lineEnd();
42440 sink.polygonEnd();
42441 }
42442 };
42443
42444 function point(lambda, phi) {
42445 var point = rotate(lambda, phi);
42446 if (pointVisible(lambda = point[0], phi = point[1])) sink.point(lambda, phi);
42447 }
42448
42449 function pointLine(lambda, phi) {
42450 var point = rotate(lambda, phi);
42451 line.point(point[0], point[1]);
42452 }
42453
42454 function lineStart() {
42455 clip.point = pointLine;
42456 line.lineStart();
42457 }
42458
42459 function lineEnd() {
42460 clip.point = point;
42461 line.lineEnd();
42462 }
42463
42464 function pointRing(lambda, phi) {
42465 ring.push([lambda, phi]);
42466 var point = rotate(lambda, phi);
42467 ringSink.point(point[0], point[1]);
42468 }
42469
42470 function ringStart() {
42471 ringSink.lineStart();
42472 ring = [];
42473 }
42474
42475 function ringEnd() {
42476 pointRing(ring[0][0], ring[0][1]);
42477 ringSink.lineEnd();
42478
42479 var clean = ringSink.clean(),
42480 ringSegments = ringBuffer.result(),
42481 i, n = ringSegments.length, m,
42482 segment,
42483 point;
42484
42485 ring.pop();
42486 polygon.push(ring);
42487 ring = null;
42488
42489 if (!n) return;
42490
42491 // No intersections.
42492 if (clean & 1) {
42493 segment = ringSegments[0];
42494 if ((m = segment.length - 1) > 0) {
42495 if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
42496 sink.lineStart();
42497 for (i = 0; i < m; ++i) sink.point((point = segment[i])[0], point[1]);
42498 sink.lineEnd();
42499 }
42500 return;
42501 }
42502
42503 // Rejoin connected segments.
42504 // TODO reuse ringBuffer.rejoin()?
42505 if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
42506
42507 segments.push(ringSegments.filter(validSegment));
42508 }
42509
42510 return clip;
42511 };
42512};
42513
42514function validSegment(segment) {
42515 return segment.length > 1;
42516}
42517
42518// Intersections are sorted along the clip edge. For both antimeridian cutting
42519// and circle clipping, the same comparison is used.
42520function compareIntersection(a, b) {
42521 return ((a = a.x)[0] < 0 ? a[1] - halfPi - epsilon$1 : halfPi - a[1])
42522 - ((b = b.x)[0] < 0 ? b[1] - halfPi - epsilon$1 : halfPi - b[1]);
42523}
42524
42525var clipAntimeridian = clip(
42526 function() { return true; },
42527 clipAntimeridianLine,
42528 clipAntimeridianInterpolate,
42529 [-pi, -halfPi]
42530);
42531
42532// Takes a line and cuts into visible segments. Return values: 0 - there were
42533// intersections or the line was empty; 1 - no intersections; 2 - there were
42534// intersections, and the first and last segments should be rejoined.
42535function clipAntimeridianLine(stream) {
42536 var lambda0 = NaN,
42537 phi0 = NaN,
42538 sign0 = NaN,
42539 clean; // no intersections
42540
42541 return {
42542 lineStart: function() {
42543 stream.lineStart();
42544 clean = 1;
42545 },
42546 point: function(lambda1, phi1) {
42547 var sign1 = lambda1 > 0 ? pi : -pi,
42548 delta = abs(lambda1 - lambda0);
42549 if (abs(delta - pi) < epsilon$1) { // line crosses a pole
42550 stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi : -halfPi);
42551 stream.point(sign0, phi0);
42552 stream.lineEnd();
42553 stream.lineStart();
42554 stream.point(sign1, phi0);
42555 stream.point(lambda1, phi0);
42556 clean = 0;
42557 } else if (sign0 !== sign1 && delta >= pi) { // line crosses antimeridian
42558 if (abs(lambda0 - sign0) < epsilon$1) lambda0 -= sign0 * epsilon$1; // handle degeneracies
42559 if (abs(lambda1 - sign1) < epsilon$1) lambda1 -= sign1 * epsilon$1;
42560 phi0 = clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1);
42561 stream.point(sign0, phi0);
42562 stream.lineEnd();
42563 stream.lineStart();
42564 stream.point(sign1, phi0);
42565 clean = 0;
42566 }
42567 stream.point(lambda0 = lambda1, phi0 = phi1);
42568 sign0 = sign1;
42569 },
42570 lineEnd: function() {
42571 stream.lineEnd();
42572 lambda0 = phi0 = NaN;
42573 },
42574 clean: function() {
42575 return 2 - clean; // if intersections, rejoin first and last segments
42576 }
42577 };
42578}
42579
42580function clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1) {
42581 var cosPhi0,
42582 cosPhi1,
42583 sinLambda0Lambda1 = sin(lambda0 - lambda1);
42584 return abs(sinLambda0Lambda1) > epsilon$1
42585 ? atan((sin(phi0) * (cosPhi1 = cos(phi1)) * sin(lambda1)
42586 - sin(phi1) * (cosPhi0 = cos(phi0)) * sin(lambda0))
42587 / (cosPhi0 * cosPhi1 * sinLambda0Lambda1))
42588 : (phi0 + phi1) / 2;
42589}
42590
42591function clipAntimeridianInterpolate(from, to, direction, stream) {
42592 var phi;
42593 if (from == null) {
42594 phi = direction * halfPi;
42595 stream.point(-pi, phi);
42596 stream.point(0, phi);
42597 stream.point(pi, phi);
42598 stream.point(pi, 0);
42599 stream.point(pi, -phi);
42600 stream.point(0, -phi);
42601 stream.point(-pi, -phi);
42602 stream.point(-pi, 0);
42603 stream.point(-pi, phi);
42604 } else if (abs(from[0] - to[0]) > epsilon$1) {
42605 var lambda = from[0] < to[0] ? pi : -pi;
42606 phi = direction * lambda / 2;
42607 stream.point(-lambda, phi);
42608 stream.point(0, phi);
42609 stream.point(lambda, phi);
42610 } else {
42611 stream.point(to[0], to[1]);
42612 }
42613}
42614
42615var clipCircle = function(radius, delta) {
42616 var cr = cos(radius),
42617 smallRadius = cr > 0,
42618 notHemisphere = abs(cr) > epsilon$1; // TODO optimise for this common case
42619
42620 function interpolate(from, to, direction, stream) {
42621 circleStream(stream, radius, delta, direction, from, to);
42622 }
42623
42624 function visible(lambda, phi) {
42625 return cos(lambda) * cos(phi) > cr;
42626 }
42627
42628 // Takes a line and cuts into visible segments. Return values used for polygon
42629 // clipping: 0 - there were intersections or the line was empty; 1 - no
42630 // intersections 2 - there were intersections, and the first and last segments
42631 // should be rejoined.
42632 function clipLine(stream) {
42633 var point0, // previous point
42634 c0, // code for previous point
42635 v0, // visibility of previous point
42636 v00, // visibility of first point
42637 clean; // no intersections
42638 return {
42639 lineStart: function() {
42640 v00 = v0 = false;
42641 clean = 1;
42642 },
42643 point: function(lambda, phi) {
42644 var point1 = [lambda, phi],
42645 point2,
42646 v = visible(lambda, phi),
42647 c = smallRadius
42648 ? v ? 0 : code(lambda, phi)
42649 : v ? code(lambda + (lambda < 0 ? pi : -pi), phi) : 0;
42650 if (!point0 && (v00 = v0 = v)) stream.lineStart();
42651 // Handle degeneracies.
42652 // TODO ignore if not clipping polygons.
42653 if (v !== v0) {
42654 point2 = intersect(point0, point1);
42655 if (!point2 || pointEqual(point0, point2) || pointEqual(point1, point2)) {
42656 point1[0] += epsilon$1;
42657 point1[1] += epsilon$1;
42658 v = visible(point1[0], point1[1]);
42659 }
42660 }
42661 if (v !== v0) {
42662 clean = 0;
42663 if (v) {
42664 // outside going in
42665 stream.lineStart();
42666 point2 = intersect(point1, point0);
42667 stream.point(point2[0], point2[1]);
42668 } else {
42669 // inside going out
42670 point2 = intersect(point0, point1);
42671 stream.point(point2[0], point2[1]);
42672 stream.lineEnd();
42673 }
42674 point0 = point2;
42675 } else if (notHemisphere && point0 && smallRadius ^ v) {
42676 var t;
42677 // If the codes for two points are different, or are both zero,
42678 // and there this segment intersects with the small circle.
42679 if (!(c & c0) && (t = intersect(point1, point0, true))) {
42680 clean = 0;
42681 if (smallRadius) {
42682 stream.lineStart();
42683 stream.point(t[0][0], t[0][1]);
42684 stream.point(t[1][0], t[1][1]);
42685 stream.lineEnd();
42686 } else {
42687 stream.point(t[1][0], t[1][1]);
42688 stream.lineEnd();
42689 stream.lineStart();
42690 stream.point(t[0][0], t[0][1]);
42691 }
42692 }
42693 }
42694 if (v && (!point0 || !pointEqual(point0, point1))) {
42695 stream.point(point1[0], point1[1]);
42696 }
42697 point0 = point1, v0 = v, c0 = c;
42698 },
42699 lineEnd: function() {
42700 if (v0) stream.lineEnd();
42701 point0 = null;
42702 },
42703 // Rejoin first and last segments if there were intersections and the first
42704 // and last points were visible.
42705 clean: function() {
42706 return clean | ((v00 && v0) << 1);
42707 }
42708 };
42709 }
42710
42711 // Intersects the great circle between a and b with the clip circle.
42712 function intersect(a, b, two) {
42713 var pa = cartesian(a),
42714 pb = cartesian(b);
42715
42716 // We have two planes, n1.p = d1 and n2.p = d2.
42717 // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2).
42718 var n1 = [1, 0, 0], // normal
42719 n2 = cartesianCross(pa, pb),
42720 n2n2 = cartesianDot(n2, n2),
42721 n1n2 = n2[0], // cartesianDot(n1, n2),
42722 determinant = n2n2 - n1n2 * n1n2;
42723
42724 // Two polar points.
42725 if (!determinant) return !two && a;
42726
42727 var c1 = cr * n2n2 / determinant,
42728 c2 = -cr * n1n2 / determinant,
42729 n1xn2 = cartesianCross(n1, n2),
42730 A = cartesianScale(n1, c1),
42731 B = cartesianScale(n2, c2);
42732 cartesianAddInPlace(A, B);
42733
42734 // Solve |p(t)|^2 = 1.
42735 var u = n1xn2,
42736 w = cartesianDot(A, u),
42737 uu = cartesianDot(u, u),
42738 t2 = w * w - uu * (cartesianDot(A, A) - 1);
42739
42740 if (t2 < 0) return;
42741
42742 var t = sqrt(t2),
42743 q = cartesianScale(u, (-w - t) / uu);
42744 cartesianAddInPlace(q, A);
42745 q = spherical(q);
42746
42747 if (!two) return q;
42748
42749 // Two intersection points.
42750 var lambda0 = a[0],
42751 lambda1 = b[0],
42752 phi0 = a[1],
42753 phi1 = b[1],
42754 z;
42755
42756 if (lambda1 < lambda0) z = lambda0, lambda0 = lambda1, lambda1 = z;
42757
42758 var delta = lambda1 - lambda0,
42759 polar = abs(delta - pi) < epsilon$1,
42760 meridian = polar || delta < epsilon$1;
42761
42762 if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z;
42763
42764 // Check that the first point is between a and b.
42765 if (meridian
42766 ? polar
42767 ? phi0 + phi1 > 0 ^ q[1] < (abs(q[0] - lambda0) < epsilon$1 ? phi0 : phi1)
42768 : phi0 <= q[1] && q[1] <= phi1
42769 : delta > pi ^ (lambda0 <= q[0] && q[0] <= lambda1)) {
42770 var q1 = cartesianScale(u, (-w + t) / uu);
42771 cartesianAddInPlace(q1, A);
42772 return [q, spherical(q1)];
42773 }
42774 }
42775
42776 // Generates a 4-bit vector representing the location of a point relative to
42777 // the small circle's bounding box.
42778 function code(lambda, phi) {
42779 var r = smallRadius ? radius : pi - radius,
42780 code = 0;
42781 if (lambda < -r) code |= 1; // left
42782 else if (lambda > r) code |= 2; // right
42783 if (phi < -r) code |= 4; // below
42784 else if (phi > r) code |= 8; // above
42785 return code;
42786 }
42787
42788 return clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi, radius - pi]);
42789};
42790
42791function transformer(methods) {
42792 return function(stream) {
42793 var s = new TransformStream;
42794 for (var key in methods) s[key] = methods[key];
42795 s.stream = stream;
42796 return s;
42797 };
42798}
42799
42800function TransformStream() {}
42801
42802TransformStream.prototype = {
42803 constructor: TransformStream,
42804 point: function(x, y) { this.stream.point(x, y); },
42805 sphere: function() { this.stream.sphere(); },
42806 lineStart: function() { this.stream.lineStart(); },
42807 lineEnd: function() { this.stream.lineEnd(); },
42808 polygonStart: function() { this.stream.polygonStart(); },
42809 polygonEnd: function() { this.stream.polygonEnd(); }
42810};
42811
42812function fitExtent(projection, extent, object) {
42813 var w = extent[1][0] - extent[0][0],
42814 h = extent[1][1] - extent[0][1],
42815 clip = projection.clipExtent && projection.clipExtent();
42816
42817 projection
42818 .scale(150)
42819 .translate([0, 0]);
42820
42821 if (clip != null) projection.clipExtent(null);
42822
42823 geoStream(object, projection.stream(boundsStream$1));
42824
42825 var b = boundsStream$1.result(),
42826 k = Math.min(w / (b[1][0] - b[0][0]), h / (b[1][1] - b[0][1])),
42827 x = +extent[0][0] + (w - k * (b[1][0] + b[0][0])) / 2,
42828 y = +extent[0][1] + (h - k * (b[1][1] + b[0][1])) / 2;
42829
42830 if (clip != null) projection.clipExtent(clip);
42831
42832 return projection
42833 .scale(k * 150)
42834 .translate([x, y]);
42835}
42836
42837function fitSize(projection, size, object) {
42838 return fitExtent(projection, [[0, 0], size], object);
42839}
42840
42841var maxDepth = 16;
42842var cosMinDistance = cos(30 * radians); // cos(minimum angular distance)
42843
42844var resample = function(project, delta2) {
42845 return +delta2 ? resample$1(project, delta2) : resampleNone(project);
42846};
42847
42848function resampleNone(project) {
42849 return transformer({
42850 point: function(x, y) {
42851 x = project(x, y);
42852 this.stream.point(x[0], x[1]);
42853 }
42854 });
42855}
42856
42857function resample$1(project, delta2) {
42858
42859 function resampleLineTo(x0, y0, lambda0, a0, b0, c0, x1, y1, lambda1, a1, b1, c1, depth, stream) {
42860 var dx = x1 - x0,
42861 dy = y1 - y0,
42862 d2 = dx * dx + dy * dy;
42863 if (d2 > 4 * delta2 && depth--) {
42864 var a = a0 + a1,
42865 b = b0 + b1,
42866 c = c0 + c1,
42867 m = sqrt(a * a + b * b + c * c),
42868 phi2 = asin(c /= m),
42869 lambda2 = abs(abs(c) - 1) < epsilon$1 || abs(lambda0 - lambda1) < epsilon$1 ? (lambda0 + lambda1) / 2 : atan2(b, a),
42870 p = project(lambda2, phi2),
42871 x2 = p[0],
42872 y2 = p[1],
42873 dx2 = x2 - x0,
42874 dy2 = y2 - y0,
42875 dz = dy * dx2 - dx * dy2;
42876 if (dz * dz / d2 > delta2 // perpendicular projected distance
42877 || abs((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end
42878 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { // angular distance
42879 resampleLineTo(x0, y0, lambda0, a0, b0, c0, x2, y2, lambda2, a /= m, b /= m, c, depth, stream);
42880 stream.point(x2, y2);
42881 resampleLineTo(x2, y2, lambda2, a, b, c, x1, y1, lambda1, a1, b1, c1, depth, stream);
42882 }
42883 }
42884 }
42885 return function(stream) {
42886 var lambda00, x00, y00, a00, b00, c00, // first point
42887 lambda0, x0, y0, a0, b0, c0; // previous point
42888
42889 var resampleStream = {
42890 point: point,
42891 lineStart: lineStart,
42892 lineEnd: lineEnd,
42893 polygonStart: function() { stream.polygonStart(); resampleStream.lineStart = ringStart; },
42894 polygonEnd: function() { stream.polygonEnd(); resampleStream.lineStart = lineStart; }
42895 };
42896
42897 function point(x, y) {
42898 x = project(x, y);
42899 stream.point(x[0], x[1]);
42900 }
42901
42902 function lineStart() {
42903 x0 = NaN;
42904 resampleStream.point = linePoint;
42905 stream.lineStart();
42906 }
42907
42908 function linePoint(lambda, phi) {
42909 var c = cartesian([lambda, phi]), p = project(lambda, phi);
42910 resampleLineTo(x0, y0, lambda0, a0, b0, c0, x0 = p[0], y0 = p[1], lambda0 = lambda, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
42911 stream.point(x0, y0);
42912 }
42913
42914 function lineEnd() {
42915 resampleStream.point = point;
42916 stream.lineEnd();
42917 }
42918
42919 function ringStart() {
42920 lineStart();
42921 resampleStream.point = ringPoint;
42922 resampleStream.lineEnd = ringEnd;
42923 }
42924
42925 function ringPoint(lambda, phi) {
42926 linePoint(lambda00 = lambda, phi), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
42927 resampleStream.point = linePoint;
42928 }
42929
42930 function ringEnd() {
42931 resampleLineTo(x0, y0, lambda0, a0, b0, c0, x00, y00, lambda00, a00, b00, c00, maxDepth, stream);
42932 resampleStream.lineEnd = lineEnd;
42933 lineEnd();
42934 }
42935
42936 return resampleStream;
42937 };
42938}
42939
42940var transformRadians = transformer({
42941 point: function(x, y) {
42942 this.stream.point(x * radians, y * radians);
42943 }
42944});
42945
42946function projection(project) {
42947 return projectionMutator(function() { return project; })();
42948}
42949
42950function projectionMutator(projectAt) {
42951 var project,
42952 k = 150, // scale
42953 x = 480, y = 250, // translate
42954 dx, dy, lambda = 0, phi = 0, // center
42955 deltaLambda = 0, deltaPhi = 0, deltaGamma = 0, rotate, projectRotate, // rotate
42956 theta = null, preclip = clipAntimeridian, // clip angle
42957 x0 = null, y0, x1, y1, postclip = identity$2, // clip extent
42958 delta2 = 0.5, projectResample = resample(projectTransform, delta2), // precision
42959 cache,
42960 cacheStream;
42961
42962 function projection(point) {
42963 point = projectRotate(point[0] * radians, point[1] * radians);
42964 return [point[0] * k + dx, dy - point[1] * k];
42965 }
42966
42967 function invert(point) {
42968 point = projectRotate.invert((point[0] - dx) / k, (dy - point[1]) / k);
42969 return point && [point[0] * degrees, point[1] * degrees];
42970 }
42971
42972 function projectTransform(x, y) {
42973 return x = project(x, y), [x[0] * k + dx, dy - x[1] * k];
42974 }
42975
42976 projection.stream = function(stream) {
42977 return cache && cacheStream === stream ? cache : cache = transformRadians(preclip(rotate, projectResample(postclip(cacheStream = stream))));
42978 };
42979
42980 projection.clipAngle = function(_) {
42981 return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians, 6 * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees;
42982 };
42983
42984 projection.clipExtent = function(_) {
42985 return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$2) : clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]];
42986 };
42987
42988 projection.scale = function(_) {
42989 return arguments.length ? (k = +_, recenter()) : k;
42990 };
42991
42992 projection.translate = function(_) {
42993 return arguments.length ? (x = +_[0], y = +_[1], recenter()) : [x, y];
42994 };
42995
42996 projection.center = function(_) {
42997 return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees, phi * degrees];
42998 };
42999
43000 projection.rotate = function(_) {
43001 return arguments.length ? (deltaLambda = _[0] % 360 * radians, deltaPhi = _[1] % 360 * radians, deltaGamma = _.length > 2 ? _[2] % 360 * radians : 0, recenter()) : [deltaLambda * degrees, deltaPhi * degrees, deltaGamma * degrees];
43002 };
43003
43004 projection.precision = function(_) {
43005 return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt(delta2);
43006 };
43007
43008 projection.fitExtent = function(extent$$1, object) {
43009 return fitExtent(projection, extent$$1, object);
43010 };
43011
43012 projection.fitSize = function(size, object) {
43013 return fitSize(projection, size, object);
43014 };
43015
43016 function recenter() {
43017 projectRotate = compose(rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma), project);
43018 var center = project(lambda, phi);
43019 dx = x - center[0] * k;
43020 dy = y + center[1] * k;
43021 return reset();
43022 }
43023
43024 function reset() {
43025 cache = cacheStream = null;
43026 return projection;
43027 }
43028
43029 return function() {
43030 project = projectAt.apply(this, arguments);
43031 projection.invert = project.invert && invert;
43032 return recenter();
43033 };
43034}
43035
43036function mercatorRaw(lambda, phi) {
43037 return [lambda, log(tan((halfPi + phi) / 2))];
43038}
43039
43040mercatorRaw.invert = function(x, y) {
43041 return [x, 2 * atan(exp(y)) - halfPi];
43042};
43043
43044function mercatorProjection(project) {
43045 var m = projection(project),
43046 center = m.center,
43047 scale = m.scale,
43048 translate = m.translate,
43049 clipExtent = m.clipExtent,
43050 x0 = null, y0, x1, y1; // clip extent
43051
43052 m.scale = function(_) {
43053 return arguments.length ? (scale(_), reclip()) : scale();
43054 };
43055
43056 m.translate = function(_) {
43057 return arguments.length ? (translate(_), reclip()) : translate();
43058 };
43059
43060 m.center = function(_) {
43061 return arguments.length ? (center(_), reclip()) : center();
43062 };
43063
43064 m.clipExtent = function(_) {
43065 return arguments.length ? (_ == null ? x0 = y0 = x1 = y1 = null : (x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reclip()) : x0 == null ? null : [[x0, y0], [x1, y1]];
43066 };
43067
43068 function reclip() {
43069 var k = pi * scale(),
43070 t = m(rotation(m.rotate()).invert([0, 0]));
43071 return clipExtent(x0 == null
43072 ? [[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]] : project === mercatorRaw
43073 ? [[Math.max(t[0] - k, x0), y0], [Math.min(t[0] + k, x1), y1]]
43074 : [[x0, Math.max(t[1] - k, y0)], [x1, Math.min(t[1] + k, y1)]]);
43075 }
43076
43077 return reclip();
43078}
43079
43080function transverseMercatorRaw(lambda, phi) {
43081 return [log(tan((halfPi + phi) / 2)), -lambda];
43082}
43083
43084transverseMercatorRaw.invert = function(x, y) {
43085 return [-y, 2 * atan(exp(x)) - halfPi];
43086};
43087
43088var geoTransverseMercator = function() {
43089 var m = mercatorProjection(transverseMercatorRaw),
43090 center = m.center,
43091 rotate = m.rotate;
43092
43093 m.center = function(_) {
43094 return arguments.length ? center([-_[1], _[0]]) : (_ = center(), [_[1], -_[0]]);
43095 };
43096
43097 m.rotate = function(_) {
43098 return arguments.length ? rotate([_[0], _[1], _.length > 2 ? _[2] + 90 : 90]) : (_ = rotate(), [_[0], _[1], _[2] - 90]);
43099 };
43100
43101 return rotate([0, 0, 90])
43102 .scale(159.155);
43103};
43104
43105/**
43106 * Calculates a buffer for input features for a given radius. Units supported are miles, kilometers, and degrees.
43107 *
43108 * When using a negative radius, the resulting geometry may be invalid if
43109 * it's too small compared to the radius magnitude. If the input is a
43110 * FeatureCollection, only valid members will be returned in the output
43111 * FeatureCollection - i.e., the output collection may have fewer members than
43112 * the input, or even be empty.
43113 *
43114 * @name buffer
43115 * @param {FeatureCollection|Geometry|Feature<any>} geojson input to be buffered
43116 * @param {number} radius distance to draw the buffer (negative values are allowed)
43117 * @param {Object} [options={}] Optional parameters
43118 * @param {string} [options.units="kilometers"] any of the options supported by turf units
43119 * @param {number} [options.steps=64] number of steps
43120 * @returns {FeatureCollection|Feature<Polygon|MultiPolygon>|undefined} buffered features
43121 * @example
43122 * var point = turf.point([-90.548630, 14.616599]);
43123 * var buffered = turf.buffer(point, 500, {units: 'miles'});
43124 *
43125 * //addToMap
43126 * var addToMap = [point, buffered]
43127 */
43128function buffer$1(geojson, radius, options) {
43129 // Optional params
43130 options = options || {};
43131 var units = options.units;
43132 var steps = options.steps || 64;
43133
43134 // validation
43135 if (!geojson) throw new Error('geojson is required');
43136 if (typeof options !== 'object') throw new Error('options must be an object');
43137 if (typeof steps !== 'number') throw new Error('steps must be an number');
43138
43139 // Allow negative buffers ("erosion") or zero-sized buffers ("repair geometry")
43140 if (radius === undefined) throw new Error('radius is required');
43141 if (steps <= 0) throw new Error('steps must be greater than 0');
43142
43143 // default params
43144 steps = steps || 64;
43145 units = units || 'kilometers';
43146
43147 var results = [];
43148 switch (geojson.type) {
43149 case 'GeometryCollection':
43150 geomEach(geojson, function (geometry$$1) {
43151 var buffered = bufferFeature(geometry$$1, radius, units, steps);
43152 if (buffered) results.push(buffered);
43153 });
43154 return featureCollection(results);
43155 case 'FeatureCollection':
43156 featureEach(geojson, function (feature$$1) {
43157 var multiBuffered = bufferFeature(feature$$1, radius, units, steps);
43158 if (multiBuffered) {
43159 featureEach(multiBuffered, function (buffered) {
43160 if (buffered) results.push(buffered);
43161 });
43162 }
43163 });
43164 return featureCollection(results);
43165 }
43166 return bufferFeature(geojson, radius, units, steps);
43167}
43168
43169/**
43170 * Buffer single Feature/Geometry
43171 *
43172 * @private
43173 * @param {Feature<any>} geojson input to be buffered
43174 * @param {number} radius distance to draw the buffer
43175 * @param {string} [units='kilometers'] any of the options supported by turf units
43176 * @param {number} [steps=64] number of steps
43177 * @returns {Feature<Polygon|MultiPolygon>} buffered feature
43178 */
43179function bufferFeature(geojson, radius, units, steps) {
43180 var properties = geojson.properties || {};
43181 var geometry$$1 = (geojson.type === 'Feature') ? geojson.geometry : geojson;
43182
43183 // Geometry Types faster than jsts
43184 if (geometry$$1.type === 'GeometryCollection') {
43185 var results = [];
43186 geomEach(geojson, function (geometry$$1) {
43187 var buffered = bufferFeature(geometry$$1, radius, units, steps);
43188 if (buffered) results.push(buffered);
43189 });
43190 return featureCollection(results);
43191 }
43192
43193 // Project GeoJSON to Transverse Mercator projection (convert to Meters)
43194 var projected;
43195 var bbox$$1 = bbox(geojson);
43196 var needsTransverseMercator = bbox$$1[1] > 50 && bbox$$1[3] > 50;
43197
43198 if (needsTransverseMercator) {
43199 projected = {
43200 type: geometry$$1.type,
43201 coordinates: projectCoords(geometry$$1.coordinates, defineProjection(geometry$$1))
43202 };
43203 } else {
43204 projected = toMercator(geometry$$1);
43205 }
43206
43207 // JSTS buffer operation
43208 var reader = new GeoJSONReader();
43209 var geom = reader.read(projected);
43210 var distance = radiansToLength(lengthToRadians(radius, units), 'meters');
43211 var buffered = BufferOp.bufferOp(geom, distance);
43212 var writer = new GeoJSONWriter();
43213 buffered = writer.write(buffered);
43214
43215 // Detect if empty geometries
43216 if (coordsIsNaN(buffered.coordinates)) return undefined;
43217
43218 // Unproject coordinates (convert to Degrees)
43219 var result;
43220 if (needsTransverseMercator) {
43221 result = {
43222 type: buffered.type,
43223 coordinates: unprojectCoords(buffered.coordinates, defineProjection(geometry$$1))
43224 };
43225 } else {
43226 result = toWgs84(buffered);
43227 }
43228
43229 return (result.geometry) ? result : feature(result, properties);
43230}
43231
43232/**
43233 * Coordinates isNaN
43234 *
43235 * @private
43236 * @param {Array<any>} coords GeoJSON Coordinates
43237 * @returns {boolean} if NaN exists
43238 */
43239function coordsIsNaN(coords) {
43240 if (Array.isArray(coords[0])) return coordsIsNaN(coords[0]);
43241 return isNaN(coords[0]);
43242}
43243
43244/**
43245 * Project coordinates to projection
43246 *
43247 * @private
43248 * @param {Array<any>} coords to project
43249 * @param {GeoProjection} proj D3 Geo Projection
43250 * @returns {Array<any>} projected coordinates
43251 */
43252function projectCoords(coords, proj) {
43253 if (typeof coords[0] !== 'object') return proj(coords);
43254 return coords.map(function (coord) {
43255 return projectCoords(coord, proj);
43256 });
43257}
43258
43259/**
43260 * Un-Project coordinates to projection
43261 *
43262 * @private
43263 * @param {Array<any>} coords to un-project
43264 * @param {GeoProjection} proj D3 Geo Projection
43265 * @returns {Array<any>} un-projected coordinates
43266 */
43267function unprojectCoords(coords, proj) {
43268 if (typeof coords[0] !== 'object') return proj.invert(coords);
43269 return coords.map(function (coord) {
43270 return unprojectCoords(coord, proj);
43271 });
43272}
43273
43274/**
43275 * Define Transverse Mercator projection
43276 *
43277 * @private
43278 * @param {Geometry|Feature<any>} geojson Base projection on center of GeoJSON
43279 * @returns {GeoProjection} D3 Geo Transverse Mercator Projection
43280 */
43281function defineProjection(geojson) {
43282 var coords = center(geojson).geometry.coordinates.reverse();
43283 var rotate = coords.map(function (coord) { return -coord; });
43284 return geoTransverseMercator()
43285 .center(coords)
43286 .rotate(rotate)
43287 .scale(earthRadius);
43288}
43289
43290/**
43291 * Takes two or more {@link Polygon|polygons} and returns a combined polygon. If the input polygons are not contiguous, this function returns a {@link MultiPolygon} feature.
43292 *
43293 * @name union
43294 * @param {...Feature<Polygon>} A polygon to combine
43295 * @returns {Feature<(Polygon|MultiPolygon)>} a combined {@link Polygon} or {@link MultiPolygon} feature
43296 * @example
43297 * var poly1 = turf.polygon([[
43298 * [-82.574787, 35.594087],
43299 * [-82.574787, 35.615581],
43300 * [-82.545261, 35.615581],
43301 * [-82.545261, 35.594087],
43302 * [-82.574787, 35.594087]
43303 * ]], {"fill": "#0f0"});
43304 * var poly2 = turf.polygon([[
43305 * [-82.560024, 35.585153],
43306 * [-82.560024, 35.602602],
43307 * [-82.52964, 35.602602],
43308 * [-82.52964, 35.585153],
43309 * [-82.560024, 35.585153]
43310 * ]], {"fill": "#00f"});
43311 *
43312 * var union = turf.union(poly1, poly2);
43313 *
43314 * //addToMap
43315 * var addToMap = [poly1, poly2, union];
43316 */
43317function union() {
43318 var reader = new GeoJSONReader();
43319 var result = reader.read(JSON.stringify(arguments[0].geometry));
43320
43321 for (var i = 1; i < arguments.length; i++) {
43322 result = UnionOp.union(result, reader.read(JSON.stringify(arguments[i].geometry)));
43323 }
43324
43325 var writer = new GeoJSONWriter();
43326 result = writer.write(result);
43327
43328 return {
43329 type: 'Feature',
43330 geometry: result,
43331 properties: arguments[0].properties
43332 };
43333}
43334
43335// depend on jsts for now http://bjornharrtell.github.io/jsts/
43336/**
43337 * Takes two {@link Polygon|polygons} and finds their intersection. If they share a border, returns the border; if they don't intersect, returns undefined.
43338 *
43339 * @name intersect
43340 * @param {Feature<Polygon>} poly1 the first polygon
43341 * @param {Feature<Polygon>} poly2 the second polygon
43342 * @returns {Feature|null} returns a feature representing the point(s) they share (in case of a {@link Point} or {@link MultiPoint}), the borders they share (in case of a {@link LineString} or a {@link MultiLineString}), the area they share (in case of {@link Polygon} or {@link MultiPolygon}). If they do not share any point, returns `null`.
43343 * @example
43344 * var poly1 = turf.polygon([[
43345 * [-122.801742, 45.48565],
43346 * [-122.801742, 45.60491],
43347 * [-122.584762, 45.60491],
43348 * [-122.584762, 45.48565],
43349 * [-122.801742, 45.48565]
43350 * ]]);
43351 *
43352 * var poly2 = turf.polygon([[
43353 * [-122.520217, 45.535693],
43354 * [-122.64038, 45.553967],
43355 * [-122.720031, 45.526554],
43356 * [-122.669906, 45.507309],
43357 * [-122.723464, 45.446643],
43358 * [-122.532577, 45.408574],
43359 * [-122.487258, 45.477466],
43360 * [-122.520217, 45.535693]
43361 * ]]);
43362 *
43363 * var intersection = turf.intersect(poly1, poly2);
43364 *
43365 * //addToMap
43366 * var addToMap = [poly1, poly2, intersection];
43367 */
43368function intersect$2(poly1, poly2) {
43369 var geom1 = getGeom(poly1);
43370 var geom2 = getGeom(poly2);
43371
43372 // Return null if geometry is too narrow in coordinate precision
43373 // fixes topology errors with JSTS
43374 // https://github.com/Turfjs/turf/issues/463
43375 // https://github.com/Turfjs/turf/pull/1004
43376 if (cleanCoords(truncate(geom2, {precision: 4})).coordinates[0].length < 4) return null;
43377 if (cleanCoords(truncate(geom1, {precision: 4})).coordinates[0].length < 4) return null;
43378
43379 var reader = new GeoJSONReader();
43380 var a = reader.read(truncate(geom1));
43381 var b = reader.read(truncate(geom2));
43382 var intersection = OverlayOp.intersection(a, b);
43383
43384 // https://github.com/Turfjs/turf/issues/951
43385 if (intersection.isEmpty()) return null;
43386
43387 var writer = new GeoJSONWriter();
43388 var geom = writer.write(intersection);
43389 return feature(geom);
43390}
43391
43392/**
43393 * @license get-closest https://github.com/cosmosio/get-closest
43394 *
43395 * The MIT License (MIT)
43396 *
43397 * Copyright (c) 2014-2017 Olivier Scherrer <pode.fr@gmail.com>
43398 */
43399
43400/**
43401 * Get the closest number in an array
43402 *
43403 * @private
43404 * @param {number} item the base number
43405 * @param {Array} array the array to search into
43406 * @param {Function} getDiff returns the difference between the base number and
43407 * and the currently read item in the array. The item which returned the smallest difference wins.
43408 * @returns {Object} Get Closest
43409 */
43410function _getClosest(item, array, getDiff) {
43411 var closest,
43412 diff;
43413
43414 if (!Array.isArray(array)) {
43415 throw new Error('Get closest expects an array as second argument');
43416 }
43417
43418 array.forEach(function (comparedItem, comparedItemIndex) {
43419 var thisDiff = getDiff(comparedItem, item);
43420
43421 if (thisDiff >= 0 && (typeof diff == 'undefined' || thisDiff < diff)) {
43422 diff = thisDiff;
43423 closest = comparedItemIndex;
43424 }
43425 });
43426
43427 return closest;
43428}
43429
43430/**
43431 * Get the closest number in an array given a base number
43432 *
43433 * @private
43434 * @param {number} item the base number
43435 * @param {Array<number>} array the array of numbers to search into
43436 * @returns {number} the index of the closest item in the array
43437 * @example
43438 * closestNumber(30, [20, 0, 50, 29])
43439 * //= will return 3 as 29 is the closest item
43440 */
43441
43442
43443/**
43444 * Get the closest greater number in an array given a base number
43445 *
43446 * @private
43447 * @param {number} item the base number
43448 * @param {Array<number>} array the array of numbers to search into
43449 * @returns {number} the index of the closest item in the array
43450 * @example
43451 * closestGreaterNumber(30, [20, 0, 50, 29])
43452 * //= will return 2 as 50 is the closest greater item
43453 */
43454function closestGreaterNumber(item, array) {
43455 return _getClosest(item, array, function (comparedItem, item) {
43456 return comparedItem - item;
43457 });
43458}
43459
43460/**
43461 * Get the closest lower number in an array given a base number
43462 *
43463 * @private
43464 * @param {number} item the base number
43465 * @param {Array<number>} array the array of numbers to search into
43466 * @returns {number} the index of the closest item in the array
43467 * @example
43468 * closestLowerNumber(30, [20, 0, 50, 29])
43469 * //= will return 0 as 20 is the closest lower item
43470 */
43471
43472
43473/**
43474 * Get the closest item in an array given a base item and a comparator function
43475 *
43476 * @private
43477 * @param {*} item the base item
43478 * @param {Array} array an array of items
43479 * @param {Function} comparator a comparatof function to compare the items
43480 * @returns {Object} Closest Custom
43481 * @example
43482 * closestCustom("lundi", ["mundi", "mardi"], getLevenshteinDistance)
43483 * //= will return 0 for "lundi"
43484 *
43485 * // The function looks like:
43486 *
43487 * // comparedItem comes from the array
43488 * // baseItem is the item to compare the others to
43489 * // It returns a number
43490 * function comparator(comparedItem, baseItem) {
43491 * return comparedItem - baseItem;
43492 * }
43493 */
43494
43495/**
43496 * Dissolves a FeatureCollection of {@link polygon} features, filtered by an optional property name:value.
43497 * Note that {@link mulitpolygon} features within the collection are not supported
43498 *
43499 * @name dissolve
43500 * @param {FeatureCollection<Polygon>} featureCollection input feature collection to be dissolved
43501 * @param {Object} [options={}] Optional parameters
43502 * @param {string} [options.propertyName] features with equals 'propertyName' in `properties` will be merged
43503 * @returns {FeatureCollection<Polygon>} a FeatureCollection containing the dissolved polygons
43504 * @example
43505 * var features = turf.featureCollection([
43506 * turf.polygon([[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]], {combine: 'yes'}),
43507 * turf.polygon([[[0, -1], [0, 0], [1, 0], [1, -1], [0,-1]]], {combine: 'yes'}),
43508 * turf.polygon([[[1,-1],[1, 0], [2, 0], [2, -1], [1, -1]]], {combine: 'no'}),
43509 * ]);
43510 *
43511 * var dissolved = turf.dissolve(features, {propertyName: 'combine'});
43512 *
43513 * //addToMap
43514 * var addToMap = [features, dissolved]
43515 */
43516function dissolve$1(featureCollection$$1, options) {
43517 // Optional parameters
43518 options = options || {};
43519 if (!isObject(options)) throw new Error('options is invalid');
43520 var propertyName = options.propertyName;
43521
43522 // Input validation
43523 collectionOf(featureCollection$$1, 'Polygon', 'dissolve');
43524
43525 // Main
43526 var fc = clone(featureCollection$$1);
43527 var features = fc.features;
43528
43529 var originalIndexOfItemsRemoved = [];
43530
43531 features.forEach(function (f, i) {
43532 f.properties.origIndexPosition = i;
43533 });
43534 var tree = geojsonRbush();
43535 tree.load(fc);
43536
43537 for (var i in features) {
43538 var polygon$$1 = features[i];
43539
43540 var featureChanged = false;
43541
43542 tree.search(polygon$$1).features.forEach(function (potentialMatchingFeature) {
43543 polygon$$1 = features[i];
43544
43545 var matchFeaturePosition = potentialMatchingFeature.properties.origIndexPosition;
43546
43547 if (originalIndexOfItemsRemoved.length > 0 && matchFeaturePosition !== 0) {
43548 if (matchFeaturePosition > originalIndexOfItemsRemoved[originalIndexOfItemsRemoved.length - 1]) {
43549 matchFeaturePosition = matchFeaturePosition - (originalIndexOfItemsRemoved.length);
43550 } else {
43551 var closestNumber$$1 = closestGreaterNumber(matchFeaturePosition, originalIndexOfItemsRemoved);
43552 if (closestNumber$$1 !== 0) {
43553 matchFeaturePosition = matchFeaturePosition - closestNumber$$1;
43554 }
43555 }
43556 }
43557
43558 if (matchFeaturePosition === +i) return;
43559
43560 var matchFeature = features[matchFeaturePosition];
43561 if (!matchFeature || !polygon$$1) return;
43562
43563 if (propertyName !== undefined &&
43564 matchFeature.properties[propertyName] !== polygon$$1.properties[propertyName]) return;
43565
43566 if (!booleanOverlap(polygon$$1, matchFeature) || !ringsIntersect(polygon$$1, matchFeature)) return;
43567
43568 features[i] = union(polygon$$1, matchFeature);
43569
43570 originalIndexOfItemsRemoved.push(potentialMatchingFeature.properties.origIndexPosition);
43571 originalIndexOfItemsRemoved.sort(function (a, b) {
43572 return a - b;
43573 });
43574
43575 tree.remove(potentialMatchingFeature);
43576 features.splice(matchFeaturePosition, 1);
43577 polygon$$1.properties.origIndexPosition = i;
43578 tree.remove(polygon$$1, function (a, b) {
43579 return a.properties.origIndexPosition === b.properties.origIndexPosition;
43580 });
43581 featureChanged = true;
43582 });
43583
43584 if (featureChanged) {
43585 if (!polygon$$1) continue;
43586 polygon$$1.properties.origIndexPosition = i;
43587 tree.insert(polygon$$1);
43588 i--;
43589 }
43590 }
43591
43592 features.forEach(function (f) {
43593 delete f.properties.origIndexPosition;
43594 delete f.bbox;
43595 });
43596
43597 return fc;
43598}
43599
43600function ringsIntersect(poly1, poly2) {
43601 var line1 = lineString(coordAll(poly1));
43602 var line2 = lineString(coordAll(poly2));
43603 var points$$1 = lineIntersect(line1, line2).features;
43604 return points$$1.length > 0;
43605}
43606
43607/**
43608 * Takes a bounding box and the diameter of the cell and returns a {@link FeatureCollection} of flat-topped
43609 * hexagons or triangles ({@link Polygon} features) aligned in an "odd-q" vertical grid as
43610 * described in [Hexagonal Grids](http://www.redblobgames.com/grids/hexagons/).
43611 *
43612 * @name hexGrid
43613 * @param {BBox} bbox extent in [minX, minY, maxX, maxY] order
43614 * @param {number} cellSide length of the side of the the hexagons or triangles, in units. It will also coincide with the
43615 * radius of the circumcircle of the hexagons.
43616 * @param {Object} [options={}] Optional parameters
43617 * @param {string} [options.units='kilometers'] used in calculating cell size, can be degrees, radians, miles, or kilometers
43618 * @param {Object} [options.properties={}] passed to each hexagon or triangle of the grid
43619 * @param {Feature<Polygon|MultiPolygon>} [options.mask] if passed a Polygon or MultiPolygon, the grid Points will be created only inside it
43620 * @param {boolean} [options.triangles=false] whether to return as triangles instead of hexagons
43621 * @returns {FeatureCollection<Polygon>} a hexagonal grid
43622 * @example
43623 * var bbox = [-96,31,-84,40];
43624 * var cellSide = 50;
43625 * var options = {units: 'miles'};
43626 *
43627 * var hexgrid = turf.hexGrid(bbox, cellSide, options);
43628 *
43629 * //addToMap
43630 * var addToMap = [hexgrid];
43631 */
43632function hexGrid(bbox, cellSide, options) {
43633 // Optional parameters
43634 options = options || {};
43635 if (!isObject(options)) throw new Error('options is invalid');
43636 // var units = options.units;
43637 var properties = options.properties || {};
43638 var triangles = options.triangles;
43639 var mask = options.mask;
43640
43641 // validation
43642 if (cellSide === null || cellSide === undefined) throw new Error('cellSide is required');
43643 if (!isNumber(cellSide)) throw new Error('cellSide is invalid');
43644 if (!bbox) throw new Error('bbox is required');
43645 if (!Array.isArray(bbox)) throw new Error('bbox must be array');
43646 if (bbox.length !== 4) throw new Error('bbox must contain 4 numbers');
43647 if (mask && ['Polygon', 'MultiPolygon'].indexOf(getType(mask)) === -1) throw new Error('options.mask must be a (Multi)Polygon');
43648
43649 var west = bbox[0];
43650 var south = bbox[1];
43651 var east = bbox[2];
43652 var north = bbox[3];
43653 var centerY = (south + north) / 2;
43654 var centerX = (west + east) / 2;
43655
43656 // https://github.com/Turfjs/turf/issues/758
43657 var xFraction = cellSide * 2 / (distance([west, centerY], [east, centerY], options));
43658 var cellWidth = xFraction * (east - west);
43659 var yFraction = cellSide * 2 / (distance([centerX, south], [centerX, north], options));
43660 var cellHeight = yFraction * (north - south);
43661 var radius = cellWidth / 2;
43662
43663 var hex_width = radius * 2;
43664 var hex_height = Math.sqrt(3) / 2 * cellHeight;
43665
43666 var box_width = east - west;
43667 var box_height = north - south;
43668
43669 var x_interval = 3 / 4 * hex_width;
43670 var y_interval = hex_height;
43671
43672 // adjust box_width so all hexagons will be inside the bbox
43673 var x_span = (box_width - hex_width) / (hex_width - radius / 2);
43674 var x_count = Math.floor(x_span);
43675
43676 var x_adjust = ((x_count * x_interval - radius / 2) - box_width) / 2 - radius / 2 + x_interval / 2;
43677
43678 // adjust box_height so all hexagons will be inside the bbox
43679 var y_count = Math.floor((box_height - hex_height) / hex_height);
43680
43681 var y_adjust = (box_height - y_count * hex_height) / 2;
43682
43683 var hasOffsetY = y_count * hex_height - box_height > hex_height / 2;
43684 if (hasOffsetY) {
43685 y_adjust -= hex_height / 4;
43686 }
43687
43688 // Precompute cosines and sines of angles used in hexagon creation for performance gain
43689 var cosines = [];
43690 var sines = [];
43691 for (var i = 0; i < 6; i++) {
43692 var angle = 2 * Math.PI / 6 * i;
43693 cosines.push(Math.cos(angle));
43694 sines.push(Math.sin(angle));
43695 }
43696
43697 var results = [];
43698 for (var x = 0; x <= x_count; x++) {
43699 for (var y = 0; y <= y_count; y++) {
43700
43701 var isOdd = x % 2 === 1;
43702 if (y === 0 && isOdd) continue;
43703 if (y === 0 && hasOffsetY) continue;
43704
43705 var center_x = x * x_interval + west - x_adjust;
43706 var center_y = y * y_interval + south + y_adjust;
43707
43708 if (isOdd) {
43709 center_y -= hex_height / 2;
43710 }
43711
43712 if (triangles === true) {
43713 hexTriangles(
43714 [center_x, center_y],
43715 cellWidth / 2,
43716 cellHeight / 2,
43717 properties,
43718 cosines,
43719 sines).forEach(function (triangle) {
43720 if (mask) {
43721 if (intersect$2(mask, triangle)) results.push(triangle);
43722 } else {
43723 results.push(triangle);
43724 }
43725 });
43726 } else {
43727 var hex = hexagon(
43728 [center_x, center_y],
43729 cellWidth / 2,
43730 cellHeight / 2,
43731 properties,
43732 cosines,
43733 sines
43734 );
43735 if (mask) {
43736 if (intersect$2(mask, hex)) results.push(hex);
43737 } else {
43738 results.push(hex);
43739 }
43740 }
43741 }
43742 }
43743
43744 return featureCollection(results);
43745}
43746
43747/**
43748 * Creates hexagon
43749 *
43750 * @private
43751 * @param {Array<number>} center of the hexagon
43752 * @param {number} rx half hexagon width
43753 * @param {number} ry half hexagon height
43754 * @param {Object} properties passed to each hexagon
43755 * @param {Array<number>} cosines precomputed
43756 * @param {Array<number>} sines precomputed
43757 * @returns {Feature<Polygon>} hexagon
43758 */
43759function hexagon(center, rx, ry, properties, cosines, sines) {
43760 var vertices = [];
43761 for (var i = 0; i < 6; i++) {
43762 var x = center[0] + rx * cosines[i];
43763 var y = center[1] + ry * sines[i];
43764 vertices.push([x, y]);
43765 }
43766 //first and last vertex must be the same
43767 vertices.push(vertices[0].slice());
43768 return polygon([vertices], properties);
43769}
43770
43771/**
43772 * Creates triangles composing an hexagon
43773 *
43774 * @private
43775 * @param {Array<number>} center of the hexagon
43776 * @param {number} rx half triangle width
43777 * @param {number} ry half triangle height
43778 * @param {Object} properties passed to each triangle
43779 * @param {Array<number>} cosines precomputed
43780 * @param {Array<number>} sines precomputed
43781 * @returns {Array<Feature<Polygon>>} triangles
43782 */
43783function hexTriangles(center, rx, ry, properties, cosines, sines) {
43784 var triangles = [];
43785 for (var i = 0; i < 6; i++) {
43786 var vertices = [];
43787 vertices.push(center);
43788 vertices.push([
43789 center[0] + rx * cosines[i],
43790 center[1] + ry * sines[i]
43791 ]);
43792 vertices.push([
43793 center[0] + rx * cosines[(i + 1) % 6],
43794 center[1] + ry * sines[(i + 1) % 6]
43795 ]);
43796 vertices.push(center);
43797 triangles.push(polygon([vertices], properties));
43798 }
43799 return triangles;
43800}
43801
43802/**
43803 * Takes any type of {@link Polygon|polygon} and an optional mask and returns a {@link Polygon|polygon} exterior ring with holes.
43804 *
43805 * @name mask
43806 * @param {FeatureCollection|Feature<Polygon|MultiPolygon>} polygon GeoJSON Polygon used as interior rings or holes.
43807 * @param {Feature<Polygon>} [mask] GeoJSON Polygon used as the exterior ring (if undefined, the world extent is used)
43808 * @returns {Feature<Polygon>} Masked Polygon (exterior ring with holes).
43809 * @example
43810 * var polygon = turf.polygon([[[112, -21], [116, -36], [146, -39], [153, -24], [133, -10], [112, -21]]]);
43811 * var mask = turf.polygon([[[90, -55], [170, -55], [170, 10], [90, 10], [90, -55]]]);
43812 *
43813 * var masked = turf.mask(polygon, mask);
43814 *
43815 * //addToMap
43816 * var addToMap = [masked]
43817 */
43818function mask(polygon$$1, mask) {
43819 // Define mask
43820 var maskPolygon = createMask(mask);
43821
43822 // Define polygon
43823 var separated = separatePolygons(polygon$$1);
43824 var polygonOuters = separated[0];
43825 var polygonInners = separated[1];
43826
43827 // Union Outers & Inners
43828 polygonOuters = unionPolygons(polygonOuters);
43829 polygonInners = unionPolygons(polygonInners);
43830
43831 // Create masked area
43832 var masked = buildMask(maskPolygon, polygonOuters, polygonInners);
43833 return masked;
43834}
43835
43836/**
43837 * Build Mask
43838 *
43839 * @private
43840 * @param {Feature<Polygon>} maskPolygon Mask Outer
43841 * @param {FeatureCollection<Polygon>} polygonOuters Polygon Outers
43842 * @param {FeatureCollection<Polygon>} polygonInners Polygon Inners
43843 * @returns {Feature<Polygon>} Feature Polygon
43844 */
43845function buildMask(maskPolygon, polygonOuters, polygonInners) {
43846 var coordinates = [];
43847 coordinates.push(maskPolygon.geometry.coordinates[0]);
43848
43849 flattenEach(polygonOuters, function (feature$$1) {
43850 coordinates.push(feature$$1.geometry.coordinates[0]);
43851 });
43852
43853 flattenEach(polygonInners, function (feature$$1) {
43854 coordinates.push(feature$$1.geometry.coordinates[0]);
43855 });
43856 return polygon(coordinates);
43857}
43858
43859/**
43860 * Separate Polygons to inners & outers
43861 *
43862 * @private
43863 * @param {FeatureCollection|Feature<Polygon|MultiPolygon>} poly GeoJSON Feature
43864 * @returns {Array<FeatureCollection<Polygon>, FeatureCollection<Polygon>>} Outer & Inner lines
43865 */
43866function separatePolygons(poly) {
43867 var outers = [];
43868 var inners = [];
43869 flattenEach(poly, function (feature$$1) {
43870 var coordinates = feature$$1.geometry.coordinates;
43871 var featureOuter = coordinates[0];
43872 var featureInner = coordinates.slice(1);
43873 outers.push(polygon([featureOuter]));
43874 featureInner.forEach(function (inner) {
43875 inners.push(polygon([inner]));
43876 });
43877 });
43878 return [featureCollection(outers), featureCollection(inners)];
43879}
43880
43881/**
43882 * Create Mask Coordinates
43883 *
43884 * @private
43885 * @param {Feature<Polygon>} [mask] default to world if undefined
43886 * @returns {Feature<Polygon>} mask coordinate
43887 */
43888function createMask(mask) {
43889 var world = [[[180, 90], [-180, 90], [-180, -90], [180, -90], [180, 90]]];
43890 var coordinates = mask && mask.geometry.coordinates || world;
43891 return polygon(coordinates);
43892}
43893
43894/**
43895 * Union Polygons
43896 *
43897 * @private
43898 * @param {FeatureCollection<Polygon>} polygons collection of polygons
43899 * @returns {FeatureCollection<Polygon>} polygons only apply union if they collide
43900 */
43901function unionPolygons(polygons$$1) {
43902 if (polygons$$1.features.length <= 1) return polygons$$1;
43903
43904 var tree = createIndex(polygons$$1);
43905 var results = [];
43906 var removed = {};
43907
43908 flattenEach(polygons$$1, function (currentFeature, currentIndex) {
43909 // Exclude any removed features
43910 if (removed[currentIndex]) return true;
43911
43912 // Don't search for itself
43913 tree.remove({index: currentIndex}, filterByIndex);
43914 removed[currentIndex] = true;
43915
43916 // Keep applying the union operation until no more overlapping features
43917 while (true) {
43918 var bbox$$1 = bbox(currentFeature);
43919 var search = tree.search({
43920 minX: bbox$$1[0],
43921 minY: bbox$$1[1],
43922 maxX: bbox$$1[2],
43923 maxY: bbox$$1[3]
43924 });
43925 if (search.length > 0) {
43926 var polys = search.map(function (item) {
43927 removed[item.index] = true;
43928 tree.remove({index: item.index}, filterByIndex);
43929 return item.geojson;
43930 });
43931 polys.push(currentFeature);
43932 currentFeature = union.apply(this, polys);
43933 }
43934 // Done
43935 if (search.length === 0) break;
43936 }
43937 results.push(currentFeature);
43938 });
43939
43940 return featureCollection(results);
43941}
43942
43943/**
43944 * Filter by Index - RBush helper function
43945 *
43946 * @private
43947 * @param {Object} a remove item
43948 * @param {Object} b search item
43949 * @returns {boolean} true if matches
43950 */
43951function filterByIndex(a, b) {
43952 return a.index === b.index;
43953}
43954
43955/**
43956 * Create RBush Tree Index
43957 *
43958 * @private
43959 * @param {FeatureCollection<any>} features GeoJSON FeatureCollection
43960 * @returns {RBush} RBush Tree
43961 */
43962function createIndex(features) {
43963 var tree = rbush_1();
43964 var load = [];
43965 flattenEach(features, function (feature$$1, index) {
43966 var bbox$$1 = bbox(feature$$1);
43967 load.push({
43968 minX: bbox$$1[0],
43969 minY: bbox$$1[1],
43970 maxX: bbox$$1[2],
43971 maxY: bbox$$1[3],
43972 geojson: feature$$1,
43973 index: index
43974 });
43975 });
43976 tree.load(load);
43977 return tree;
43978}
43979
43980/**
43981 * Creates a square grid from a bounding box, {@link Feature} or {@link FeatureCollection}.
43982 *
43983 * @name squareGrid
43984 * @param {Array<number>} bbox extent in [minX, minY, maxX, maxY] order
43985 * @param {number} cellSide of each cell, in units
43986 * @param {Object} [options={}] Optional parameters
43987 * @param {string} [options.units='kilometers'] used in calculating cellSide, can be degrees, radians, miles, or kilometers
43988 * @param {Feature<Polygon|MultiPolygon>} [options.mask] if passed a Polygon or MultiPolygon, the grid Points will be created only inside it
43989 * @param {Object} [options.properties={}] passed to each point of the grid
43990 * @returns {FeatureCollection<Polygon>} grid a grid of polygons
43991 * @example
43992 * var bbox = [-95, 30 ,-85, 40];
43993 * var cellSide = 50;
43994 * var options = {units: 'miles'};
43995 *
43996 * var squareGrid = turf.squareGrid(bbox, cellSide, options);
43997 *
43998 * //addToMap
43999 * var addToMap = [squareGrid]
44000 */
44001function squareGrid(bbox, cellSide, options) {
44002 // Optional parameters
44003 options = options || {};
44004 if (!isObject(options)) throw new Error('options is invalid');
44005 // var units = options.units;
44006 var properties = options.properties;
44007 var mask = options.mask;
44008
44009 // Containers
44010 var results = [];
44011
44012 // Input Validation
44013 if (cellSide === null || cellSide === undefined) throw new Error('cellSide is required');
44014 if (!isNumber(cellSide)) throw new Error('cellSide is invalid');
44015 if (!bbox) throw new Error('bbox is required');
44016 if (!Array.isArray(bbox)) throw new Error('bbox must be array');
44017 if (bbox.length !== 4) throw new Error('bbox must contain 4 numbers');
44018 if (mask && ['Polygon', 'MultiPolygon'].indexOf(getType(mask)) === -1) throw new Error('options.mask must be a (Multi)Polygon');
44019
44020 var west = bbox[0];
44021 var south = bbox[1];
44022 var east = bbox[2];
44023 var north = bbox[3];
44024
44025 var xFraction = cellSide / (distance([west, south], [east, south], options));
44026 var cellWidth = xFraction * (east - west);
44027 var yFraction = cellSide / (distance([west, south], [west, north], options));
44028 var cellHeight = yFraction * (north - south);
44029
44030 // rows & columns
44031 var bboxWidth = (east - west);
44032 var bboxHeight = (north - south);
44033 var columns = Math.floor(bboxWidth / cellWidth);
44034 var rows = Math.floor(bboxHeight / cellHeight);
44035
44036 // adjust origin of the grid
44037 var deltaX = (bboxWidth - columns * cellWidth) / 2;
44038 var deltaY = (bboxHeight - rows * cellHeight) / 2;
44039
44040 // iterate over columns & rows
44041 var currentX = west + deltaX;
44042 for (var column = 0; column < columns; column++) {
44043 var currentY = south + deltaY;
44044 for (var row = 0; row < rows; row++) {
44045 var cellPoly = polygon([[
44046 [currentX, currentY],
44047 [currentX, currentY + cellHeight],
44048 [currentX + cellWidth, currentY + cellHeight],
44049 [currentX + cellWidth, currentY],
44050 [currentX, currentY]
44051 ]], properties);
44052 if (mask) {
44053 if (intersect$2(mask, cellPoly)) results.push(cellPoly);
44054 } else {
44055 results.push(cellPoly);
44056 }
44057
44058 currentY += cellHeight;
44059 }
44060 currentX += cellWidth;
44061 }
44062 return featureCollection(results);
44063}
44064
44065/**
44066 * Takes a bounding box and a cell depth and returns a set of triangular {@link Polygon|polygons} in a grid.
44067 *
44068 * @name triangleGrid
44069 * @param {Array<number>} bbox extent in [minX, minY, maxX, maxY] order
44070 * @param {number} cellSide dimension of each cell
44071 * @param {Object} [options={}] Optional parameters
44072 * @param {string} [options.units='kilometers'] used in calculating cellSide, can be degrees, radians, miles, or kilometers
44073 * @param {Feature<Polygon|MultiPolygon>} [options.mask] if passed a Polygon or MultiPolygon, the grid Points will be created only inside it
44074 * @param {Object} [options.properties={}] passed to each point of the grid
44075 * @returns {FeatureCollection<Polygon>} grid of polygons
44076 * @example
44077 * var bbox = [-95, 30 ,-85, 40];
44078 * var cellSide = 50;
44079 * var options = {units: 'miles'};
44080 *
44081 * var triangleGrid = turf.triangleGrid(bbox, cellSide, options);
44082 *
44083 * //addToMap
44084 * var addToMap = [triangleGrid];
44085 */
44086function triangleGrid(bbox, cellSide, options) {
44087 // Optional parameters
44088 options = options || {};
44089 if (!isObject(options)) throw new Error('options is invalid');
44090 // var units = options.units;
44091 var properties = options.properties;
44092 var mask = options.mask;
44093
44094 // Containers
44095 var results = [];
44096
44097 // Input Validation
44098 if (cellSide === null || cellSide === undefined) throw new Error('cellSide is required');
44099 if (!isNumber(cellSide)) throw new Error('cellSide is invalid');
44100 if (!bbox) throw new Error('bbox is required');
44101 if (!Array.isArray(bbox)) throw new Error('bbox must be array');
44102 if (bbox.length !== 4) throw new Error('bbox must contain 4 numbers');
44103 if (mask && ['Polygon', 'MultiPolygon'].indexOf(getType(mask)) === -1) throw new Error('options.mask must be a (Multi)Polygon');
44104
44105 // Main
44106 var xFraction = cellSide / (distance([bbox[0], bbox[1]], [bbox[2], bbox[1]], options));
44107 var cellWidth = xFraction * (bbox[2] - bbox[0]);
44108 var yFraction = cellSide / (distance([bbox[0], bbox[1]], [bbox[0], bbox[3]], options));
44109 var cellHeight = yFraction * (bbox[3] - bbox[1]);
44110
44111 var xi = 0;
44112 var currentX = bbox[0];
44113 while (currentX <= bbox[2]) {
44114 var yi = 0;
44115 var currentY = bbox[1];
44116 while (currentY <= bbox[3]) {
44117 var cellTriangle1 = null;
44118 var cellTriangle2 = null;
44119
44120 if (xi % 2 === 0 && yi % 2 === 0) {
44121 cellTriangle1 = polygon([[
44122 [currentX, currentY],
44123 [currentX, currentY + cellHeight],
44124 [currentX + cellWidth, currentY],
44125 [currentX, currentY]
44126 ]], properties);
44127 cellTriangle2 = polygon([[
44128 [currentX, currentY + cellHeight],
44129 [currentX + cellWidth, currentY + cellHeight],
44130 [currentX + cellWidth, currentY],
44131 [currentX, currentY + cellHeight]
44132 ]], properties);
44133 } else if (xi % 2 === 0 && yi % 2 === 1) {
44134 cellTriangle1 = polygon([[
44135 [currentX, currentY],
44136 [currentX + cellWidth, currentY + cellHeight],
44137 [currentX + cellWidth, currentY],
44138 [currentX, currentY]
44139 ]], properties);
44140 cellTriangle2 = polygon([[
44141 [currentX, currentY],
44142 [currentX, currentY + cellHeight],
44143 [currentX + cellWidth, currentY + cellHeight],
44144 [currentX, currentY]
44145 ]], properties);
44146 } else if (yi % 2 === 0 && xi % 2 === 1) {
44147 cellTriangle1 = polygon([[
44148 [currentX, currentY],
44149 [currentX, currentY + cellHeight],
44150 [currentX + cellWidth, currentY + cellHeight],
44151 [currentX, currentY]
44152 ]], properties);
44153 cellTriangle2 = polygon([[
44154 [currentX, currentY],
44155 [currentX + cellWidth, currentY + cellHeight],
44156 [currentX + cellWidth, currentY],
44157 [currentX, currentY]
44158 ]], properties);
44159 } else if (yi % 2 === 1 && xi % 2 === 1) {
44160 cellTriangle1 = polygon([[
44161 [currentX, currentY],
44162 [currentX, currentY + cellHeight],
44163 [currentX + cellWidth, currentY],
44164 [currentX, currentY]
44165 ]], properties);
44166 cellTriangle2 = polygon([[
44167 [currentX, currentY + cellHeight],
44168 [currentX + cellWidth, currentY + cellHeight],
44169 [currentX + cellWidth, currentY],
44170 [currentX, currentY + cellHeight]
44171 ]], properties);
44172 }
44173 if (mask) {
44174 if (intersect$2(mask, cellTriangle1)) results.push(cellTriangle1);
44175 if (intersect$2(mask, cellTriangle2)) results.push(cellTriangle2);
44176 } else {
44177 results.push(cellTriangle1);
44178 results.push(cellTriangle2);
44179 }
44180
44181 currentY += cellHeight;
44182 yi++;
44183 }
44184 xi++;
44185 currentX += cellWidth;
44186 }
44187 return featureCollection(results);
44188}
44189
44190/**
44191 * Takes a set of points and estimates their 'property' values on a grid using the [Inverse Distance Weighting (IDW) method](https://en.wikipedia.org/wiki/Inverse_distance_weighting).
44192 *
44193 * @name interpolate
44194 * @param {FeatureCollection<Point>} points with known value
44195 * @param {number} cellSize the distance across each grid point
44196 * @param {Object} [options={}] Optional parameters
44197 * @param {string} [options.gridType='square'] defines the output format based on a Grid Type (options: 'square' | 'point' | 'hex' | 'triangle')
44198 * @param {string} [options.property='elevation'] the property name in `points` from which z-values will be pulled, zValue fallbacks to 3rd coordinate if no property exists.
44199 * @param {string} [options.units='kilometers'] used in calculating cellSize, can be degrees, radians, miles, or kilometers
44200 * @param {number} [options.weight=1] exponent regulating the distance-decay weighting
44201 * @returns {FeatureCollection<Point|Polygon>} grid of points or polygons with interpolated 'property'
44202 * @example
44203 * var points = turf.randomPoint(30, {bbox: [50, 30, 70, 50]});
44204 *
44205 * // add a random property to each point
44206 * turf.featureEach(points, function(point) {
44207 * point.properties.solRad = Math.random() * 50;
44208 * });
44209 * var options = {gridType: 'points', property: 'solRad', units: 'miles'};
44210 * var grid = turf.interpolate(points, 100, options);
44211 *
44212 * //addToMap
44213 * var addToMap = [grid];
44214 */
44215function interpolate$1(points$$1, cellSize, options) {
44216 // Optional parameters
44217 options = options || {};
44218 if (typeof options !== 'object') throw new Error('options is invalid');
44219 var gridType = options.gridType;
44220 var property = options.property;
44221 var weight = options.weight;
44222
44223 // validation
44224 if (!points$$1) throw new Error('points is required');
44225 collectionOf(points$$1, 'Point', 'input must contain Points');
44226 if (!cellSize) throw new Error('cellSize is required');
44227 if (weight !== undefined && typeof weight !== 'number') throw new Error('weight must be a number');
44228
44229 // default values
44230 property = property || 'elevation';
44231 gridType = gridType || 'square';
44232 weight = weight || 1;
44233
44234 var box = bbox(points$$1);
44235 var grid;
44236 switch (gridType) {
44237 case 'point':
44238 case 'points':
44239 grid = pointGrid(box, cellSize, options);
44240 break;
44241 case 'square':
44242 case 'squares':
44243 grid = squareGrid(box, cellSize, options);
44244 break;
44245 case 'hex':
44246 case 'hexes':
44247 grid = hexGrid(box, cellSize, options);
44248 break;
44249 case 'triangle':
44250 case 'triangles':
44251 grid = triangleGrid(box, cellSize, options);
44252 break;
44253 default:
44254 throw new Error('invalid gridType');
44255 }
44256 var results = [];
44257 featureEach(grid, function (gridFeature) {
44258 var zw = 0;
44259 var sw = 0;
44260 // calculate the distance from each input point to the grid points
44261 featureEach(points$$1, function (point$$1) {
44262 var gridPoint = (gridType === 'point') ? gridFeature : centroid(gridFeature);
44263 var d = distance(gridPoint, point$$1, options);
44264 var zValue;
44265 // property has priority for zValue, fallbacks to 3rd coordinate from geometry
44266 if (property !== undefined) zValue = point$$1.properties[property];
44267 if (zValue === undefined) zValue = point$$1.geometry.coordinates[2];
44268 if (zValue === undefined) throw new Error('zValue is missing');
44269 if (d === 0) zw = zValue;
44270 var w = 1.0 / Math.pow(d, weight);
44271 sw += w;
44272 zw += w * zValue;
44273 });
44274 // write interpolated value for each grid point
44275 var newFeature = clone(gridFeature);
44276 newFeature.properties[property] = zw / sw;
44277 results.push(newFeature);
44278 });
44279 return featureCollection(results);
44280}
44281
44282/**
44283 * Turf is a modular geospatial analysis engine written in JavaScript. It performs geospatial
44284 * processing tasks with GeoJSON data and can be run on a server or in a browser.
44285 *
44286 * @module turf
44287 * @summary Geospatial analysis for JavaScript
44288 */
44289
44290exports.projection = main_es$3;
44291exports.random = main_es$4;
44292exports.clusters = main_es$5;
44293exports.helpers = main_es$1;
44294exports.invariant = main_es$2;
44295exports.meta = main_es;
44296exports.isolines = isolines;
44297exports.convex = convex;
44298exports.pointsWithinPolygon = pointsWithinPolygon;
44299exports.concave = concave;
44300exports.collect = collect;
44301exports.flip = flip;
44302exports.simplify = simplify;
44303exports.bezierSpline = bezier;
44304exports.tag = tag;
44305exports.sample = sample;
44306exports.envelope = envelope;
44307exports.square = square;
44308exports.circle = circle;
44309exports.midpoint = midpoint;
44310exports.center = center;
44311exports.centerOfMass = centerOfMass;
44312exports.centroid = centroid;
44313exports.combine = combine;
44314exports.distance = distance;
44315exports.explode = explode;
44316exports.bbox = bbox;
44317exports.tesselate = tesselate;
44318exports.bboxPolygon = bboxPolygon;
44319exports.booleanPointInPolygon = booleanPointInPolygon;
44320exports.nearestPoint = nearestPoint;
44321exports.nearestPointOnLine = nearestPointOnLine;
44322exports.nearestPointToLine = nearestPointToLine;
44323exports.planepoint = planepoint;
44324exports.tin = tin;
44325exports.bearing = bearing;
44326exports.destination = destination;
44327exports.kinks = kinks;
44328exports.pointOnFeature = pointOnFeature;
44329exports.area = area$1;
44330exports.along = along;
44331exports.length = length;
44332exports.lineSlice = lineSlice;
44333exports.lineSliceAlong = lineSliceAlong;
44334exports.pointGrid = pointGrid;
44335exports.truncate = truncate;
44336exports.flatten = flatten;
44337exports.lineIntersect = lineIntersect;
44338exports.lineChunk = lineChunk;
44339exports.unkinkPolygon = unkinkPolygon;
44340exports.greatCircle = greatCircle;
44341exports.lineSegment = lineSegment;
44342exports.lineSplit = lineSplit;
44343exports.lineArc = lineArc;
44344exports.polygonToLine = polygonToLine;
44345exports.lineToPolygon = lineToPolygon;
44346exports.bboxClip = bboxClip;
44347exports.lineOverlap = lineOverlap;
44348exports.sector = sector;
44349exports.rhumbBearing = rhumbBearing;
44350exports.rhumbDistance = rhumbDistance;
44351exports.rhumbDestination = rhumbDestination;
44352exports.polygonTangents = polygonTangents;
44353exports.rewind = rewind;
44354exports.isobands = isobands;
44355exports.transformRotate = transformRotate;
44356exports.transformScale = transformScale;
44357exports.transformTranslate = transformTranslate;
44358exports.lineOffset = lineOffset;
44359exports.polygonize = polygonize$1;
44360exports.booleanDisjoint = booleanDisjoint;
44361exports.booleanContains = booleanContains;
44362exports.booleanCrosses = booleanCrosses;
44363exports.booleanClockwise = booleanClockwise;
44364exports.booleanOverlap = booleanOverlap;
44365exports.booleanPointOnLine = booleanPointOnLine;
44366exports.booleanEqual = booleanEqual;
44367exports.booleanWithin = booleanWithin;
44368exports.clone = clone;
44369exports.cleanCoords = cleanCoords;
44370exports.clustersDbscan = clustersDbscan;
44371exports.clustersKmeans = clustersKmeans;
44372exports.pointToLineDistance = pointToLineDistance;
44373exports.booleanParallel = booleanParallel;
44374exports.shortestPath = shortestPath;
44375exports.voronoi = voronoi$1;
44376exports.ellipse = ellipse;
44377exports.centerMean = centerMean;
44378exports.centerMedian = centerMedian;
44379exports.standardDeviationalEllipse = standardDeviationalEllipse;
44380exports.difference = difference;
44381exports.buffer = buffer$1;
44382exports.union = union;
44383exports.intersect = intersect$2;
44384exports.dissolve = dissolve$1;
44385exports.hexGrid = hexGrid;
44386exports.mask = mask;
44387exports.squareGrid = squareGrid;
44388exports.triangleGrid = triangleGrid;
44389exports.interpolate = interpolate$1;
44390exports.pointOnSurface = pointOnFeature;
44391exports.polygonToLineString = polygonToLine;
44392exports.lineStringToPolygon = lineToPolygon;
44393exports.inside = booleanPointInPolygon;
44394exports.within = pointsWithinPolygon;
44395exports.bezier = bezier;
44396exports.nearest = nearestPoint;
44397exports.pointOnLine = nearestPointOnLine;
44398exports.lineDistance = length;
44399exports.radians2degrees = radiansToDegrees;
44400exports.degrees2radians = degreesToRadians;
44401exports.distanceToDegrees = lengthToDegrees;
44402exports.distanceToRadians = lengthToRadians;
44403exports.radiansToDistance = radiansToLength;
44404exports.bearingToAngle = bearingToAzimuth;
44405exports.convertDistance = convertLength;
44406exports.toMercator = toMercator;
44407exports.toWgs84 = toWgs84;
44408exports.randomPosition = randomPosition;
44409exports.randomPoint = randomPoint;
44410exports.randomPolygon = randomPolygon;
44411exports.randomLineString = randomLineString;
44412exports.getCluster = getCluster;
44413exports.clusterEach = clusterEach;
44414exports.clusterReduce = clusterReduce;
44415exports.createBins = createBins;
44416exports.applyFilter = applyFilter;
44417exports.propertiesContainsFilter = propertiesContainsFilter;
44418exports.filterProperties = filterProperties;
44419exports.earthRadius = earthRadius;
44420exports.factors = factors;
44421exports.unitsFactors = unitsFactors;
44422exports.areaFactors = areaFactors;
44423exports.feature = feature;
44424exports.geometry = geometry;
44425exports.point = point;
44426exports.points = points;
44427exports.polygon = polygon;
44428exports.polygons = polygons;
44429exports.lineString = lineString;
44430exports.lineStrings = lineStrings;
44431exports.featureCollection = featureCollection;
44432exports.multiLineString = multiLineString;
44433exports.multiPoint = multiPoint;
44434exports.multiPolygon = multiPolygon;
44435exports.geometryCollection = geometryCollection;
44436exports.round = round;
44437exports.radiansToLength = radiansToLength;
44438exports.lengthToRadians = lengthToRadians;
44439exports.lengthToDegrees = lengthToDegrees;
44440exports.bearingToAzimuth = bearingToAzimuth;
44441exports.radiansToDegrees = radiansToDegrees;
44442exports.degreesToRadians = degreesToRadians;
44443exports.convertLength = convertLength;
44444exports.convertArea = convertArea;
44445exports.isNumber = isNumber;
44446exports.isObject = isObject;
44447exports.validateBBox = validateBBox;
44448exports.validateId = validateId;
44449exports.getCoord = getCoord;
44450exports.getCoords = getCoords;
44451exports.containsNumber = containsNumber;
44452exports.geojsonType = geojsonType;
44453exports.featureOf = featureOf;
44454exports.collectionOf = collectionOf;
44455exports.getGeom = getGeom;
44456exports.getGeomType = getGeomType;
44457exports.getType = getType;
44458exports.coordEach = coordEach;
44459exports.coordReduce = coordReduce;
44460exports.propEach = propEach;
44461exports.propReduce = propReduce;
44462exports.featureEach = featureEach;
44463exports.featureReduce = featureReduce;
44464exports.coordAll = coordAll;
44465exports.geomEach = geomEach;
44466exports.geomReduce = geomReduce;
44467exports.flattenEach = flattenEach;
44468exports.flattenReduce = flattenReduce;
44469exports.segmentEach = segmentEach;
44470exports.segmentReduce = segmentReduce;
44471exports.lineEach = lineEach;
44472exports.lineReduce = lineReduce;
44473
44474Object.defineProperty(exports, '__esModule', { value: true });
44475
44476})));