@@ -498,6 +498,47 @@ void ConcatenatedOperation::fixStepsDirection(
498
498
auto newOp (Conversion::createGeographicGeocentric (
499
499
NN_NO_CHECK (prevOpTarget), NN_NO_CHECK (l_targetCRS)));
500
500
operationsInOut.insert (operationsInOut.begin () + i, newOp);
501
+ // Particular case for https://github.com/OSGeo/PROJ/issues/3819
502
+ // where the antepenultimate transformation goes to A
503
+ // (geographic 3D) // and the last transformation is a NADCON 3D
504
+ // but between A (geographic 2D) to B (geographic 2D), and the
505
+ // concatenated transformation target CRS is B (geographic 3D)
506
+ // This is due to an oddity of the EPSG database that registers
507
+ // the NADCON 3D transformation between the 2D geographic CRS
508
+ // and not the 3D ones.
509
+ } else if (i + 1 == operationsInOut.size () &&
510
+ l_sourceCRS->nameStr () == prevOpTarget->nameStr () &&
511
+ l_targetCRS->nameStr () == concatOpTargetCRS->nameStr () &&
512
+ isGeographic (l_targetCRS.get ()) &&
513
+ isGeographic (concatOpTargetCRS.get ()) &&
514
+ isGeographic (l_sourceCRS.get ()) &&
515
+ isGeographic (prevOpTarget.get ()) &&
516
+ dynamic_cast <const crs::GeographicCRS *>(
517
+ prevOpTarget.get ())
518
+ ->coordinateSystem ()
519
+ ->axisList ()
520
+ .size () == 3 &&
521
+ dynamic_cast <const crs::GeographicCRS *>(
522
+ l_sourceCRS.get ())
523
+ ->coordinateSystem ()
524
+ ->axisList ()
525
+ .size () == 2 &&
526
+ dynamic_cast <const crs::GeographicCRS *>(
527
+ l_targetCRS.get ())
528
+ ->coordinateSystem ()
529
+ ->axisList ()
530
+ .size () == 2 ) {
531
+ const auto transf =
532
+ dynamic_cast <const Transformation *>(op.get ());
533
+ if (transf &&
534
+ (transf->method ()->getEPSGCode () ==
535
+ EPSG_CODE_METHOD_NADCON5_3D ||
536
+ transf->parameterValue (
537
+ PROJ_WKT2_PARAMETER_LATITUDE_LONGITUDE_ELLIPOISDAL_HEIGHT_DIFFERENCE_FILE,
538
+ 0 ))) {
539
+ op->setCRSs (NN_NO_CHECK (prevOpTarget), concatOpTargetCRS,
540
+ nullptr );
541
+ }
501
542
}
502
543
}
503
544
}
0 commit comments