Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 13 additions & 14 deletions packages/turf-random/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
polygon,
validateBBox,
} from "@turf/helpers";
import destination from "@turf/destination";

/**
* Returns a random position within a {@link BBox|bounding box}.
Expand Down Expand Up @@ -233,20 +234,18 @@ function randomLineString(
for (let i = 0; i < count; i++) {
const startingPoint = randomPositionUnchecked(bbox);
const vertices = [startingPoint];
for (let j = 0; j < num_vertices - 1; j++) {
const priorAngle =
j === 0
? Math.random() * 2 * Math.PI
: Math.tan(
(vertices[j][1] - vertices[j - 1][1]) /
(vertices[j][0] - vertices[j - 1][0])
);
const angle = priorAngle + (Math.random() - 0.5) * max_rotation * 2;
const distance = Math.random() * max_length;
vertices.push([
vertices[j][0] + distance * Math.cos(angle),
vertices[j][1] + distance * Math.sin(angle),
]);
var priorBearing = Math.random() * 360;
for (var j = 0; j < num_vertices - 1; j++) {
var newBearing =
priorBearing +
((Math.random() - 0.5) * max_rotation * 2 * 180) / Math.PI;
if (newBearing > 180) newBearing -= 360;
var distance = Math.random() * max_length;
const vertex = destination(vertices[j], distance, newBearing, {
units: "degrees",
});
priorBearing = newBearing;
vertices.push(vertex.geometry.coordinates);
}
features.push(lineString(vertices));
}
Expand Down
3 changes: 3 additions & 0 deletions packages/turf-random/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
"test:tape": "tsx test.ts"
},
"devDependencies": {
"@turf/bearing": "workspace:*",
"@turf/distance": "workspace:*",
"@types/benchmark": "^2.1.5",
"@types/tape": "^5.8.1",
"benchmark": "^2.1.4",
Expand All @@ -60,6 +62,7 @@
"typescript": "^5.8.3"
},
"dependencies": {
"@turf/destination": "workspace:*",
"@turf/helpers": "workspace:*",
"@types/geojson": "^7946.0.10",
"tslib": "^2.8.1"
Expand Down
107 changes: 106 additions & 1 deletion packages/turf-random/test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import test from "tape";
import distance from "@turf/distance";
import bearing from "@turf/bearing";
import {
randomPoint,
randomPolygon,
Expand Down Expand Up @@ -30,7 +32,7 @@ test("random(polygons, 10)", (t) => {
t.end();
});

test("random(polygons, 1, {num_vertices})", (t) => {
test("random(polygons, 10, {num_vertices})", (t) => {
var points = randomPolygon(10, { num_vertices: 23 });
t.equal(points.type, "FeatureCollection", "is a featurecollection");
t.equal(points.features.length, 10, "right number of features");
Expand Down Expand Up @@ -77,3 +79,106 @@ test("bbox input gets validated", (t) => {
}, "randomPosition checks bbox validity");
t.end();
});

test("random(lines)", (t) => {
var lines = randomLineString();
t.equal(lines.type, "FeatureCollection", "is a featurecollection");
t.equal(lines.features.length, 1, "right number of features");
t.equal(
lines.features[0].geometry.type,
"LineString",
"feature type correct"
);
t.end();
});

test("random(lines, 10)", (t) => {
var lines = randomLineString(10);
t.equal(lines.type, "FeatureCollection", "is a featurecollection");
t.equal(lines.features.length, 10, "right number of features");
t.equal(
lines.features[0].geometry.type,
"LineString",
"feature type correct"
);
t.end();
});

test("random(lines, 10, {num_vertices})", (t) => {
var lines = randomLineString(10, { num_vertices: 10 });
t.equal(lines.type, "FeatureCollection", "is a featurecollection");
t.equal(lines.features.length, 10, "right number of features");
t.equal(lines.features[0].geometry.coordinates.length, 10, "num vertices");
t.end();
});

test("random(lines, 10, {bbox})", (t) => {
var lines = randomLineString(10, { bbox: [0, 0, 0, 0] });
t.equal(lines.type, "FeatureCollection", "is a featurecollection");
t.equal(lines.features.length, 10, "right number of features");
t.equal(
lines.features[0].geometry.type,
"LineString",
"feature type correct"
);
t.deepEqual(
lines.features[0].geometry.coordinates[0],
[0, 0],
"feature type correct"
);
t.end();
});

test("random(lines, 10, {max_length})", (t) => {
var lines = randomLineString(10, { max_length: 0.1 });
t.equal(lines.type, "FeatureCollection", "is a featurecollection");
t.equal(lines.features.length, 10, "right number of features");
t.equal(
lines.features[0].geometry.type,
"LineString",
"feature type correct"
);
let ok = true;
for (let i = 1; i < lines.features[0].geometry.coordinates.length; i++) {
const length = distance(
lines.features[0].geometry.coordinates[i - 1],
lines.features[0].geometry.coordinates[i],
{ units: "degrees" }
);
if (length > 0.1) ok = false;
}
t.ok(ok, "randomLineString ensures max_length");
t.end();
});

test("random(lines, 10, {max_rotation})", (t) => {
var lines = randomLineString(10, { max_rotation: Math.PI / 10 });
t.equal(lines.type, "FeatureCollection", "is a featurecollection");
t.equal(lines.features.length, 10, "right number of features");
t.equal(
lines.features[0].geometry.type,
"LineString",
"feature type correct"
);
let ok = true;
for (let i = 2; i < lines.features[0].geometry.coordinates.length; i++) {
// Compute the differential angle with the previous segment
let bearing1 = bearing(
lines.features[0].geometry.coordinates[i - 2],
lines.features[0].geometry.coordinates[i - 1]
);
//if (bearing1 < 0) bearing1 += 360;
let bearing2 = bearing(
lines.features[0].geometry.coordinates[i - 1],
lines.features[0].geometry.coordinates[i]
);
//if (bearing2 < 0) bearing2 += 360;
const difference =
bearing1 * bearing2 < 0
? bearing2 + bearing1
: Math.abs(bearing2 - bearing1);
if (difference > 18) ok = false;
}
t.ok(ok, "randomLineString ensures max_rotation");
t.end();
});
Loading