Source: api/GeometryUtils.js

Retour à la documentation
/**
 * @class spw.api.GeometryUtils
 * @classdesc Classe utilitaire permettant de réaliser des opération topologiques sur 
 */
define([
    'dojo/_base/lang', 'dojo/_base/array', 'esri/geometry/geometryEngine',
    'spw/api/GeometryConverter', 'esri/geometry/Polyline', 'spw/api/ProjectionManager',
    'esri/geometry/Point',

    'spw/libs/turf'
],
/** @lends spw.api.GeometryUtils.prototype */
function(lang, array, geometryEngine, GeometryConverter, Polyline, ProjectionManager, Point, turf) {

    var self = {
        buffer: function(geoms, distance, unit, union) {
            geoms = [].concat(geoms);

            // array.forEach(geoms, lang.hitch(this, function(geom) {
            //     geom.getExtent && geom.getExtent(); // to generate cache
            // }));

            union = (union == null ? true : union);

            // var results = [];
            //
            // array.forEach(geoms, function(geom) {
            //
            //     var wgs84 = self._transformGeometry(geom.spatialReference.wkid, '4326', geom);
            //
            //     var geojson = self.toGeoJSON(wgs84);
            //
            //     geojson = turf.buffer({
            //         type: 'Feature',
            //         properties: {},
            //         geometry: geojson
            //     }, distance, unit);
            //
            //     if (geojson.type === 'FeatureCollection') {
            //         geojson = turf.combine(geojson).geometry;
            //     }
            //     else {
            //         geojson = geojson.feature.geometry;
            //     }
            //
            //     wgs84 = self.toEsri(geojson);
            //
            //     results.push(self._transformGeometry('4326', geom.spatialReference.wkid, wgs84));
            // });
            //
            // if (union === true) {
            //     return self.union(results);
            // }
            // else {
            //     return results;
            // }

            var multiplier = 1;

            if (array.some(geoms, lang.hitch(this, function(geom) {
                var srid = lang.getObject('spatialReference.wkid', false, geom);
                return srid == 4326 || srid == 3857;
            }))) {
                multiplier = 1.60934;
            }

            var distances = array.map(geoms, function(){ return distance * multiplier; });
            var res = geometryEngine.buffer(geoms, distances, unit, union);

            if (res == null) {
                return res;
            }

            return res.length === 1 ? res[0] : res;
        },

        intersection: function(polygon, line) {
            var wgsPoly = self._transformGeometry(polygon.spatialReference.wkid, '4326', polygon);
            var geojsonPoly = self.toGeoJSON(wgsPoly);

            var wgsLine = self._transformGeometry(line.spatialReference.wkid, '4326', line);
            var geojsonLine = self.toGeoJSON(wgsLine);

            var lineSlices = self.lineSliceAtIntersection({
                type: 'Feature',
                properties: {},
                geometry: geojsonLine
            }, {
                type: 'Feature',
                properties: {},
                geometry: geojsonPoly
            });

            var pt = null;

            for (var i = 0; pt == null && i < lineSlices.features.length - 1; ++i) {
                var previous = lineSlices.features[i === 0 ? lineSlices.features.length - 1 : i - 1].geometry;
                var next = lineSlices.features[i + 1].geometry;
                var current = lineSlices.features[i].geometry;

                if (self.equal(current.coordinates[0], previous.coordinates[1])) {
                    pt = new Point(current.coordinates[0]);
                    pt.setSpatialReference(line.spatialReference);
                }
                else if (self.equal(current.coordinates[1], next.coordinates[0])) {
                    pt = new Point(current.coordinates[1]);
                    pt.setSpatialReference(line.spatialReference);
                }
            }

            return self._transformGeometry('4326', line.spatialReference.wkid, pt);
        },

        lineSliceAtIntersection: function(line, segmenter) {
            var coordRings = [];
            var segmenterFeatures = (segmenter.type === 'FeatureCollection') ?
                segmenter.features :
                [segmenter];

            var segments = [line.geometry.coordinates.slice()];

            for (var i = 0; i < segmenterFeatures.length; i++) {
                switch (segmenterFeatures[i].geometry.type) {
                    case 'LineString':
                        coordRings = [segmenterFeatures[i].geometry.coordinates];
                        break;
                    case 'MultiLineString':
                    case 'Polygon':
                        coordRings = segmenterFeatures[i].geometry.coordinates;
                        break;
                    case 'MultiPolygon':
                        for (var p = 0; p < segmenterFeatures[i].geometry.coordinates.length; p++) {
                            coordRings = coordRings.concat(segmenterFeatures[i].geometry.coordinates[p]);
                        }
                        break;
                }

                for (var j = 0; j < coordRings.length; j++) {
                    segments = self.testLineAndRing(segments, coordRings[j]);
                }
            }

            return turf.featurecollection(segments.map(function (segment) {
                return turf.linestring(segment, lang.mixin({}, line.properties));
            }));
        },

        testLineAndRing: function(segments, ring) {
            var tempSegments = [];

            for (var k = 0; k < segments.length; k++) {
                var curr = [];
                for (var l = 0; l < segments[k].length - 1; l++) {
                    curr.push(segments[k][l]);

                    for (var m = 0; m < ring.length - 1; m++) {

                        if (self.equal(segments[k][l], ring[m])) {
                            tempSegments.push(curr.slice());
                            curr = [segments[k][l]];
                            continue;
                        }

                        var is = self.linesIntersect(
                            segments[k][l],
                            segments[k][l + 1],
                            ring[m],
                            ring[m + 1]
                        );

                        if (is) {
                            curr.push(is);
                            tempSegments.push(curr.slice());
                            curr = [is];
                        }
                    }
                }
                curr.push(segments[k][segments[k].length - 1]);
                tempSegments.push(curr.slice());
            }

            return tempSegments;
        },

        equal: function(pt1, pt2) {
            return (pt1[0] === pt2[0] && pt1[1] === pt2[1]);
        },

        linesIntersect: function(a1, a2, b1, b2) {
            var uaT = (b2[0] - b1[0]) * (a1[1] - b1[1]) - (b2[1] - b1[1]) * (a1[0] - b1[0]),
                ubT = (a2[0] - a1[0]) * (a1[1] - b1[1]) - (a2[1] - a1[1]) * (a1[0] - b1[0]),
                uB = (b2[1] - b1[1]) * (a2[0] - a1[0]) - (b2[0] - b1[0]) * (a2[1] - a1[1]);

            if (uB !== 0) {
                var ua = uaT / uB,
                    ub = ubT / uB;
                if (ua > 0 && ua < 1 && ub > 0 && ub < 1) {
                    return [a1[0] + ua * (a2[0] - a1[0]), a1[1] + ua * (a2[1] - a1[1])];
                }
            }
        },

        area: function(geom, unit) {
//            var geojson = {
//                type: 'Feature',
//                properties: {},
//                geometry: self.toGeoJSON(self._transformGeometry(geom.spatialReference.wkid, '4326', geom))
//            };
//
//            return turf.area(geojson);
        	return (geom.spatialReference.wkid != 4326 && geom.spatialReference.wkid != 3857) ? geometryEngine.planarArea(geom, unit) : geometryEngine.geodesicArea(geom, unit);
        },
        
        geometryLength: function(geom, unit) {
        	return (geom.spatialReference.wkid != 4326 && geom.spatialReference.wkid != 3857) ? geometryEngine.planarLength(geom, unit) : geometryEngine.geodesicLength(geom, unit);
        },

        union: function(geometries) {
            return geometryEngine.union(geometries);
        },

        projectOnLine: function(line, pt) {
            var goodLine = line;

            if (line.paths.length > 1) {
                var minDis = Infinity;

                array.forEach(line.paths, function(path) {
                    var tmp = new Polyline(line.spatialReference);
                    tmp.addPath(path);

                    var dis = self.distance(tmp, pt);

                    if (dis < minDis) {
                        minDis = dis;
                        goodLine = tmp;
                    }
                });
            }

            var lineWgs84 = self._transformGeometry(goodLine.spatialReference.wkid, '4326', goodLine);
            var ptWgs84 = self._transformGeometry(pt.spatialReference.wkid, '4326', pt);

            var lineGeoJSON = {
                type: 'Feature',
                properties: {},
                geometry: self.toGeoJSON(lineWgs84)
            };

            var ptGeoJSON = {
                type: 'Feature',
                properties: {},
                geometry: self.toGeoJSON(ptWgs84)
            };

            var snapped = turf.pointOnLine(lineGeoJSON, ptGeoJSON);

            var wgs84 = self.toEsri(snapped.geometry);

            return self._transformGeometry('4326', goodLine.spatialReference.wkid, wgs84);
        },

        slice: function(pt1, pt2, line) {
            var lineWgs84 = self._transformGeometry(line.spatialReference.wkid, '4326', line);
            var pt1Wgs84 = self._transformGeometry(pt1.spatialReference.wkid, '4326', pt1);
            var pt2Wgs84 = self._transformGeometry(pt2.spatialReference.wkid, '4326', pt2);

            var lineGeoJSON = {
                type: 'Feature',
                properties: {},
                geometry: self.toGeoJSON(lineWgs84)
            };

            var pt1GeoJSON = {
                type: 'Feature',
                properties: {},
                geometry: self.toGeoJSON(pt1Wgs84)
            };

            var pt2GeoJSON = {
                type: 'Feature',
                properties: {},
                geometry: self.toGeoJSON(pt2Wgs84)
            };

            var sliced = turf.lineSlice(pt1GeoJSON, pt2GeoJSON, lineGeoJSON);

            var wgs84 = self.toEsri(sliced.geometry);

            return self._transformGeometry('4326', line.spatialReference.wkid, wgs84);
        },

        merge: function(features) {
            if (features.length === 1) {
                return features[0];
            }

            for (var i = 1; i < features.length; ++i) {
                array.forEach(features[i].paths, function(path) {
                    features[0].addPath(path);
                });
            }

            return features[0];
            /*var ftc = {
                type: 'FeatureCollection',
                features: array.map(features, function(feature) {
                    var wgs84 = self._transformGeometry(feature.spatialReference.wkid, '4326', feature);

                    var geojson = self.toGeoJSON(wgs84);

                    return {
                        type: 'Feature',
                        properties: {},
                        geometry: geojson
                    };
                })
            };

            var merged = turf.merge(ftc);

            var wgs84 = self.toEsri(merged.geometry);

            return self._transformGeometry('4326', features[0].spatialReference.wkid, wgs84);*/ // multiple paths
        },

        distance: function(from, to) {
            return geometryEngine.distance(from, to);
        },

        nearestPoint: function(geometry, pt) {
            return geometryEngine.nearestVertex(geometry, pt);
        },

        angleBetweenLines: function(line1, line2) {
            var l1pt1 = line1.getPoint(0, 0);
            var l1pt2 = line1.getPoint(0, 1);

            var l2pt1 = line2.getPoint(0, 0);
            var l2pt2 = line2.getPoint(0, 1);

            var angle1 = Math.atan2(l1pt1.y - l1pt2.y, l1pt1.x - l1pt2.x);
            var angle2 = Math.atan2(l2pt1.y - l2pt2.y, l2pt1.x - l2pt2.x);

            return self.radToDeg(angle1 - angle2);
        },

        length: function(geom) {
            return geometryEngine.planarLength(geom, 'meters');
        },

        rotate: function(geom, angle, pt) {
            return geometryEngine.rotate(geom, angle, pt);
        },

        radToDeg: function(rad) {
            return (rad * 180) / Math.PI;
        },

        degToRad: function(deg) {
            return (deg * Math.PI) / 180;
        },

        contains: function(container, contained) {
            var containers = [].concat(container);
            var unioned = self.union(array.map(containers, function(c) {
                if (c.getExtent) {
                    c.getExtent();
                }

                return c;
            }));

            if (contained.cache == null) {
                contained.getExtent();
            }

            return geometryEngine.contains(unioned, contained);
        },

        toGeoJSON: function(geom) {
            return GeometryConverter.esriToGeoJSON(geom);
        },

        touches: function(geom1, geom2) {
            return geometryEngine.touches(geom1, geom2);
        },

        intersects: function(geom1, geom2) {
            return geometryEngine.intersects(geom1, geom2);
        },

        toEsri: function(geojson) {
            var esri = GeometryConverter.geoJSONToEsri(geojson);

            // to refresh geometry's cache !
            if (esri.getExtent) {
                esri.getExtent();
            }

            return esri;
        },

        _transformGeometry: function(source, dest, geometry) {
            return ProjectionManager.getInstance().transform(source, dest, geometry);
        }
    };

    return self;

});