Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
function lineSplit(line, splitter) {
if (!line) throw new Error('line is required');
if (!splitter) throw new Error('splitter is required');
var lineType = getType(line);
var splitterType = getType(splitter);
if (lineType !== 'LineString') throw new Error('line must be LineString');
if (splitterType === 'FeatureCollection') throw new Error('splitter cannot be a FeatureCollection');
if (splitterType === 'GeometryCollection') throw new Error('splitter cannot be a GeometryCollection');
// remove excessive decimals from splitter
// to avoid possible approximation issues in rbush
var truncatedSplitter = truncate(splitter, {precision: 7});
switch (splitterType) {
case 'Point':
return splitLineWithPoint(line, truncatedSplitter);
case 'MultiPoint':
return splitLineWithPoints(line, truncatedSplitter);
case 'LineString':
function rhumbDistance(from: Coord, to: Coord, options: {
units?: Units,
} = {}): number {
const origin = getCoord(from);
const destination = getCoord(to);
// compensate the crossing of the 180th meridian (https://macwright.org/2016/09/26/the-180th-meridian.html)
// solution from https://github.com/mapbox/mapbox-gl-js/issues/3250#issuecomment-294887678
destination[0] += (destination[0] - origin[0] > 180) ? -360 : (origin[0] - destination[0] > 180) ? 360 : 0;
const distanceInMeters = calculateRhumbDistance(origin, destination);
const distance = convertLength(distanceInMeters, "meters", options.units);
return distance;
}
options = options || {};
var steps = options.steps || 64;
var units = options.units || 'kilometers';
var angle = options.angle || 0;
var pivot = options.pivot || center;
var properties = options.properties || center.properties || {};
// validation
if (!center) throw new Error('center is required');
if (!xSemiAxis) throw new Error('xSemiAxis is required');
if (!ySemiAxis) throw new Error('ySemiAxis is required');
if (!isObject(options)) throw new Error('options must be an object');
if (!isNumber(steps)) throw new Error('steps must be a number');
if (!isNumber(angle)) throw new Error('angle must be a number');
var centerCoords = getCoord(center);
if (units === 'degrees') {
var angleRad = degreesToRadians(angle);
} else {
xSemiAxis = rhumbDestination(center, xSemiAxis, 90, {units: units});
ySemiAxis = rhumbDestination(center, ySemiAxis, 0, {units: units});
xSemiAxis = getCoord(xSemiAxis)[0] - centerCoords[0];
ySemiAxis = getCoord(ySemiAxis)[1] - centerCoords[1];
}
var coordinates = [];
for (var i = 0; i < steps; i += 1) {
var stepAngle = i * -360 / steps;
var x = ((xSemiAxis * ySemiAxis) / Math.sqrt(Math.pow(ySemiAxis, 2) + (Math.pow(xSemiAxis, 2) * Math.pow(getTanDeg(stepAngle), 2))));
var y = ((xSemiAxis * ySemiAxis) / Math.sqrt(Math.pow(xSemiAxis, 2) + (Math.pow(ySemiAxis, 2) / Math.pow(getTanDeg(stepAngle), 2))));
if (stepAngle < -90 && stepAngle >= -270) x = -x;
// Support all GeoJSON Geometry Objects
switch (type) {
case 'GeometryCollection':
geomEach(geojson, function (geometry) {
rewind(geometry, reverse);
});
return geojson;
case 'LineString':
rewindLineString(getCoords(geojson), reverse);
return geojson;
case 'Polygon':
rewindPolygon(getCoords(geojson), reverse);
return geojson;
case 'MultiLineString':
getCoords(geojson).forEach(function (lineCoords) {
rewindLineString(lineCoords, reverse);
});
return geojson;
case 'MultiPolygon':
getCoords(geojson).forEach(function (lineCoords) {
rewindPolygon(lineCoords, reverse);
});
return geojson;
case 'Point':
case 'MultiPoint':
return geojson;
}
}
function rewind(geojson, reverse) {
var type = (geojson.type === 'Feature') ? geojson.geometry.type : geojson.type;
// Support all GeoJSON Geometry Objects
switch (type) {
case 'GeometryCollection':
geomEach(geojson, function (geometry) {
rewind(geometry, reverse);
});
return geojson;
case 'LineString':
rewindLineString(getCoords(geojson), reverse);
return geojson;
case 'Polygon':
rewindPolygon(getCoords(geojson), reverse);
return geojson;
case 'MultiLineString':
getCoords(geojson).forEach(function (lineCoords) {
rewindLineString(lineCoords, reverse);
});
return geojson;
case 'MultiPolygon':
getCoords(geojson).forEach(function (lineCoords) {
rewindPolygon(lineCoords, reverse);
});
return geojson;
case 'Point':
case 'MultiPoint':
return geojson;
}
}
featureEach(tree.search(segment), function (match) {
if (doesOverlaps === false) {
var coordsSegment = getCoords(segment).sort();
var coordsMatch: any = getCoords(match).sort();
// Segment overlaps feature
if (equal(coordsSegment, coordsMatch)) {
doesOverlaps = true;
// Overlaps already exists - only append last coordinate of segment
if (overlapSegment) overlapSegment = concatSegment(overlapSegment, segment);
else overlapSegment = segment;
// Match segments which don't share nodes (Issue #901)
} else if (
(tolerance === 0) ?
booleanPointOnLine(coordsSegment[0], match) && booleanPointOnLine(coordsSegment[1], match) :
nearestPointOnLine(match, coordsSegment[0]).properties.dist <= tolerance &&
nearestPointOnLine(match, coordsSegment[1]).properties.dist <= tolerance) {
doesOverlaps = true;
if (overlapSegment) overlapSegment = concatSegment(overlapSegment, segment);
var lastCoords = featureReduce(segments, function (previous, current, index) {
var currentCoords = getCoords(current)[1];
var splitterCoords = getCoords(splitter);
// Location where segment intersects with line
if (index === closestSegment.id) {
previous.push(splitterCoords);
results.push(lineString(previous));
// Don't duplicate splitter coordinate (Issue #688)
if (pointsEquals(splitterCoords, currentCoords)) return [splitterCoords];
return [splitterCoords, currentCoords];
// Keep iterating over coords until finished or intersection is found
} else {
previous.push(currentCoords);
return previous;
}
}, initialValue);
var lastCoords = featureReduce(segments, function (previous, current, index) {
var currentCoords = getCoords(current)[1];
var splitterCoords = getCoords(splitter);
// Location where segment intersects with line
if (index === closestSegment.id) {
previous.push(splitterCoords);
results.push(lineString(previous));
// Don't duplicate splitter coordinate (Issue #688)
if (pointsEquals(splitterCoords, currentCoords)) return [splitterCoords];
return [splitterCoords, currentCoords];
// Keep iterating over coords until finished or intersection is found
} else {
previous.push(currentCoords);
return previous;
}
}, initialValue);
// Append last line to final split results
function lineOffsetFeature(line, distance, units) {
var segments = [];
var offsetDegrees = lengthToDegrees(distance, units);
var coords = getCoords(line);
var finalCoords = [];
coords.forEach(function (currentCoords, index) {
if (index !== coords.length - 1) {
var segment = processSegment(currentCoords, coords[index + 1], offsetDegrees);
segments.push(segment);
if (index > 0) {
var seg2Coords = segments[index - 1];
var intersects = intersection(segment, seg2Coords);
// Handling for line segments that aren't straight
if (intersects !== false) {
seg2Coords[1] = intersects;
segment[0] = intersects;
}
finalCoords.push(seg2Coords[0]);
featureEach(tree.search(current), function (polySegment) {
if (!matched) {
// Segments match
var intersect = lineIntersect(current, polySegment).features[0];
if (intersect) {
// Create Segment
var newSegment = clone(previous);
if (index === 0) {
newSegment = lineString([getCoords(current)[0], getCoords(intersect)]);
} else {
newSegment.geometry.coordinates.push(getCoords(intersect));
}
// Push new split lines to results
if (validSegment(newSegment)) {
results.push(newSegment);
}
// Restart previous value to intersection point
previous.geometry.coordinates = [intersect.geometry.coordinates];
matched = true;
}
}
});
// Append last coordinate of current segment