diff --git a/dart/geobase/lib/src/geodesy/ellipsoidal/datum.dart b/dart/geobase/lib/src/geodesy/ellipsoidal/datum.dart index d5c0be45..47a97659 100644 --- a/dart/geobase/lib/src/geodesy/ellipsoidal/datum.dart +++ b/dart/geobase/lib/src/geodesy/ellipsoidal/datum.dart @@ -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, ); } diff --git a/dart/geobase/lib/src/geodesy/ellipsoidal/ellipsoidal.dart b/dart/geobase/lib/src/geodesy/ellipsoidal/ellipsoidal.dart index 9639fb2b..52b8d362 100644 --- a/dart/geobase/lib/src/geodesy/ellipsoidal/ellipsoidal.dart +++ b/dart/geobase/lib/src/geodesy/ellipsoidal/ellipsoidal.dart @@ -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. // @@ -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. /// @@ -61,7 +63,18 @@ 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. @@ -69,7 +82,7 @@ class Ellipsoidal { /// 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} /// @@ -77,10 +90,26 @@ class Ellipsoidal { /// * [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} /// @@ -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). /// @@ -156,7 +206,8 @@ 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} /// @@ -164,13 +215,37 @@ extension EllipsoidalExtension on Geographic { 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, diff --git a/dart/geobase/test/geodesy/ellipsoidal_test.dart b/dart/geobase/test/geodesy/ellipsoidal_test.dart index daca1702..e40ba08c 100644 --- a/dart/geobase/test/geodesy/ellipsoidal_test.dart +++ b/dart/geobase/test/geodesy/ellipsoidal_test.dart @@ -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'); @@ -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'); });