diff --git a/lib/random_linestring.dart b/lib/random_linestring.dart new file mode 100644 index 00000000..f6a6800d --- /dev/null +++ b/lib/random_linestring.dart @@ -0,0 +1,4 @@ +library turf_random_linestring; + +export 'src/random_linestring.dart'; +export 'package:geotypes/geotypes.dart'; \ No newline at end of file diff --git a/lib/src/random_linestring.dart b/lib/src/random_linestring.dart new file mode 100644 index 00000000..a3984fda --- /dev/null +++ b/lib/src/random_linestring.dart @@ -0,0 +1,62 @@ +import 'dart:math'; +import 'package:turf/turf.dart'; + +// Takes an optional bbox and a mandatory integer to generate x number of linestrings. Other optional parameters: numVertices, maxLength, maxRotation +// Returns a random linestring + +FeatureCollection randomLineString(int? count, + {BBox? bbox, numVertices, maxLength, maxRotation}) { + numVertices ??= 10; + maxLength ??= 0.0001; + maxRotation ??= pi / 8; + + // Ensure count is +ve value + if (count! <= 0) { + throw ArgumentError( + 'Count must be set to a positive integer to return a LineString.'); + } + + // Returns a random position within Bbox if provided + Position coordInBBox(BBox? bbox) { + return Position(bbox![0]! + Random().nextDouble() * (bbox[2]! - bbox[0]!), + bbox[1]! + Random().nextDouble() * (bbox[3]! - bbox[1]!)); + } + + // Returns a random position within bbox if provided, else returns a random Position on the globe + Position randomPositionUnchecked(BBox? bbox) { + if (bbox != null) { + return coordInBBox(bbox); + } + return Position( + Random().nextDouble() * 360 - 180, Random().nextDouble() * 180 - 90); + } + + // Generate list for all features, and loops through to generate all linestrings + List> features = []; + + for (int i = 0; i < count; i++) { + Position startingPos = randomPositionUnchecked(bbox); + + List vertices = [startingPos]; + + for (int j = 0; j < numVertices - 1; j++) { + double priorAngle = j == 0 + ? Random().nextDouble() * 2 * pi + : atan((vertices[j][1]! - vertices[j - 1][1]!) / + (vertices[j][0]! - vertices[j - 1][0]!)); + + double angle = + priorAngle + (Random().nextDouble() - 0.5) * maxRotation * 2; + double distance = Random().nextDouble() * maxLength; + + vertices.add(Position( + vertices[j][0]! + distance * cos(angle), + vertices[j][1]! + distance * sin(angle), + )); + } + + features.add(Feature(geometry: LineString(coordinates: vertices))); + } + //Finally return FeatureCollection + return FeatureCollection(features: features); +} diff --git a/test/components/random_linestring_test.dart b/test/components/random_linestring_test.dart new file mode 100644 index 00000000..1eda342f --- /dev/null +++ b/test/components/random_linestring_test.dart @@ -0,0 +1,57 @@ +import 'package:test/test.dart'; +import 'package:turf/random_linestring.dart'; +import 'dart:math'; + +void main() { + group('Random linestring tests', () { + test('Returning a valid feature collection', () { + FeatureCollection featureCollection = randomLineString(3); + + expect(featureCollection, isA>()); + expect( + featureCollection.features + .every((line) => line.geometry is LineString), + isTrue); + }); + + test('Checking bbox boundaries', () { + BBox? bbox = BBox(100.0, -24.0, 110.0, -23.0); + + FeatureCollection lineString = + randomLineString(1, bbox: bbox); + + lineString.features.first.geometry?.coordinates.forEach((coord) { + expect(coord[0], greaterThanOrEqualTo(bbox[0]!)); + expect(coord[0], lessThanOrEqualTo(bbox[2]!)); + expect(coord[1], greaterThanOrEqualTo(bbox[1]!)); + expect(coord[1], lessThanOrEqualTo(bbox[3]!)); + }); + }); + + test('Testing Linestrings have vertexes = numVertices', () { + int vertices = 15; + FeatureCollection lineString = + randomLineString(1, numVertices: vertices); + + expect(lineString.features.first.geometry?.coordinates.length, + equals(vertices)); + }); + + test('Testing maxLength and maxRotation constraints', () { + num maxLength = 0.001; + FeatureCollection featureCollection = + randomLineString(5, maxLength: maxLength); + + featureCollection.features.forEach((feature) { + final coords = feature.geometry?.coordinates; + for (int i = 1; i < coords!.length; i++) { + final dx = coords[i][0]! - coords[i - 1][0]!; + final dy = coords[i][1]! - coords[i - 1][1]!; + final distance = sqrt(dx * dx + dy * dy); + + expect(distance, lessThanOrEqualTo(maxLength)); + } + }); + }); + }); +}