From ec42c042cf9a7ec1d82e68a9458063713ec2b18b Mon Sep 17 00:00:00 2001 From: Mike Mitterer Date: Wed, 3 Feb 2016 15:47:27 +0100 Subject: [PATCH] feature: Made Path more generic --- lib/latlong/LatLng.dart | 20 +++++++++ lib/latlong/Path.dart | 74 +++++++++++++++++++++----------- lib/spline.dart | 5 --- test/unit/latlong/Path_test.dart | 10 +++-- tool/grind.dart | 6 ++- 5 files changed, 81 insertions(+), 34 deletions(-) diff --git a/lib/latlong/LatLng.dart b/lib/latlong/LatLng.dart index ea6087a..01e132d 100644 --- a/lib/latlong/LatLng.dart +++ b/lib/latlong/LatLng.dart @@ -20,6 +20,9 @@ part of latlong; /// Coordinates in Degrees +/// +/// final Location location = new Location(10.000002,12.00001); +/// class LatLng { // final Logger _logger = new Logger('latlong.LatLng'); @@ -31,15 +34,32 @@ class LatLng { Validate.inclusiveBetween(-180.0,180.0,_longitude,"Longitude must be between -90 and 90 degrees but was $_longitude"); } + void set latitude(final double value) { + Validate.inclusiveBetween(-90.0,90.0,_latitude,"Latitude must be between -90 and 90 degrees but was $_latitude"); + _latitude = value; + } double get latitude => _latitude; + void set longitude(final double value) { + Validate.inclusiveBetween(-180.0,180.0,_longitude,"Longitude must be between -90 and 90 degrees but was $_longitude"); + _longitude = value; + } double get longitude => _longitude; + double get latitudeInRad => degToRadian(latitude); double get longitudeInRad => degToRadian(_longitude); String toString() => 'LatLng(latitude:$latitude, longitude:$longitude)'; + + /// Converts lat/long values into sexagesimal + /// + /// final LatLng p1 = new LatLng(51.519475, -19.37555556); + /// + /// // Shows: 51° 31' 10.11" N, 19° 22' 32.00" W + /// print(p1..toSexagesimal()); + /// String toSexagesimal() { String latDirection = latitude >= 0 ? "N" : "S"; String lonDirection = longitude >= 0 ? "O" : "W"; diff --git a/lib/latlong/Path.dart b/lib/latlong/Path.dart index 5226c1b..806521c 100644 --- a/lib/latlong/Path.dart +++ b/lib/latlong/Path.dart @@ -19,35 +19,63 @@ part of latlong; +/// Necessary for creating new instances T extends LatLng (Path) +/// +/// class Location extends LatLng { +/// .... +/// } +/// +/// final Path path = new Path(factory: locationFactory); +/// +typedef LatLng LatLngFactory(final double latitude, final double longitude); + +LatLng _defaultLatLngFactory(final double latitude, final double longitude) + => new LatLng(latitude,longitude); + /// Path of [LatLng] values -class Path { +/// +/// If you use [Path] with Generics - check out this sample: +/// +/// class Location extends LatLng { +/// .... +/// } +/// +/// final Path path = new Path(factory: locationFactory); +/// +class Path { final Logger _logger = new Logger('latlong.Path'); /// Coordinates managed by this class - final List _coordinates; + final List _coordinates; /// For [Distance] calculations final Distance _distance = const Distance(); - Path() : _coordinates = new List(); + final LatLngFactory _latLngFactory; + + Path({ final LatLngFactory factory: _defaultLatLngFactory }) + : _coordinates = new List(), _latLngFactory = factory; + + //TODO: Should be Iterable but is not supported by Dart at the moment + Path.from(final Iterable/**/ coordinates, { final LatLngFactory factory: _defaultLatLngFactory }) + : _coordinates = new List.from(coordinates), _latLngFactory = factory { - Path.from(final Iterable coordinates) : _coordinates = new List.from(coordinates) { Validate.notNull(coordinates); } - List get coordinates => _coordinates; + List get coordinates => _coordinates; /// Removes all coordinates from path void clear() => _coordinates.clear(); - /// Add new [LatLng] coordinate to path - void add(final LatLng value) { + /// Add new [T] coordinate to path + void add(final T value) { Validate.notNull(value); return _coordinates.add(value); } - LatLng get first => _coordinates.first; - LatLng get last => _coordinates.last; + T get first => _coordinates.first; + T get last => _coordinates.last; /// Splits the path into even sections. /// @@ -87,14 +115,14 @@ class Path { return new Path.from([ _coordinates.first, _coordinates.last ]); } - final List tempCoordinates = new List.from(_coordinates); + final List tempCoordinates = new List.from(_coordinates); final Path path = new Path(); double remainingSteps = 0.0; double bearing; path.add(tempCoordinates.first); - LatLng baseStep = tempCoordinates.first; + T baseStep = tempCoordinates.first; for(int index = 0;index < coordinates.length - 1;index++) { final double distance = _distance(tempCoordinates[index],tempCoordinates[index + 1]); @@ -116,7 +144,9 @@ class Path { for(int stepCounter = 0; stepCounter < fullSteps;stepCounter++) { // Add step on the given path - final LatLng nextStep = _distance.offset(baseStep,firstStepPos,bearing); + // Intermediate step is necessary to stay type-safe + final LatLng tempStep = _distance.offset(baseStep,firstStepPos,bearing); + final T nextStep = _latLngFactory(tempStep.latitude,tempStep.longitude); path.add(nextStep); firstStepPos += stepDistance; @@ -190,7 +220,7 @@ class Path { /// print(path.length); /// num get distance { - final List tempCoordinates = new List.from(_coordinates); + final List tempCoordinates = new List.from(_coordinates); double length = 0.0; for(int index = 0;index < coordinates.length - 1;index++) { @@ -202,7 +232,7 @@ class Path { /// Calculates the center of a collection of geo coordinates /// /// The function rounds the result to 6 decimals - LatLng get center { + T get center { Validate.notEmpty(coordinates,"Coordinates must not be empty!"); double X = 0.0; @@ -211,7 +241,7 @@ class Path { double lat, lon, hyp; - coordinates.forEach( (final LatLng coordinate) { + coordinates.forEach( (final T coordinate) { lat = coordinate.latitudeInRad; lon = coordinate.longitudeInRad; @@ -231,7 +261,7 @@ class Path { hyp = math.sqrt(X * X + Y * Y); lat = math.atan2(Z, hyp); - return new LatLng(round(radianToDeg(lat)),round(radianToDeg(lon))); + return _latLngFactory(round(radianToDeg(lat)),round(radianToDeg(lon))); } /// Returns the number of coordinates @@ -246,12 +276,12 @@ class Path { /// final Path path = new Path.from([ startPos,endPos ]); /// final LatLng p1 = path[0]; // p1 == startPos /// - LatLng operator[](final int index) => _coordinates.elementAt(index); + T operator[](final int index) => _coordinates.elementAt(index); //- private ----------------------------------------------------------------------------------- /// 4 Points are necessary to create a [CatmullRomSpline2D] - CatmullRomSpline2D _createSpline(final LatLng p0,final LatLng p1,final LatLng p2,final LatLng p3) { + CatmullRomSpline2D _createSpline(final T p0,final T p1,final T p2,final T p3) { Validate.notNull(p0); Validate.notNull(p1); Validate.notNull(p2); @@ -266,12 +296,6 @@ class Path { } /// Convert [Point2D] to [LatLng] - LatLng _pointToLatLng(final Point2D point) => new LatLng(point.x,point.y); - - void _removeDuplicates() { - final Set temp = new Set.from(_coordinates); - _coordinates.clear(); - _coordinates.addAll(temp); - } + T _pointToLatLng(final Point2D point) => _latLngFactory(point.x,point.y); } diff --git a/lib/spline.dart b/lib/spline.dart index e35a6fa..79c3d35 100644 --- a/lib/spline.dart +++ b/lib/spline.dart @@ -27,11 +27,6 @@ /// library spline; -import 'dart:async'; -import 'dart:collection'; - -import 'dart:math' as math; - import 'package:validate/validate.dart'; //import 'package:logging/logging.dart'; diff --git a/test/unit/latlong/Path_test.dart b/test/unit/latlong/Path_test.dart index d3a851a..d78a8b8 100644 --- a/test/unit/latlong/Path_test.dart +++ b/test/unit/latlong/Path_test.dart @@ -150,6 +150,8 @@ main() { expect(distance(westendorf.first,westendorf.last),209); final Path steps = path.equalize(5); + expect(steps.nrOfCoordinates,44); + _exportForGoogleEarth(steps,show: false); }); // end of 'Reality Test - Westendorf, short' test @@ -165,10 +167,12 @@ main() { expect(distance(zigzag.first,zigzag.last),190); final Path steps = path.equalize(8,smoothPath: true); - _exportForGoogleEarth(steps,show: false); - // 282 / 8 = 38 + first + last - expect(steps.coordinates.length, inInclusiveRange(36,38)); + // 282 / 8 = 35,25 + first + last + expect(steps.nrOfCoordinates,36); + expect(steps.coordinates.length, inInclusiveRange(36,37)); + + _exportForGoogleEarth(steps,show: false); // Distance check makes no sense - path is shorter than the original one! diff --git a/tool/grind.dart b/tool/grind.dart index de7147a..e1ab27b 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -8,8 +8,12 @@ build() { } @Task() -@Depends(analyze) +@Depends(analyze, testUnit) test() { +} + +@Task() +testUnit() { new TestRunner().testAsync(files: "test/unit"); // All tests with @TestOn("content-shell") in header