@@ -4082,26 +4082,31 @@ CoordinateOperationFactory::Private::createOperationsEnsembleCRSToOtherGeodCRS(
40824082 const auto getNatureOf = [](const crs::GeodeticCRS &crs) -> std::string {
40834083 if (dynamic_cast <const crs::GeographicCRS *>(&crs) != nullptr ) {
40844084 if (crs.coordinateSystem ()->axisList ().size () == 2 )
4085- return " geographic2D " ;
4085+ return CRS_SUBTYPE_GEOG_2D ;
40864086 else
4087- return " geographic3D " ;
4087+ return CRS_SUBTYPE_GEOG_3D ;
40884088 } else {
4089- return " geodetic " ;
4089+ return CRS_SUBTYPE_GEOCENTRIC ;
40904090 }
40914091 };
40924092
40934093 const auto &authFactory = context.context ->getAuthorityFactory ();
40944094 const auto srcEnsemble = geodSrc->datumEnsemble ();
40954095 assert (srcEnsemble);
40964096 const auto &dstDomains = geodDst->domains ();
4097+ const auto &dstExtent = dstDomains[0 ]->domainOfValidity ();
4098+ if (!dstExtent) {
4099+ return {};
4100+ }
4101+
40974102 const auto &areaOfInterest = context.context ->getAreaOfInterest ();
40984103 const bool is3D = geodSrc->coordinateSystem ()->axisList ().size () == 3 &&
40994104 geodDst->coordinateSystem ()->axisList ().size () == 3 ;
4100- const char *intermediateType = is3D ? " geographic 3D" : " geographic 2D" ;
4101-
41024105 std::vector<CoordinateOperationNNPtr> newOps;
4103- const auto &dstExtent = dstDomains[0 ]->domainOfValidity ();
4104- if (dstExtent) {
4106+ for (int iter = 0 ; iter < (is3D ? 2 : 1 ); ++iter) {
4107+ const char *intermediateType =
4108+ is3D ? (iter == 0 ? CRS_SUBTYPE_GEOG_3D : CRS_SUBTYPE_GEOCENTRIC )
4109+ : CRS_SUBTYPE_GEOG_2D ;
41054110 for (const auto &srcDatumCandidate : srcEnsemble->datums ()) {
41064111 const auto &srcDatumDomains = srcDatumCandidate->domains ();
41074112 if (srcDatumDomains.empty ())
@@ -4125,8 +4130,29 @@ CoordinateOperationFactory::Private::createOperationsEnsembleCRSToOtherGeodCRS(
41254130 srcDatumCandidate.as_nullable ())),
41264131 std::string (), intermediateType);
41274132 for (const auto &srcDatumGeogCRS : srcDatumGeogCRSList) {
4128- auto ops = createOperations (srcDatumGeogCRS, sourceEpoch,
4129- targetCRS, targetEpoch, context);
4133+
4134+ std::vector<CoordinateOperationNNPtr> ops;
4135+ std::vector<CoordinateOperationNNPtr> opsLastConversion;
4136+ if (getNatureOf (*(srcDatumGeogCRS.get ())) ==
4137+ CRS_SUBTYPE_GEOCENTRIC &&
4138+ getNatureOf (*geodDst) == CRS_SUBTYPE_GEOG_3D ) {
4139+ auto tmpList = authFactory->createGeodeticCRSFromDatum (
4140+ NN_CHECK_ASSERT (geodDst->datum ()), std::string (),
4141+ CRS_SUBTYPE_GEOCENTRIC );
4142+ if (!tmpList.empty ()) {
4143+ ops = createOperations (srcDatumGeogCRS, sourceEpoch,
4144+ tmpList.front (), targetEpoch,
4145+ context);
4146+ opsLastConversion =
4147+ createOperations (tmpList.front (), targetEpoch,
4148+ targetCRS, targetEpoch, context);
4149+ }
4150+ }
4151+ if (ops.empty ()) {
4152+ opsLastConversion.clear ();
4153+ ops = createOperations (srcDatumGeogCRS, sourceEpoch,
4154+ targetCRS, targetEpoch, context);
4155+ }
41304156 if (getNatureOf (*(srcDatumGeogCRS.get ())) ==
41314157 getNatureOf (*geodSrc) &&
41324158 srcDatumGeogCRS->coordinateSystem ()->_isEquivalentTo (
@@ -4142,6 +4168,12 @@ CoordinateOperationFactory::Private::createOperationsEnsembleCRSToOtherGeodCRS(
41424168 util::IComparable::Criterion::EQUIVALENT )) {
41434169 newOp->setInterpolationCRS (sourceCRS);
41444170 }
4171+ if (!opsLastConversion.empty ()) {
4172+ newOp = ConcatenatedOperation::
4173+ createComputeMetadata (
4174+ {newOp, opsLastConversion.front ()},
4175+ context.disallowEmptyIntersection ());
4176+ }
41454177 setCRSs (newOp.get (), sourceCRS, targetCRS);
41464178 newOps.push_back (newOp);
41474179 }
@@ -4150,20 +4182,55 @@ CoordinateOperationFactory::Private::createOperationsEnsembleCRSToOtherGeodCRS(
41504182 // Expected to get only one as this is a null
41514183 // transformation between an ensemble and one
41524184 // of its member
4153- const auto opsFirst =
4154- createOperations (sourceCRS, sourceEpoch,
4155- srcDatumGeogCRS, sourceEpoch, context);
4185+ std::vector<CoordinateOperationNNPtr> opsFirstConversion;
4186+ std::vector<CoordinateOperationNNPtr> opsFirst;
4187+ if (getNatureOf (*(srcDatumGeogCRS.get ())) ==
4188+ CRS_SUBTYPE_GEOCENTRIC &&
4189+ getNatureOf (*geodSrc) == CRS_SUBTYPE_GEOG_3D ) {
4190+ auto tmpList = authFactory->createGeodeticCRSFromDatum (
4191+ geodSrc->datumNonNull (
4192+ authFactory->databaseContext ()),
4193+ std::string (), CRS_SUBTYPE_GEOCENTRIC );
4194+ if (!tmpList.empty ()) {
4195+ opsFirstConversion = createOperations (
4196+ sourceCRS, sourceEpoch, tmpList.front (),
4197+ sourceEpoch, context);
4198+ context
4199+ .inCreateOperationsWithDatumPivotAntiRecursion =
4200+ false ;
4201+ opsFirst = createOperations (
4202+ tmpList.front (), sourceEpoch, srcDatumGeogCRS,
4203+ sourceEpoch, context);
4204+ context
4205+ .inCreateOperationsWithDatumPivotAntiRecursion =
4206+ true ;
4207+ }
4208+ }
4209+ if (opsFirst.empty ()) {
4210+ opsFirstConversion.clear ();
4211+ opsFirst = createOperations (sourceCRS, sourceEpoch,
4212+ srcDatumGeogCRS,
4213+ sourceEpoch, context);
4214+ }
41564215 if (!opsFirst.empty () &&
41574216 !opsFirst.front ()->hasBallparkTransformation ()) {
41584217 const auto &opFirst = opsFirst.front ();
41594218 for (const auto &op : ops) {
41604219 if (!op->hasBallparkTransformation ()) {
4161- newOps.push_back (
4162- ConcatenatedOperation::
4163- createComputeMetadata (
4164- {opFirst, op},
4165- context
4166- .disallowEmptyIntersection ()));
4220+ std::vector<CoordinateOperationNNPtr> tmp;
4221+ if (!opsFirstConversion.empty ()) {
4222+ tmp.push_back (opsFirstConversion.front ());
4223+ }
4224+ tmp.push_back (opFirst);
4225+ tmp.push_back (op);
4226+ if (!opsLastConversion.empty ()) {
4227+ tmp.push_back (opsLastConversion.front ());
4228+ }
4229+ auto newOp = ConcatenatedOperation::
4230+ createComputeMetadata (
4231+ tmp,
4232+ context.disallowEmptyIntersection ());
4233+ newOps.push_back (newOp);
41674234 }
41684235 }
41694236 }
0 commit comments