/* Copyright (c) 2016 Jean-Marc VIGLINO, released under the CeCILL-B license (French BSD license) (http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt). Usefull function to handle geometric operations */ import ol_geom_LineString from 'ol/geom/LineString.js' import ol_geom_LinearRing from 'ol/geom/LinearRing.js' import ol_geom_MultiLineString from 'ol/geom/MultiLineString.js' import ol_geom_MultiPoint from 'ol/geom/MultiPoint.js' import ol_geom_MultiPolygon from 'ol/geom/MultiPolygon.js' import ol_geom_Point from 'ol/geom/Point.js' import ol_geom_Polygon from 'ol/geom/Polygon.js' import ol_geom_Circle from 'ol/geom/Circle.js' import {getCenter as ol_extent_getCenter} from 'ol/extent.js' import {buffer as ol_extent_buffer} from 'ol/extent.js' /** Distance beetween 2 points * Usefull geometric functions * @param {ol.Coordinate} p1 first point * @param {ol.Coordinate} p2 second point * @return {number} distance */ var ol_coordinate_dist2d = function(p1, p2) { var dx = p1[0]-p2[0]; var dy = p1[1]-p2[1]; return Math.sqrt(dx*dx+dy*dy); } /** 2 points are equal * Usefull geometric functions * @param {ol.Coordinate} p1 first point * @param {ol.Coordinate} p2 second point * @return {boolean} */ var ol_coordinate_equal = function(p1, p2) { return (p1[0]==p2[0] && p1[1]==p2[1]); } /** Get center coordinate of a feature * @param {ol.Feature} f * @return {ol.coordinate} the center */ var ol_coordinate_getFeatureCenter = function(f) { return ol_coordinate_getGeomCenter (f.getGeometry()); }; /** Get center coordinate of a geometry * @param {ol.geom.Geometry} geom * @return {ol.Coordinate} the center */ var ol_coordinate_getGeomCenter = function(geom) { switch (geom.getType()) { case 'Point': return geom.getCoordinates(); case "MultiPolygon": geom = geom.getPolygon(0); // fallthrough case "Polygon": return geom.getInteriorPoint().getCoordinates(); default: return geom.getClosestPoint(ol_extent_getCenter(geom.getExtent())); } }; /** Offset a polyline * @param {Array} coords * @param {number} offset * @return {Array} resulting coord * @see http://stackoverflow.com/a/11970006/796832 * @see https://drive.google.com/viewerng/viewer?a=v&pid=sites&srcid=ZGVmYXVsdGRvbWFpbnxqa2dhZGdldHN0b3JlfGd4OjQ4MzI5M2Y0MjNmNzI2MjY */ var ol_coordinate_offsetCoords = function (coords, offset) { var path = []; var N = coords.length-1; var max = N; var mi, mi1, li, li1, ri, ri1, si, si1, Xi1, Yi1; var p0, p1, p2; var isClosed = ol_coordinate_equal(coords[0],coords[N]); if (!isClosed) { p0 = coords[0]; p1 = coords[1]; p2 = [ p0[0] + (p1[1] - p0[1]) / ol_coordinate_dist2d(p0,p1) *offset, p0[1] - (p1[0] - p0[0]) / ol_coordinate_dist2d(p0,p1) *offset ]; path.push(p2); coords.push(coords[N]) N++; max--; } for (var i = 0; i < max; i++) { p0 = coords[i]; p1 = coords[(i+1) % N]; p2 = coords[(i+2) % N]; mi = (p1[1] - p0[1])/(p1[0] - p0[0]); mi1 = (p2[1] - p1[1])/(p2[0] - p1[0]); // Prevent alignements if (Math.abs(mi-mi1) > 1e-10) { li = Math.sqrt((p1[0] - p0[0])*(p1[0] - p0[0])+(p1[1] - p0[1])*(p1[1] - p0[1])); li1 = Math.sqrt((p2[0] - p1[0])*(p2[0] - p1[0])+(p2[1] - p1[1])*(p2[1] - p1[1])); ri = p0[0] + offset*(p1[1] - p0[1])/li; ri1 = p1[0] + offset*(p2[1] - p1[1])/li1; si = p0[1] - offset*(p1[0] - p0[0])/li; si1 = p1[1] - offset*(p2[0] - p1[0])/li1; Xi1 = (mi1*ri1-mi*ri+si-si1) / (mi1-mi); Yi1 = (mi*mi1*(ri1-ri)+mi1*si-mi*si1) / (mi1-mi); // Correction for vertical lines if(p1[0] - p0[0] == 0) { Xi1 = p1[0] + offset*(p1[1] - p0[1])/Math.abs(p1[1] - p0[1]); Yi1 = mi1*Xi1 - mi1*ri1 + si1; } if (p2[0] - p1[0] == 0 ) { Xi1 = p2[0] + offset*(p2[1] - p1[1])/Math.abs(p2[1] - p1[1]); Yi1 = mi*Xi1 - mi*ri + si; } path.push([Xi1, Yi1]); } } if (isClosed) { path.push(path[0]); } else { coords.pop(); p0 = coords[coords.length-1]; p1 = coords[coords.length-2]; p2 = [ p0[0] - (p1[1] - p0[1]) / ol_coordinate_dist2d(p0,p1) *offset, p0[1] + (p1[0] - p0[0]) / ol_coordinate_dist2d(p0,p1) *offset ]; path.push(p2); } return path; } /** Find the segment a point belongs to * @param {ol.Coordinate} pt * @param {Array} coords * @return {} the index (-1 if not found) and the segment */ var ol_coordinate_findSegment = function (pt, coords) { for (var i=0; i} geom * @param {number} y the y to split * @param {number} n contour index * @return {Array>} */ var ol_coordinate_splitH = function (geom, y, n) { var x, abs; var list = []; for (var i=0; iy || geom[i][1]>=y && geom[i+1][1]} d1 * @param {Arrar} d2 */ var ol_coordinate_getIntersectionPoint = function (d1, d2) { var d1x = d1[1][0] - d1[0][0]; var d1y = d1[1][1] - d1[0][1]; var d2x = d2[1][0] - d2[0][0]; var d2y = d2[1][1] - d2[0][1]; var det = d1x * d2y - d1y * d2x; if (det != 0) { var k = (d1x * d1[0][1] - d1x * d2[0][1] - d1y * d1[0][0] + d1y * d2[0][0]) / det; return [d2[0][0] + k*d2x, d2[0][1] + k*d2y]; } else { return false; } }; export { ol_coordinate_getIntersectionPoint } var ol_extent_intersection; (function() { // Split at x function splitX(pts, x) { var pt; for (let i=pts.length-1; i>0; i--) { if ((pts[i][0]>x && pts[i-1][0]x)) { pt = [ x, (x - pts[i][0]) / (pts[i-1][0]-pts[i][0]) * (pts[i-1][1]-pts[i][1]) + pts[i][1]]; pts.splice(i, 0, pt); } } } // Split at y function splitY(pts, y) { var pt; for (let i=pts.length-1; i>0; i--) { if ((pts[i][1]>y && pts[i-1][1]y)) { pt = [ (y - pts[i][1]) / (pts[i-1][1]-pts[i][1]) * (pts[i-1][0]-pts[i][0]) + pts[i][0], y]; pts.splice(i, 0, pt); } } } /** Fast polygon intersection with an extent (used for area calculation) * @param {ol_extent_Extent} extent * @param {ol_geom_Polygon|ol_geom_MultiPolygon} polygon * @returns {ol_geom_Polygon|ol_geom_MultiPolygon|null} return null if not a polygon geometry */ ol_extent_intersection = function(extent, polygon) { var poly = (polygon.getType() === 'Polygon'); if (!poly && polygon.getType() !== 'MultiPolygon') return null; var geom = polygon.getCoordinates(); if (poly) geom = [geom]; geom.forEach(function(g) { g.forEach(function(c) { splitX(c, extent[0]); splitX(c, extent[2]); splitY(c, extent[1]); splitY(c, extent[3]); }); }) // Snap geom to the extent geom.forEach(function(g) { g.forEach(function(c) { c.forEach(function(p) { if (p[0]extent[2]) p[0] = extent[2]; if (p[1]extent[3]) p[1] = extent[3]; }) }) }) if (poly) { return new ol_geom_Polygon(geom[0]); } else { return new ol_geom_MultiPolygon(geom); } }; })(); export { ol_extent_intersection } export { ol_extent_intersection as extentIntersection } /** Add points along a segment * @param {ol_Coordinate} p1 * @param {ol_Coordinate} p2 * @param {number} d * @param {boolean} start include starting point, default true * @returns {Array} */ var ol_coordinate_sampleAt = function(p1, p2, d, start) { var pts = []; if (start!==false) pts.push(p1); var dl = ol_coordinate_dist2d(p1,p2); if (dl) { var nb = Math.round(dl/d); if (nb>1) { var dx = (p2[0]-p1[0]) / nb; var dy = (p2[1]-p1[1]) / nb; for (var i=1; i r) { hasout = true; l.push([ c[0] + r / d * (p[0]-c[0]), c[1] + r / d * (p[1]-c[1]) ]); } else { // hasin = true; l.push(p); } }); }) }); if (!hasout) return geom; if (geom.getType() === 'Polygon') { return new ol_geom_Polygon(result[0]); } else { return new ol_geom_MultiPolygon(result); } } } } else { console.warn('[ol/geom/Circle~intersection] Unsupported geometry type: '+geom.getType()); } return geom; };