Skip to content

Commit

Permalink
Merge branch 'master' into patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewharvey authored Aug 6, 2024
2 parents ba45657 + e231564 commit 645e844
Show file tree
Hide file tree
Showing 23 changed files with 34,987 additions and 9,051 deletions.
22 changes: 13 additions & 9 deletions .github/workflows/turf.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ name: CI build

on:
push:
branches: [master]
branches:
- master
- support/6.x
pull_request:
branches: [master]
branches:
- master
- support/6.x

permissions:
contents: read
Expand All @@ -21,17 +25,17 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}

- name: Install pnpm
uses: pnpm/action-setup@v2
uses: pnpm/action-setup@v4
with:
version: 8
run_install: false

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
cache: "pnpm"
node-version: ${{ matrix.node-version }}

- run: pnpm install --frozen-lockfile
- run: git diff --exit-code
- run: pnpm test
1 change: 1 addition & 0 deletions documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ toc:
- booleanWithin
- name: Unit Conversion
- bearingToAzimuth
- azimuthToBearing
- convertArea
- convertLength
- degreesToRadians
Expand Down
11 changes: 11 additions & 0 deletions packages/turf-helpers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,17 @@ and returns an angle between 0-360 degrees (positive clockwise), 0 being the nor

Returns **[number][1]** angle between 0 and 360 degrees

## azimuthToBearing

Converts any azimuth angle from the north line direction (positive clockwise)
and returns an angle between -180 and +180 degrees (positive clockwise), 0 being the north line

### Parameters

* `angle` **[number][1]** between 0 and 360 degrees

Returns **[number][1]** bearing between -180 and +180 degrees

## radiansToDegrees

Converts an angle in radians to degrees
Expand Down
14 changes: 14 additions & 0 deletions packages/turf-helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,20 @@ export function bearingToAzimuth(bearing: number): number {
return angle;
}

/**
* Converts any azimuth angle from the north line direction (positive clockwise)
* and returns an angle between -180 and +180 degrees (positive clockwise), 0 being the north line
*
* @name azimuthToBearing
* @param {number} angle between 0 and 360 degrees
* @returns {number} bearing between -180 and +180 degrees
*/
export function azimuthToBearing(angle: number): number {
angle = angle % 360;
if (angle > 0) return angle > 180 ? angle - 360 : angle;
return angle < -180 ? angle + 360 : angle;
}

/**
* Converts an angle in radians to degrees
*
Expand Down
21 changes: 21 additions & 0 deletions packages/turf-helpers/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
radiansToDegrees,
degreesToRadians,
bearingToAzimuth,
azimuthToBearing,
convertLength,
convertArea,
round,
Expand Down Expand Up @@ -540,6 +541,26 @@ test("bearingToAzimuth", (t) => {
t.end();
});

test("azimuthToBearing", (t) => {
t.equal(azimuthToBearing(0), 0);
t.equal(azimuthToBearing(360), 0);
t.equal(azimuthToBearing(180), 180);

t.equal(azimuthToBearing(40), 40);
t.equal(azimuthToBearing(40 + 360), 40);

t.equal(azimuthToBearing(-35), -35);
t.equal(azimuthToBearing(-35 - 360), -35);

t.equal(azimuthToBearing(255), -105);
t.equal(azimuthToBearing(255 + 360), -105);

t.equal(azimuthToBearing(-200), 160);
t.equal(azimuthToBearing(-200 - 360), 160);

t.end();
});

test("round", (t) => {
t.equal(round(125.123), 125);
t.equal(round(123.123, 1), 123.1);
Expand Down
2 changes: 1 addition & 1 deletion packages/turf-line-offset/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ test("turf-line-offset - Throws Errors", (t) => {
[0, 0],
]);
t.throws(() => lineOffset(), /geojson is required/);
t.throws(() => lineOffset(line, /offset is required/));
t.throws(() => lineOffset(line), /distance is required/);
t.end();
});

Expand Down
2 changes: 1 addition & 1 deletion packages/turf-nearest-point-on-line/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ var addToMap = [line, pt, snapped];
snapped.properties['marker-color'] = '#00f';
```

Returns **[Feature][4]<[Point][1]>** 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.
Returns **[Feature][4]<[Point][1]>** closest point on the `line` to `point`. The properties object will contain four values: `index`: closest point was found on nth line part, `multiFeatureIndex`: closest point was found on the nth line of the `MultiLineString`, `dist`: distance between pt and the closest point, `location`: distance along the line between start and the closest point.

[1]: https://tools.ietf.org/html/rfc7946#section-3.1.2

Expand Down
170 changes: 93 additions & 77 deletions packages/turf-nearest-point-on-line/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { getCoords } from "@turf/invariant";
* @param {Geometry|Feature<Point>|number[]} pt point to snap from
* @param {Object} [options={}] Optional parameters
* @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers
* @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.
* @returns {Feature<Point>} closest point on the `line` to `point`. The properties object will contain four values: `index`: closest point was found on nth line part, `multiFeatureIndex`: closest point was found on the nth line of the `MultiLineString`, `dist`: distance between pt and the closest point, `location`: distance along the line between start and the closest point.
* @example
* var line = turf.lineString([
* [-77.031669, 38.878605],
Expand All @@ -42,6 +42,7 @@ function nearestPointOnLine<G extends LineString | MultiLineString>(
{
dist: number;
index: number;
multiFeatureIndex: number;
location: number;
[key: string]: any;
}
Expand All @@ -52,96 +53,111 @@ function nearestPointOnLine<G extends LineString | MultiLineString>(

let closestPt: Feature<
Point,
{ dist: number; index: number; location: number }
{ dist: number; index: number; multiFeatureIndex: number; location: number }
> = point([Infinity, Infinity], {
dist: Infinity,
index: -1,
multiFeatureIndex: -1,
location: -1,
});

let length = 0.0;
flattenEach(lines, function (line: any) {
const coords: any = getCoords(line);
flattenEach(
lines,
function (line: any, _featureIndex: number, multiFeatureIndex: number) {
const coords: any = getCoords(line);

for (let i = 0; i < coords.length - 1; i++) {
//start
const start: Feature<Point, { dist: number }> = point(coords[i]);
start.properties.dist = distance(pt, start, options);
//stop
const stop: Feature<Point, { dist: number }> = point(coords[i + 1]);
stop.properties.dist = distance(pt, stop, options);
// sectionLength
const sectionLength = distance(start, stop, options);
//perpendicular
const heightDistance = Math.max(
start.properties.dist,
stop.properties.dist
);
const direction = bearing(start, stop);
const perpendicularPt1 = destination(
pt,
heightDistance,
direction + 90,
options
);
const perpendicularPt2 = destination(
pt,
heightDistance,
direction - 90,
options
);
const intersect = lineIntersects(
lineString([
perpendicularPt1.geometry.coordinates,
perpendicularPt2.geometry.coordinates,
]),
lineString([start.geometry.coordinates, stop.geometry.coordinates])
);
let intersectPt:
| Feature<Point, { dist: number; location: number }>
| undefined;
for (let i = 0; i < coords.length - 1; i++) {
//start
const start: Feature<Point, { dist: number }> = point(coords[i]);
start.properties.dist = distance(pt, start, options);
//stop
const stop: Feature<Point, { dist: number }> = point(coords[i + 1]);
stop.properties.dist = distance(pt, stop, options);
// sectionLength
const sectionLength = distance(start, stop, options);
//perpendicular
const heightDistance = Math.max(
start.properties.dist,
stop.properties.dist
);
const direction = bearing(start, stop);
const perpendicularPt1 = destination(
pt,
heightDistance,
direction + 90,
options
);
const perpendicularPt2 = destination(
pt,
heightDistance,
direction - 90,
options
);
const intersect = lineIntersects(
lineString([
perpendicularPt1.geometry.coordinates,
perpendicularPt2.geometry.coordinates,
]),
lineString([start.geometry.coordinates, stop.geometry.coordinates])
);
let intersectPt:
| Feature<
Point,
{ dist: number; multiFeatureIndex: number; location: number }
>
| undefined;

if (intersect.features.length > 0 && intersect.features[0]) {
intersectPt = {
...intersect.features[0],
properties: {
dist: distance(pt, intersect.features[0], options),
location: length + distance(start, intersect.features[0], options),
},
};
}
if (intersect.features.length > 0 && intersect.features[0]) {
intersectPt = {
...intersect.features[0],
properties: {
dist: distance(pt, intersect.features[0], options),
multiFeatureIndex: multiFeatureIndex,
location:
length + distance(start, intersect.features[0], options),
},
};
}

if (start.properties.dist < closestPt.properties.dist) {
closestPt = {
...start,
properties: { ...start.properties, index: i, location: length },
};
}
if (start.properties.dist < closestPt.properties.dist) {
closestPt = {
...start,
properties: {
...start.properties,
index: i,
multiFeatureIndex: multiFeatureIndex,
location: length,
},
};
}

if (stop.properties.dist < closestPt.properties.dist) {
closestPt = {
...stop,
properties: {
...stop.properties,
index: i + 1,
location: length + sectionLength,
},
};
}
if (stop.properties.dist < closestPt.properties.dist) {
closestPt = {
...stop,
properties: {
...stop.properties,
index: i + 1,
multiFeatureIndex: multiFeatureIndex,
location: length + sectionLength,
},
};
}

if (
intersectPt &&
intersectPt.properties.dist < closestPt.properties.dist
) {
closestPt = {
...intersectPt,
properties: { ...intersectPt.properties, index: i },
};
if (
intersectPt &&
intersectPt.properties.dist < closestPt.properties.dist
) {
closestPt = {
...intersectPt,
properties: { ...intersectPt.properties, index: i },
};
}
// update length
length += sectionLength;
}
// update length
length += sectionLength;
}
});
);

return closestPt;
}
Expand Down
22 changes: 22 additions & 0 deletions packages/turf-nearest-point-on-line/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,3 +375,25 @@ test("turf-point-on-line -- Geometry Support", (t) => {
);
t.end();
});

test("turf-point-on-line -- multifeature index", (t) => {
const pt = point([4, 30]);
const multiLine = multiLineString([
[
[7, 50],
[8, 50],
[9, 50],
],
[
[17, 30],
[4, 30],
[2, 30],
],
]);
t.equal(
nearestPointOnLine(multiLine.geometry, pt).properties.multiFeatureIndex,
1,
"multiFeatureIndex"
);
t.end();
});
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
[0, 0, 0, 0, 0, 0, 0, 0]
[
0,
0,
0,
0,
0,
0,
0,
0
]
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
[0.362058, 0.362058, 0.362058, 0.362058]
[
0.362058,
0.362058,
0.362058,
0.362058
]
Loading

0 comments on commit 645e844

Please sign in to comment.