diff --git a/packages/turf-line-offset/LICENSE b/packages/turf-line-offset/LICENSE new file mode 100644 index 0000000000..96ce51b76f --- /dev/null +++ b/packages/turf-line-offset/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2017 TurfJS + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/turf-line-offset/README.md b/packages/turf-line-offset/README.md new file mode 100644 index 0000000000..23633785a7 --- /dev/null +++ b/packages/turf-line-offset/README.md @@ -0,0 +1,56 @@ +# @turf/line-offset + +# lineOffset + +Takes a [line](http://geojson.org/geojson-spec.html#linestring) and returns a [line](http://geojson.org/geojson-spec.html#linestring) at offset by the specified distance. + +**Parameters** + +- `line` **([Geometry](http://geojson.org/geojson-spec.html#geometry) \| [Feature](http://geojson.org/geojson-spec.html#feature-objects)<[LineString](http://geojson.org/geojson-spec.html#linestring)>)** input line +- `offset` **[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** distance to offset the line (can be of negative value) +- `units` **\[[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** can be degrees, radians, miles, kilometers, inches, yards, meters (optional, default `kilometers`) + +**Examples** + +```javascript +var line = { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [[-83, 30], [-84, 36], [-78, 41]] + } +}; + +var offsetLine = turf.lineOffset(line, 2, 'miles'); + +//addToMap +var addToMap = [offsetLine, line] +``` + +Returns **[Feature](http://geojson.org/geojson-spec.html#feature-objects)<[LineString](http://geojson.org/geojson-spec.html#linestring)>** Line offset from the input line + + + +--- + +This module is part of the [Turfjs project](http://turfjs.org/), an open source +module collection dedicated to geographic algorithms. It is maintained in the +[Turfjs/turf](https://github.com/Turfjs/turf) repository, where you can create +PRs and issues. + +### Installation + +Install this module individually: + +```sh +$ npm install @turf/line-offset +``` + +Or install the Turf module that includes it as a function: + +```sh +$ npm install @turf/turf +``` diff --git a/packages/turf-line-offset/bench.js b/packages/turf-line-offset/bench.js new file mode 100644 index 0000000000..00dce3c4dc --- /dev/null +++ b/packages/turf-line-offset/bench.js @@ -0,0 +1,33 @@ +const fs = require('fs'); +const path = require('path'); +const load = require('load-json-file'); +const Benchmark = require('benchmark'); +const lineOffset = require('./'); + +const directory = path.join(__dirname, 'test', 'in') + path.sep; +let fixtures = fs.readdirSync(directory).map(filename => { + return { + filename, + name: path.parse(filename).name, + geojson: load.sync(directory + filename) + }; +}); +// fixtures = fixtures.filter(fixture => fixture.name === 'polygon'); + +/** + * Benchmark Results + * + * line-horizontal x 1,816,451 ops/sec ±15.31% (62 runs sampled) + * linestring-long x 144,640 ops/sec ±3.35% (82 runs sampled) + * linestring-singleSegmentOnly x 2,649,959 ops/sec ±1.54% (76 runs sampled) + * linestring-straight x 1,857,452 ops/sec ±5.83% (77 runs sampled) + */ +const suite = new Benchmark.Suite('turf-line-offset'); +for (const {name, geojson} of fixtures) { + suite.add(name, () => lineOffset(geojson, 100, 'meters')); +} + +suite + .on('cycle', e => console.log(String(e.target))) + .on('complete', () => {}) + .run(); diff --git a/packages/turf-line-offset/index.d.ts b/packages/turf-line-offset/index.d.ts new file mode 100644 index 0000000000..9fd6b7a973 --- /dev/null +++ b/packages/turf-line-offset/index.d.ts @@ -0,0 +1,14 @@ +/// + +import {Units} from '@turf/helpers'; + +type GeometryObject = GeoJSON.GeometryObject; +type Feature = GeoJSON.Feature; +type Geoms = GeoJSON.LineString | GeoJSON.MultiLineString; + +/** + * http://turfjs.org/docs/#lineoffset + */ +declare function lineOffset(line: Feature | Geom, distance: number, units?: Units): Feature; +declare namespace lineOffset { } +export = lineOffset; diff --git a/packages/turf-line-offset/index.js b/packages/turf-line-offset/index.js new file mode 100644 index 0000000000..a11ac08b45 --- /dev/null +++ b/packages/turf-line-offset/index.js @@ -0,0 +1,118 @@ +var meta = require('@turf/meta'); +var helpers = require('@turf/helpers'); +var getCoords = require('@turf/invariant').getCoords; +var intersection = require('./intersection'); +var flattenEach = meta.flattenEach; +var lineString = helpers.lineString; +var multiLineString = helpers.multiLineString; +var distanceToDegrees = helpers.distanceToDegrees; + +/** + * Takes a {@link LineString|line} and returns a {@link LineString|line} at offset by the specified distance. + * + * @name lineOffset + * @param {Geometry|Feature} geojson input GeoJSON + * @param {number} distance distance to offset the line (can be of negative value) + * @param {string} [units=kilometers] can be degrees, radians, miles, kilometers, inches, yards, meters + * @returns {Feature} Line offset from the input line + * @example + * var line = { + * "type": "Feature", + * "properties": { + * "stroke": "#F00" + * }, + * "geometry": { + * "type": "LineString", + * "coordinates": [[-83, 30], [-84, 36], [-78, 41]] + * } + * }; + * + * var offsetLine = turf.lineOffset(line, 2, "miles"); + * + * //addToMap + * offsetLine.properties.stroke = "#00F" + * var addToMap = [offsetLine, line] + */ +module.exports = function (geojson, distance, units) { + if (!geojson) throw new Error('geojson is required'); + if (distance === undefined || distance === null || isNaN(distance)) throw new Error('distance is required'); + var type = (geojson.type === 'Feature') ? geojson.geometry.type : geojson.type; + var properties = geojson.properties; + + switch (type) { + case 'LineString': + return lineOffset(geojson, distance, units); + case 'MultiLineString': + var coords = []; + flattenEach(geojson, function (feature) { + coords.push(lineOffset(feature, distance, units).geometry.coordinates); + }); + return multiLineString(coords, properties); + default: + throw new Error('geometry ' + type + ' is not supported'); + } +}; + +/** + * Line Offset + * + * @private + * @param {Geometry|Feature} line input line + * @param {number} distance distance to offset the line (can be of negative value) + * @param {string} [units=kilometers] units + * @returns {Feature} Line offset from the input line + */ +function lineOffset(line, distance, units) { + var segments = []; + var offsetDegrees = distanceToDegrees(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]); + if (index === coords.length - 2) { + finalCoords.push(segment[0]); + finalCoords.push(segment[1]); + } + } + // Handling for lines that only have 1 segment + if (coords.length === 2) { + finalCoords.push(segment[0]); + finalCoords.push(segment[1]); + } + } + }); + return lineString(finalCoords, line.properties); +} + +/** + * Process Segment + * Inspiration taken from http://stackoverflow.com/questions/2825412/draw-a-parallel-line + * + * @private + * @param {Array} point1 Point coordinates + * @param {Array} point2 Point coordinates + * @param {number} offset Offset + * @returns {Array>} offset points + */ +function processSegment(point1, point2, offset) { + var L = Math.sqrt((point1[0] - point2[0]) * (point1[0] - point2[0]) + (point1[1] - point2[1]) * (point1[1] - point2[1])); + + var out1x = point1[0] + offset * (point2[1] - point1[1]) / L; + var out2x = point2[0] + offset * (point2[1] - point1[1]) / L; + var out1y = point1[1] + offset * (point1[0] - point2[0]) / L; + var out2y = point2[1] + offset * (point1[0] - point2[0]) / L; + return [[out1x, out1y], [out2x, out2y]]; +} diff --git a/packages/turf-line-offset/intersection.js b/packages/turf-line-offset/intersection.js new file mode 100644 index 0000000000..c84e4a89a0 --- /dev/null +++ b/packages/turf-line-offset/intersection.js @@ -0,0 +1,117 @@ +/** + * https://github.com/rook2pawn/node-intersection + * + * Author @rook2pawn + */ + +/** + * AB + * + * @private + * @param {Array>} segment - 2 vertex line segment + * @returns {Array} coordinates [x, y] + */ +function ab(segment) { + var start = segment[0]; + var end = segment[1]; + return [end[0] - start[0], end[1] - start[1]]; +} + +/** + * Cross Product + * + * @private + * @param {Array} v1 coordinates [x, y] + * @param {Array} v2 coordinates [x, y] + * @returns {Array} Cross Product + */ +function crossProduct(v1, v2) { + return (v1[0] * v2[1]) - (v2[0] * v1[1]); +} + +/** + * Add + * + * @private + * @param {Array} v1 coordinates [x, y] + * @param {Array} v2 coordinates [x, y] + * @returns {Array} Add + */ +function add(v1, v2) { + return [v1[0] + v2[0], v1[1] + v2[1]]; +} + +/** + * Sub + * + * @private + * @param {Array} v1 coordinates [x, y] + * @param {Array} v2 coordinates [x, y] + * @returns {Array} Sub + */ +function sub(v1, v2) { + return [v1[0] - v2[0], v1[1] - v2[1]]; +} + +/** + * scalarMult + * + * @private + * @param {number} s scalar + * @param {Array} v coordinates [x, y] + * @returns {Array} scalarMult + */ +function scalarMult(s, v) { + return [s * v[0], s * v[1]]; +} + +/** + * Intersect Segments + * + * @private + * @param {Array} a coordinates [x, y] + * @param {Array} b coordinates [x, y] + * @returns {Array} intersection + */ +function intersectSegments(a, b) { + var p = a[0]; + var r = ab(a); + var q = b[0]; + var s = ab(b); + + var cross = crossProduct(r, s); + var qmp = sub(q, p); + var numerator = crossProduct(qmp, s); + var t = numerator / cross; + var intersection = add(p, scalarMult(t, r)); + return intersection; +} + +/** + * Is Parallel + * + * @private + * @param {Array} a coordinates [x, y] + * @param {Array} b coordinates [x, y] + * @returns {boolean} true if a and b are parallel (or co-linear) + */ +function isParallel(a, b) { + var r = ab(a); + var s = ab(b); + return (crossProduct(r, s) === 0); +} + +/** + * Intersection + * + * @private + * @param {Array} a coordinates [x, y] + * @param {Array} b coordinates [x, y] + * @returns {Array|boolean} true if a and b are parallel (or co-linear) + */ +function intersection(a, b) { + if (isParallel(a, b)) return false; + return intersectSegments(a, b); +} + +module.exports = intersection; diff --git a/packages/turf-line-offset/package.json b/packages/turf-line-offset/package.json new file mode 100644 index 0000000000..6fbd2eddc2 --- /dev/null +++ b/packages/turf-line-offset/package.json @@ -0,0 +1,49 @@ +{ + "name": "@turf/line-offset", + "version": "4.0.0", + "description": "turf line-offset module", + "main": "index.js", + "types": "index.d.ts", + "files": [ + "index.js", + "index.d.ts", + "intersection.js" + ], + "scripts": { + "test": "node test.js", + "bench": "node bench.js" + }, + "repository": { + "type": "git", + "url": "git://github.com/Turfjs/turf.git" + }, + "keywords": [ + "line", + "linestring", + "turf", + "offset" + ], + "author": "Turf Authors", + "contributors": [ + "David Wee <@rook2pawn>", + "Rowan Winsemius <@rowanwins>", + "Denis Carriere <@DenisCarriere>" + ], + "license": "MIT", + "bugs": { + "url": "https://github.com/Turfjs/turf/issues" + }, + "homepage": "https://github.com/Turfjs/turf", + "devDependencies": { + "@turf/truncate": "^4.3.0", + "benchmark": "^2.1.4", + "load-json-file": "^2.0.0", + "tape": "^4.6.3", + "write-json-file": "^2.0.0" + }, + "dependencies": { + "@turf/helpers": "^4.3.0", + "@turf/invariant": "^4.3.0", + "@turf/meta": "^4.2.0" + } +} diff --git a/packages/turf-line-offset/test.js b/packages/turf-line-offset/test.js new file mode 100644 index 0000000000..96741c2c1c --- /dev/null +++ b/packages/turf-line-offset/test.js @@ -0,0 +1,58 @@ +const fs = require('fs'); +const test = require('tape'); +const path = require('path'); +const load = require('load-json-file'); +const write = require('write-json-file'); +const truncate = require('@turf/truncate'); +const {featureCollection, lineString} = require('@turf/helpers'); +const lineOffset = require('./'); + +const directories = { + in: path.join(__dirname, 'test', 'in') + path.sep, + out: path.join(__dirname, 'test', 'out') + path.sep +}; + +let fixtures = fs.readdirSync(directories.in).map(filename => { + return { + filename, + name: path.parse(filename).name, + geojson: load.sync(directories.in + filename) + }; +}); +// fixtures = fixtures.filter(fixture => fixture.name === 'polygon'); + +test('turf-line-offset', t => { + for (const {name, geojson} of fixtures) { + let {distance, units} = geojson.properties || {}; + distance = distance || 50; + const output = truncate(lineOffset(geojson, distance, units), 4); + output.properties.stroke = '#00F'; + const results = featureCollection([output, geojson]); + + if (process.env.REGEN) write.sync(directories.out + name + '.geojson', results); + t.deepEqual(results, load.sync(directories.out + name + '.geojson'), name); + } + t.end(); +}); + +test('turf-line-offset - Throws Errors', t => { + const line = lineString([[10, 10], [0, 0]]); + t.throws(() => lineOffset(), /geojson is required/); + t.throws(() => lineOffset(line, /offset is required/)); + t.end(); +}); + +test('turf-line-offset - Support Geometry Objects', t => { + const line = lineString([[10, 10], [0, 0]]); + t.ok(lineOffset(line.geometry, 10), 'Geometry Object'); + t.end(); +}); + +test('turf-line-offset - Prevent Input Mutation', t => { + const line = lineString([[10, 10], [0, 0]]); + const before = JSON.parse(JSON.stringify(line)); + lineOffset(line.geometry, 10); + + t.deepEqual(line, before, 'input does not mutate'); + t.end(); +}); diff --git a/packages/turf-line-offset/test/in/line-concave.geojson b/packages/turf-line-offset/test/in/line-concave.geojson new file mode 100644 index 0000000000..6de65e3ac3 --- /dev/null +++ b/packages/turf-line-offset/test/in/line-concave.geojson @@ -0,0 +1,38 @@ +{ + "type": "Feature", + "properties": { + "stroke-width": 5, + "stroke": "red", + "distance": 150, + "units": "miles" + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + 0.9667968749999999, + 21.69826549685252 + ], + [ + -2.5927734375, + 24.44714958973082 + ], + [ + 0.3955078125, + 29.726222319395504 + ], + [ + 7.207031249999999, + 29.916852233070173 + ], + [ + 11.337890625, + 23.079731762449878 + ], + [ + 3.2080078125, + 21.04349121680354 + ] + ] + } +} \ No newline at end of file diff --git a/packages/turf-line-offset/test/in/line-horizontal.geojson b/packages/turf-line-offset/test/in/line-horizontal.geojson new file mode 100644 index 0000000000..97ae5bef0b --- /dev/null +++ b/packages/turf-line-offset/test/in/line-horizontal.geojson @@ -0,0 +1,20 @@ + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + 10, + 0 + ], + [ + 20, + 0 + ] + ] + } + } \ No newline at end of file diff --git a/packages/turf-line-offset/test/in/linestring-long.geojson b/packages/turf-line-offset/test/in/linestring-long.geojson new file mode 100644 index 0000000000..e9f886e7cb --- /dev/null +++ b/packages/turf-line-offset/test/in/linestring-long.geojson @@ -0,0 +1,172 @@ +{ + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -24.2578125, + 41.244772343082076 + ], + [ + -6.328125, + 45.336701909968134 + ], + [ + 0.703125, + 49.83798245308484 + ], + [ + 2.8125, + 44.33956524809713 + ], + [ + -6.328125, + 39.095962936305476 + ], + [ + -5.44921875, + 36.4566360115962 + ], + [ + -0.17578125, + 37.3002752813443 + ], + [ + 1.58203125, + 39.36827914916014 + ], + [ + 3.33984375, + 40.58058466412761 + ], + [ + 6.15234375, + 41.244772343082076 + ], + [ + 7.3828125, + 39.50404070558415 + ], + [ + 4.5703125, + 37.020098201368114 + ], + [ + 3.69140625, + 35.31736632923788 + ], + [ + 4.921875, + 31.653381399664 + ], + [ + 8.61328125, + 32.54681317351514 + ], + [ + 10.72265625, + 34.016241889667015 + ], + [ + 10.546875, + 36.03133177633187 + ], + [ + 10.37109375, + 38.272688535980976 + ], + [ + 10.01953125, + 39.232253141714885 + ], + [ + 9.4921875, + 40.58058466412761 + ], + [ + 9.31640625, + 41.902277040963696 + ], + [ + 11.42578125, + 44.08758502824516 + ], + [ + 13.53515625, + 43.96119063892024 + ], + [ + 14.765625, + 42.8115217450979 + ], + [ + 15.8203125, + 37.71859032558816 + ], + [ + 15.644531250000002, + 36.1733569352216 + ], + [ + 14.94140625, + 34.59704151614417 + ], + [ + 13.359375, + 31.952162238024975 + ], + [ + 11.77734375, + 22.755920681486405 + ], + [ + 15.8203125, + 29.22889003019423 + ], + [ + 16.875, + 31.50362930577303 + ], + [ + 17.2265625, + 33.43144133557529 + ], + [ + 17.402343749999996, + 35.02999636902566 + ], + [ + 19.51171875, + 41.244772343082076 + ], + [ + 21.4453125, + 41.11246878918088 + ], + [ + 20.7421875, + 38.8225909761771 + ], + [ + 21.09375, + 36.1733569352216 + ], + [ + 21.26953125, + 34.016241889667015 + ], + [ + 21.26953125, + 31.353636941500987 + ], + [ + 26.015625, + 33.284619968887675 + ] + ] + } +} \ No newline at end of file diff --git a/packages/turf-line-offset/test/in/linestring-same-start-end.geojson b/packages/turf-line-offset/test/in/linestring-same-start-end.geojson new file mode 100644 index 0000000000..f7b5f7b1af --- /dev/null +++ b/packages/turf-line-offset/test/in/linestring-same-start-end.geojson @@ -0,0 +1,36 @@ +{ + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + 122.431640625, + -19.559790136497398 + ], + [ + 122.51953124999999, + -26.902476886279807 + ], + [ + 134.82421875, + -27.215556209029675 + ], + [ + 139.306640625, + -22.998851594142913 + ], + [ + 133.9453125, + -14.434680215297268 + ], + [ + 122.431640625, + -19.559790136497398 + ] + ] + } +} \ No newline at end of file diff --git a/packages/turf-line-offset/test/in/linestring-single-segment-only.geojson b/packages/turf-line-offset/test/in/linestring-single-segment-only.geojson new file mode 100644 index 0000000000..66f8cf2d08 --- /dev/null +++ b/packages/turf-line-offset/test/in/linestring-single-segment-only.geojson @@ -0,0 +1,20 @@ +{ + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + 1, + 1 + ], + [ + 1, + 10 + ] + ] + } +} diff --git a/packages/turf-line-offset/test/in/linestring-straight.geojson b/packages/turf-line-offset/test/in/linestring-straight.geojson new file mode 100644 index 0000000000..03a9c2f33f --- /dev/null +++ b/packages/turf-line-offset/test/in/linestring-straight.geojson @@ -0,0 +1,24 @@ +{ + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + 1, + -10 + ], + [ + 1, + 1 + ], + [ + 1, + 10 + ] + ] + } +} diff --git a/packages/turf-line-offset/test/in/multi-linestring.geojson b/packages/turf-line-offset/test/in/multi-linestring.geojson new file mode 100644 index 0000000000..dc64a6014f --- /dev/null +++ b/packages/turf-line-offset/test/in/multi-linestring.geojson @@ -0,0 +1,14 @@ +{ + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [[10, 10], [2, 2], [0, 0]], + [[25, 5], [20, 10], [15, 5]] + ] + } +} diff --git a/packages/turf-line-offset/test/in/northern-line.geojson b/packages/turf-line-offset/test/in/northern-line.geojson new file mode 100644 index 0000000000..ecb97bfaa1 --- /dev/null +++ b/packages/turf-line-offset/test/in/northern-line.geojson @@ -0,0 +1,60 @@ +{ + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -93.66943359374999, + 75.2782047773442 + ], + [ + -94.15283203125, + 75.52189820596192 + ], + [ + -94.68017578125, + 75.60133818586581 + ], + [ + -95.64697265625, + 75.55208098028335 + ], + [ + -95.8447265625, + 75.37837872661018 + ], + [ + -96.339111328125, + 75.10975495781904 + ], + [ + -96.251220703125, + 74.89940428652537 + ], + [ + -95.20751953125, + 74.73829331009176 + ], + [ + -94.50439453125, + 74.63965846462719 + ], + [ + -93.878173828125, + 74.65129477919845 + ], + [ + -93.526611328125, + 74.73250841433554 + ], + [ + -93.50463867187499, + 75.09845822124332 + ] + ] + } +} \ No newline at end of file diff --git a/packages/turf-line-offset/test/out/line-concave.geojson b/packages/turf-line-offset/test/out/line-concave.geojson new file mode 100644 index 0000000000..8885f2bdb2 --- /dev/null +++ b/packages/turf-line-offset/test/out/line-concave.geojson @@ -0,0 +1,81 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke-width": 5, + "stroke": "#00F", + "distance": 150, + "units": "miles" + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + 2.2933, + 23.416 + ], + [ + 0.2226, + 25.0151 + ], + [ + 1.6807, + 27.591 + ], + [ + 6.0035, + 27.712 + ], + [ + 7.9614, + 24.4714 + ], + [ + 2.6807, + 23.1488 + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke-width": 5, + "stroke": "red", + "distance": 150, + "units": "miles" + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + 0.9667968749999999, + 21.69826549685252 + ], + [ + -2.5927734375, + 24.44714958973082 + ], + [ + 0.3955078125, + 29.726222319395504 + ], + [ + 7.207031249999999, + 29.916852233070173 + ], + [ + 11.337890625, + 23.079731762449878 + ], + [ + 3.2080078125, + 21.04349121680354 + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/packages/turf-line-offset/test/out/line-horizontal.geojson b/packages/turf-line-offset/test/out/line-horizontal.geojson new file mode 100644 index 0000000000..e9696f37d8 --- /dev/null +++ b/packages/turf-line-offset/test/out/line-horizontal.geojson @@ -0,0 +1,45 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + 10, + -0.4495 + ], + [ + 20, + -0.4495 + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + 10, + 0 + ], + [ + 20, + 0 + ] + ] + } + } + ] +} diff --git a/packages/turf-line-offset/test/out/linestring-long.geojson b/packages/turf-line-offset/test/out/linestring-long.geojson new file mode 100644 index 0000000000..7febfe18a8 --- /dev/null +++ b/packages/turf-line-offset/test/out/linestring-long.geojson @@ -0,0 +1,349 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -24.1578, + 40.8065 + ], + [ + -6.1517, + 44.9159 + ], + [ + 0.481, + 49.162 + ], + [ + 2.2549, + 44.5379 + ], + [ + -6.8708, + 39.3029 + ], + [ + -5.7551, + 35.9525 + ], + [ + 0.0592, + 36.8826 + ], + [ + 1.8861, + 39.0319 + ], + [ + 3.5254, + 40.1625 + ], + [ + 5.9604, + 40.7376 + ], + [ + 6.7829, + 39.574 + ], + [ + 4.2095, + 37.3012 + ], + [ + 3.2047, + 35.3545 + ], + [ + 4.627, + 31.1195 + ], + [ + 8.801, + 32.1298 + ], + [ + 11.1931, + 33.7961 + ], + [ + 10.9949, + 36.0684 + ], + [ + 10.8144, + 38.3694 + ], + [ + 10.4399, + 39.3915 + ], + [ + 9.9306, + 40.6937 + ], + [ + 9.7906, + 41.7463 + ], + [ + 11.6055, + 43.6265 + ], + [ + 13.3466, + 43.5222 + ], + [ + 14.3544, + 42.5805 + ], + [ + 15.3655, + 37.6979 + ], + [ + 15.2057, + 36.2931 + ], + [ + 14.5418, + 34.8047 + ], + [ + 12.9306, + 32.111 + ], + [ + 10.9464, + 20.5769 + ], + [ + 16.2164, + 29.0145 + ], + [ + 17.3069, + 31.3666 + ], + [ + 17.6716, + 33.3665 + ], + [ + 17.8438, + 34.932 + ], + [ + 19.8262, + 40.7727 + ], + [ + 20.8493, + 40.7027 + ], + [ + 20.2837, + 38.8607 + ], + [ + 20.6466, + 36.1255 + ], + [ + 20.82, + 33.998 + ], + [ + 20.82, + 30.6854 + ], + [ + 26.185, + 32.8682 + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -24.2578125, + 41.244772343082076 + ], + [ + -6.328125, + 45.336701909968134 + ], + [ + 0.703125, + 49.83798245308484 + ], + [ + 2.8125, + 44.33956524809713 + ], + [ + -6.328125, + 39.095962936305476 + ], + [ + -5.44921875, + 36.4566360115962 + ], + [ + -0.17578125, + 37.3002752813443 + ], + [ + 1.58203125, + 39.36827914916014 + ], + [ + 3.33984375, + 40.58058466412761 + ], + [ + 6.15234375, + 41.244772343082076 + ], + [ + 7.3828125, + 39.50404070558415 + ], + [ + 4.5703125, + 37.020098201368114 + ], + [ + 3.69140625, + 35.31736632923788 + ], + [ + 4.921875, + 31.653381399664 + ], + [ + 8.61328125, + 32.54681317351514 + ], + [ + 10.72265625, + 34.016241889667015 + ], + [ + 10.546875, + 36.03133177633187 + ], + [ + 10.37109375, + 38.272688535980976 + ], + [ + 10.01953125, + 39.232253141714885 + ], + [ + 9.4921875, + 40.58058466412761 + ], + [ + 9.31640625, + 41.902277040963696 + ], + [ + 11.42578125, + 44.08758502824516 + ], + [ + 13.53515625, + 43.96119063892024 + ], + [ + 14.765625, + 42.8115217450979 + ], + [ + 15.8203125, + 37.71859032558816 + ], + [ + 15.644531250000002, + 36.1733569352216 + ], + [ + 14.94140625, + 34.59704151614417 + ], + [ + 13.359375, + 31.952162238024975 + ], + [ + 11.77734375, + 22.755920681486405 + ], + [ + 15.8203125, + 29.22889003019423 + ], + [ + 16.875, + 31.50362930577303 + ], + [ + 17.2265625, + 33.43144133557529 + ], + [ + 17.402343749999996, + 35.02999636902566 + ], + [ + 19.51171875, + 41.244772343082076 + ], + [ + 21.4453125, + 41.11246878918088 + ], + [ + 20.7421875, + 38.8225909761771 + ], + [ + 21.09375, + 36.1733569352216 + ], + [ + 21.26953125, + 34.016241889667015 + ], + [ + 21.26953125, + 31.353636941500987 + ], + [ + 26.015625, + 33.284619968887675 + ] + ] + } + } + ] +} diff --git a/packages/turf-line-offset/test/out/linestring-same-start-end.geojson b/packages/turf-line-offset/test/out/linestring-same-start-end.geojson new file mode 100644 index 0000000000..9d60ae863c --- /dev/null +++ b/packages/turf-line-offset/test/out/linestring-same-start-end.geojson @@ -0,0 +1,77 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + 121.9822, + -19.5652 + ], + [ + 122.0752, + -27.3408 + ], + [ + 134.9976, + -27.6696 + ], + [ + 139.8836, + -23.0733 + ], + [ + 134.1192, + -13.8652 + ], + [ + 122.2488, + -19.1491 + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + 122.431640625, + -19.559790136497398 + ], + [ + 122.51953124999999, + -26.902476886279807 + ], + [ + 134.82421875, + -27.215556209029675 + ], + [ + 139.306640625, + -22.998851594142913 + ], + [ + 133.9453125, + -14.434680215297268 + ], + [ + 122.431640625, + -19.559790136497398 + ] + ] + } + } + ] +} diff --git a/packages/turf-line-offset/test/out/linestring-single-segment-only.geojson b/packages/turf-line-offset/test/out/linestring-single-segment-only.geojson new file mode 100644 index 0000000000..5d2d9553ec --- /dev/null +++ b/packages/turf-line-offset/test/out/linestring-single-segment-only.geojson @@ -0,0 +1,45 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + 1.4495, + 1 + ], + [ + 1.4495, + 10 + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + 1, + 1 + ], + [ + 1, + 10 + ] + ] + } + } + ] +} diff --git a/packages/turf-line-offset/test/out/linestring-straight.geojson b/packages/turf-line-offset/test/out/linestring-straight.geojson new file mode 100644 index 0000000000..825e7a7d5e --- /dev/null +++ b/packages/turf-line-offset/test/out/linestring-straight.geojson @@ -0,0 +1,53 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + 1.4495, + -10 + ], + [ + 1.4495, + 1 + ], + [ + 1.4495, + 10 + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + 1, + -10 + ], + [ + 1, + 1 + ], + [ + 1, + 10 + ] + ] + } + } + ] +} diff --git a/packages/turf-line-offset/test/out/multi-linestring.geojson b/packages/turf-line-offset/test/out/multi-linestring.geojson new file mode 100644 index 0000000000..cc7c5d6340 --- /dev/null +++ b/packages/turf-line-offset/test/out/multi-linestring.geojson @@ -0,0 +1,85 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 6 + }, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [ + 9.6821, + 10.3179 + ], + [ + 1.6821, + 2.3179 + ], + [ + -0.3179, + 0.3179 + ] + ], + [ + [ + 25.3179, + 5.3179 + ], + [ + 20, + 10.6357 + ], + [ + 14.6821, + 5.3179 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "MultiLineString", + "coordinates": [ + [ + [ + 10, + 10 + ], + [ + 2, + 2 + ], + [ + 0, + 0 + ] + ], + [ + [ + 25, + 5 + ], + [ + 20, + 10 + ], + [ + 15, + 5 + ] + ] + ] + } + } + ] +} diff --git a/packages/turf-line-offset/test/out/northern-line.geojson b/packages/turf-line-offset/test/out/northern-line.geojson new file mode 100644 index 0000000000..bbc616bbdb --- /dev/null +++ b/packages/turf-line-offset/test/out/northern-line.geojson @@ -0,0 +1,125 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#00F", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -93.4671, + 75.6796 + ], + [ + -94.0147, + 75.9557 + ], + [ + -94.6579, + 76.0526 + ], + [ + -95.8261, + 75.9931 + ], + [ + -96.1036, + 75.7493 + ], + [ + -96.9104, + 75.311 + ], + [ + -96.5688, + 74.4936 + ], + [ + -95.273, + 74.2936 + ], + [ + -94.5316, + 74.1896 + ], + [ + -93.8228, + 74.2027 + ], + [ + -93.098, + 74.3702 + ], + [ + -93.0559, + 75.0715 + ] + ] + } + }, + { + "type": "Feature", + "properties": { + "stroke": "#F00", + "stroke-width": 6 + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -93.66943359374999, + 75.2782047773442 + ], + [ + -94.15283203125, + 75.52189820596192 + ], + [ + -94.68017578125, + 75.60133818586581 + ], + [ + -95.64697265625, + 75.55208098028335 + ], + [ + -95.8447265625, + 75.37837872661018 + ], + [ + -96.339111328125, + 75.10975495781904 + ], + [ + -96.251220703125, + 74.89940428652537 + ], + [ + -95.20751953125, + 74.73829331009176 + ], + [ + -94.50439453125, + 74.63965846462719 + ], + [ + -93.878173828125, + 74.65129477919845 + ], + [ + -93.526611328125, + 74.73250841433554 + ], + [ + -93.50463867187499, + 75.09845822124332 + ] + ] + } + } + ] +} diff --git a/packages/turf-line-offset/test/types.ts b/packages/turf-line-offset/test/types.ts new file mode 100644 index 0000000000..358953f71c --- /dev/null +++ b/packages/turf-line-offset/test/types.ts @@ -0,0 +1,11 @@ +import * as lineOffset from '../' +import {lineString, multiLineString} from '@turf/helpers' + +const line = lineString([[0, 0], [10, 10]]) +const multiLine = multiLineString([[[0, 0], [10, 10]], [[5, 5], [15, 15]]]) + +lineOffset(line, 50) +lineOffset(line.geometry, 50) +lineOffset(multiLine, 50) +lineOffset(multiLine.geometry, 50) +lineOffset(line, 50, 'miles')