Skip to content

Commit

Permalink
feat(geobase): optional datum property in Ellipsoidal class #256
Browse files Browse the repository at this point in the history
  • Loading branch information
navispatial committed Jan 1, 2025
1 parent 9be1405 commit fc6b737
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 15 deletions.
6 changes: 3 additions & 3 deletions dart/geobase/lib/src/geodesy/ellipsoidal/datum.dart
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,11 @@ class Datum {
///
/// The returned position is a geographic position in the [to] datum.
Geographic convertGeographic(Geographic geographic, {required Datum to}) {
final geocentric = geographic.toGeocentricCartesian(ellipsoid: ellipsoid);
final geocentric = geographic.toGeocentricCartesianDatum(datum: this);
final converted = convertGeocentric(geocentric, to: to);
return EllipsoidalExtension.fromGeocentricCartesian(
return EllipsoidalExtension.fromGeocentricCartesianDatum(
converted,
ellipsoid: to.ellipsoid,
datum: to,
);
}

Expand Down
91 changes: 83 additions & 8 deletions dart/geobase/lib/src/geodesy/ellipsoidal/ellipsoidal.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

// Adaptations on the derivative work (the Dart port):
//
// Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved.
// Copyright (c) 2020-2025 Navibyte (https://navibyte.com). All rights reserved.
// Use of this source code is governed by a “BSD-3-Clause”-style license that is
// specified in the LICENSE file.
//
Expand All @@ -36,6 +36,8 @@ import '/src/common/reference/ellipsoid.dart';
import '/src/coordinates/base/position.dart';
import '/src/coordinates/geographic/geographic.dart';

import 'datum.dart';

/// The base class for calculations related to the Earth surface modeled by
/// ellipsoidal reference frames.
///
Expand All @@ -61,26 +63,53 @@ import '/src/coordinates/geographic/geographic.dart';
/// accessing these transformations.
@immutable
class Ellipsoidal {
/// An optional datum used for calculations with a reference ellipsoid and
/// datum transformation parameters.
///
/// See also [ellipsoid].
final Datum? datum;

/// The reference ellipsoid used for calculations.
///
/// When [datum] is provided, this [ellipsoid] property equals to the
/// ellipsoid of the datum.
///
/// See also [datum].
final Ellipsoid ellipsoid;

/// The origin geographic position for calculations.
final Geographic origin;

/// Create an object for ellipsoidal calculations with [origin] as the
/// current geographic position (latitude and longitude as geodetic
/// coordinates).
/// coordinates) based on the given [ellipsoid].
///
/// {@template geobase.geodesy.ellipsoidal.parameters}
///
/// Parameters:
/// * [ellipsoid]: A reference ellipsoid with ellipsoidal parameters.
///
/// {@endtemplate}
const Ellipsoidal(this.origin, {this.ellipsoid = Ellipsoid.WGS84});
const Ellipsoidal(this.origin, {this.ellipsoid = Ellipsoid.WGS84})
: datum = null;

/// Create an object for ellipsoidal calculations with [origin] as the
/// current geographic position (latitude and longitude as geodetic
/// coordinates) based on the given [datum].
///
/// {@template geobase.geodesy.ellipsoidal.datum}
///
/// Parameters:
/// * [datum]: A datum with a reference ellipsoid and datum transformation
/// parameters.
///
/// {@endtemplate}
Ellipsoidal.datum(this.origin, {Datum this.datum = Datum.WGS84})
: ellipsoid = datum.ellipsoid;

/// Create an object for ellipsoidal calculations with a origin position
/// transformed from [geocentric] cartesian coordinates (X, Y, Z).
/// transformed from [geocentric] cartesian coordinates (X, Y, Z) based on the
/// given [ellipsoid].
///
/// {@macro geobase.geodesy.ellipsoidal.ecef}
///
Expand All @@ -99,6 +128,27 @@ class Ellipsoidal {
);
}

/// Create an object for ellipsoidal calculations with a origin position
/// transformed from [geocentric] cartesian coordinates (X, Y, Z) based on the
/// given [datum].
///
/// {@macro geobase.geodesy.ellipsoidal.ecef}
///
/// {@macro geobase.geodesy.ellipsoidal.datum}
factory Ellipsoidal.fromGeocentricCartesianDatum(
Position geocentric, {
Datum datum = Datum.WGS84,
}) {
// an instance with target geographic position
return Ellipsoidal.datum(
EllipsoidalExtension.fromGeocentricCartesianDatum(
geocentric,
datum: datum,
),
datum: datum,
);
}

/// Transform the geographic position at [origin] (latitude and longitude as
/// geodetic coordinates) to geocentric cartesian coordinates (X, Y, Z).
///
Expand Down Expand Up @@ -156,21 +206,46 @@ class Ellipsoidal {
/// these transformations.
extension EllipsoidalExtension on Geographic {
/// Transform this geographic position (latitude and longitude as
/// geodetic coordinates) to geocentric cartesian coordinates (X, Y, Z).
/// geodetic coordinates) to geocentric cartesian coordinates (X, Y, Z) based
/// on the given [ellipsoid].
///
/// {@macro geobase.geodesy.ellipsoidal.ecef}
///
/// {@macro geobase.geodesy.ellipsoidal.parameters}
Position toGeocentricCartesian({Ellipsoid ellipsoid = Ellipsoid.WGS84}) =>
Ellipsoidal(this, ellipsoid: ellipsoid).toGeocentricCartesian();

/// Transform this geographic position (latitude and longitude as
/// geodetic coordinates) to geocentric cartesian coordinates (X, Y, Z) based
/// on the given [datum].
///
/// {@macro geobase.geodesy.ellipsoidal.ecef}
///
/// {@macro geobase.geodesy.ellipsoidal.datum}
Position toGeocentricCartesianDatum({Datum datum = Datum.WGS84}) =>
Ellipsoidal.datum(this, datum: datum).toGeocentricCartesian();

/// Transform the given [geocentric] cartesian coordinates (X, Y, Z) to
/// geographic coordinates (latitude and longitude).
/// geographic coordinates (latitude and longitude) based on the given
/// [datum].
///
/// {@macro geobase.geodesy.ellipsoidal.ecef}
///
/// Parameters:
/// * [ellipsoid]: A reference ellipsoid with ellipsoidal parameters.
/// {@macro geobase.geodesy.ellipsoidal.datum}
static Geographic fromGeocentricCartesianDatum(
Position geocentric, {
Datum datum = Datum.WGS84,
}) {
return fromGeocentricCartesian(geocentric, ellipsoid: datum.ellipsoid);
}

/// Transform the given [geocentric] cartesian coordinates (X, Y, Z) to
/// geographic coordinates (latitude and longitude) based on the given
/// [ellipsoid].
///
/// {@macro geobase.geodesy.ellipsoidal.ecef}
///
/// {@macro geobase.geodesy.ellipsoidal.parameters}
static Geographic fromGeocentricCartesian(
Position geocentric, {
Ellipsoid ellipsoid = Ellipsoid.WGS84,
Expand Down
10 changes: 6 additions & 4 deletions dart/geobase/test/geodesy/ellipsoidal_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,9 @@ void main() {
const geo1 = Geographic(lat: 51.47788, lon: -0.00147);
final gc1 = geo1.toGeocentricCartesian();
final gc1conv = Datum.WGS84.convertGeocentric(gc1, to: Datum.OSGB36);
final geo1conv = EllipsoidalExtension.fromGeocentricCartesian(gc1conv,
ellipsoid: Datum.OSGB36.ellipsoid);
final geo1conv = EllipsoidalExtension.fromGeocentricCartesianDatum(
gc1conv,
datum: Datum.OSGB36);
expect(geo1conv.latDms(dms6), '51.477364°N');
expect(geo1conv.lonDms(dms6), '0.000150°E');

Expand All @@ -143,8 +144,9 @@ void main() {
z: 4919474.294,
);
final gc2conv = Datum.WGS84.convertGeocentric(gc2, to: Datum.OSGB36);
final geo2conv = EllipsoidalExtension.fromGeocentricCartesian(gc2conv,
ellipsoid: Datum.OSGB36.ellipsoid);
final geo2conv = EllipsoidalExtension.fromGeocentricCartesianDatum(
gc2conv,
datum: Datum.OSGB36);
expect(geo2conv.latDms(), '50.7971°N');
expect(geo2conv.lonDms(), '4.3612°E');
});
Expand Down

0 comments on commit fc6b737

Please sign in to comment.