Skip to content
This repository has been archived by the owner on Jul 11, 2019. It is now read-only.

Commit

Permalink
feature: Made Path more generic
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeMitterer committed Feb 3, 2016
1 parent 90b6c82 commit ec42c04
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 34 deletions.
20 changes: 20 additions & 0 deletions lib/latlong/LatLng.dart
Expand Up @@ -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');

Expand All @@ -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";
Expand Down
74 changes: 49 additions & 25 deletions lib/latlong/Path.dart
Expand Up @@ -19,35 +19,63 @@

part of latlong;

/// Necessary for creating new instances T extends LatLng (Path<T extends LatLng>)
///
/// class Location extends LatLng {
/// ....
/// }
///
/// final Path<Location> path = new Path<Location>(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<Location> path = new Path<Location>(factory: locationFactory);
///
class Path<T extends LatLng> {
final Logger _logger = new Logger('latlong.Path');

/// Coordinates managed by this class
final List<LatLng> _coordinates;
final List<T> _coordinates;

/// For [Distance] calculations
final Distance _distance = const Distance();

Path() : _coordinates = new List<LatLng>();
final LatLngFactory _latLngFactory;

Path({ final LatLngFactory factory: _defaultLatLngFactory })
: _coordinates = new List<T>(), _latLngFactory = factory;

//TODO: Should be Iterable<T> but is not supported by Dart at the moment
Path.from(final Iterable/*<T>*/ coordinates, { final LatLngFactory factory: _defaultLatLngFactory })
: _coordinates = new List<T>.from(coordinates), _latLngFactory = factory {

Path.from(final Iterable<LatLng> coordinates) : _coordinates = new List.from(coordinates) {
Validate.notNull(coordinates);
}

List<LatLng> get coordinates => _coordinates;
List<T> 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.
///
Expand Down Expand Up @@ -87,14 +115,14 @@ class Path {
return new Path.from([ _coordinates.first, _coordinates.last ]);
}

final List<LatLng> tempCoordinates = new List.from(_coordinates);
final List<T> 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]);
Expand All @@ -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;

Expand Down Expand Up @@ -190,7 +220,7 @@ class Path {
/// print(path.length);
///
num get distance {
final List<LatLng> tempCoordinates = new List.from(_coordinates);
final List<T> tempCoordinates = new List.from(_coordinates);
double length = 0.0;

for(int index = 0;index < coordinates.length - 1;index++) {
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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
Expand All @@ -246,12 +276,12 @@ class Path {
/// final Path path = new Path.from(<LatLng>[ 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<double> _createSpline(final LatLng p0,final LatLng p1,final LatLng p2,final LatLng p3) {
CatmullRomSpline2D<double> _createSpline(final T p0,final T p1,final T p2,final T p3) {
Validate.notNull(p0);
Validate.notNull(p1);
Validate.notNull(p2);
Expand All @@ -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<LatLng> temp = new Set<LatLng>.from(_coordinates);
_coordinates.clear();
_coordinates.addAll(temp);
}
T _pointToLatLng(final Point2D point) => _latLngFactory(point.x,point.y);
}

5 changes: 0 additions & 5 deletions lib/spline.dart
Expand Up @@ -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';

Expand Down
10 changes: 7 additions & 3 deletions test/unit/latlong/Path_test.dart
Expand Up @@ -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
Expand All @@ -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!

Expand Down
6 changes: 5 additions & 1 deletion tool/grind.dart
Expand Up @@ -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
Expand Down

0 comments on commit ec42c04

Please sign in to comment.