aboutsummaryrefslogtreecommitdiff
path: root/operations/operations_computation.html
diff options
context:
space:
mode:
authorPROJ deploybot <proj.bot@proj.bot>2022-03-22 20:00:06 +0000
committerPROJ deploybot <proj.bot@proj.bot>2022-03-22 20:00:06 +0000
commita3f43744feec86272fe532124679d3a013ef9a8c (patch)
tree27e4198db6011e3097eb7bcfe7197684aba7583a /operations/operations_computation.html
downloadPROJ-gh-pages.tar.gz
PROJ-gh-pages.zip
update with results of commit https://github.com/OSGeo/PROJ/commit/53c07a8bd211b7aee4bc07a9c6726005504b7181gh-pages
Diffstat (limited to 'operations/operations_computation.html')
-rw-r--r--operations/operations_computation.html875
1 files changed, 875 insertions, 0 deletions
diff --git a/operations/operations_computation.html b/operations/operations_computation.html
new file mode 100644
index 00000000..3ab5848c
--- /dev/null
+++ b/operations/operations_computation.html
@@ -0,0 +1,875 @@
+<!DOCTYPE html>
+<html class="writer-html5" lang="en" >
+<head>
+ <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
+
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>Computation of coordinate operations between two CRS &mdash; PROJ 9.0.0 documentation</title>
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/css/theme.css" type="text/css" />
+ <link rel="shortcut icon" href="../_static/favicon.png"/>
+ <link rel="canonical" href="https://proj.orgoperations/operations_computation.html"/>
+ <!--[if lt IE 9]>
+ <script src="../_static/js/html5shiv.min.js"></script>
+ <![endif]-->
+
+ <script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
+ <script src="../_static/jquery.js"></script>
+ <script src="../_static/underscore.js"></script>
+ <script src="../_static/doctools.js"></script>
+ <script src="../_static/js/theme.js"></script>
+ <link rel="author" title="About these documents" href="../about.html" />
+ <link rel="index" title="Index" href="../genindex.html" />
+ <link rel="search" title="Search" href="../search.html" />
+ <link rel="next" title="Resource files" href="../resource_files.html" />
+ <link rel="prev" title="The pipeline operator" href="pipeline.html" />
+</head>
+
+<body class="wy-body-for-nav">
+ <div class="wy-grid-for-nav">
+ <nav data-toggle="wy-nav-shift" class="wy-nav-side">
+ <div class="wy-side-scroll">
+ <div class="wy-side-nav-search" style="background: #353130" >
+ <a href="../index.html">
+ <img src="../_static/logo.png" class="logo" alt="Logo"/>
+ </a>
+ <div class="version">
+ 9.0.0
+ </div>
+<div role="search">
+ <form id="rtd-search-form" class="wy-form" action="../search.html" method="get">
+ <input type="text" name="q" placeholder="Search docs" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+</div>
+ </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
+ <ul class="current">
+<li class="toctree-l1"><a class="reference internal" href="../about.html">About</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../news.html">News</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../download.html">Download</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../install.html">Installation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../usage/index.html">Using PROJ</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Applications</a></li>
+<li class="toctree-l1 current"><a class="reference internal" href="index.html">Coordinate operations</a><ul class="current">
+<li class="toctree-l2"><a class="reference internal" href="projections/index.html">Projections</a></li>
+<li class="toctree-l2"><a class="reference internal" href="conversions/index.html">Conversions</a></li>
+<li class="toctree-l2"><a class="reference internal" href="transformations/index.html">Transformations</a></li>
+<li class="toctree-l2"><a class="reference internal" href="pipeline.html">The pipeline operator</a></li>
+<li class="toctree-l2 current"><a class="current reference internal" href="#">Computation of coordinate operations between two CRS</a><ul>
+<li class="toctree-l3"><a class="reference internal" href="#introduction">Introduction</a></li>
+<li class="toctree-l3"><a class="reference internal" href="#geographic-crs-to-geographic-crs-with-known-identifiers">Geographic CRS to Geographic CRS, with known identifiers</a></li>
+<li class="toctree-l3"><a class="reference internal" href="#filtering-and-sorting-of-coordinate-operations">Filtering and sorting of coordinate operations</a></li>
+<li class="toctree-l3"><a class="reference internal" href="#geodetic-geographic-crs-to-geodetic-geographic-crs-without-known-identifiers">Geodetic/geographic CRS to Geodetic/geographic CRS, without known identifiers</a></li>
+<li class="toctree-l3"><a class="reference internal" href="#geodetic-geographic-crs-to-geodetic-geographic-crs-without-direct-transformation">Geodetic/geographic CRS to Geodetic/geographic CRS, without direct transformation</a></li>
+<li class="toctree-l3"><a class="reference internal" href="#projected-crs-to-any-target-crs">Projected CRS to any target CRS</a></li>
+<li class="toctree-l3"><a class="reference internal" href="#vertical-crs-to-a-geographic-crs">Vertical CRS to a Geographic CRS</a></li>
+<li class="toctree-l3"><a class="reference internal" href="#vertical-crs-to-a-vertical-crs">Vertical CRS to a Vertical CRS</a></li>
+<li class="toctree-l3"><a class="reference internal" href="#compound-crs-to-a-geographic-crs">Compound CRS to a Geographic CRS</a></li>
+<li class="toctree-l3"><a class="reference internal" href="#compoundcrs-to-compoundcrs">CompoundCRS to CompoundCRS</a></li>
+<li class="toctree-l3"><a class="reference internal" href="#when-the-source-or-target-crs-is-a-boundcrs">When the source or target CRS is a BoundCRS</a></li>
+</ul>
+</li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="../resource_files.html">Resource files</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../geodesic.html">Geodesic calculations</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../development/index.html">Development</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../specifications/index.html">Specifications</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../community/index.html">Community</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../faq.html">FAQ</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../glossary.html">Glossary</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../zreferences.html">References</a></li>
+</ul>
+
+ </div>
+ </div>
+ </nav>
+
+ <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" style="background: #353130" >
+ <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
+ <a href="../index.html">PROJ</a>
+ </nav>
+
+ <div class="wy-nav-content">
+ <div class="rst-content">
+ <div role="navigation" aria-label="Page navigation">
+ <ul class="wy-breadcrumbs">
+ <li><a href="../index.html" class="icon icon-home"></a> &raquo;</li>
+ <li><a href="index.html">Coordinate operations</a> &raquo;</li>
+ <li>Computation of coordinate operations between two CRS</li>
+ <li class="wy-breadcrumbs-aside">
+ <a href="https://github.com/OSGeo/PROJ/edit/8.2/docs/source/operations/operations_computation.rst" class="fa fa-github"> Edit on GitHub</a>
+ </li>
+ </ul><div class="rst-breadcrumbs-buttons" role="navigation" aria-label="Sequential page navigation">
+ <a href="pipeline.html" class="btn btn-neutral float-left" title="The pipeline operator" accesskey="p"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
+ <a href="../resource_files.html" class="btn btn-neutral float-right" title="Resource files" accesskey="n">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
+ </div>
+ <hr/>
+</div>
+ <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
+ <div itemprop="articleBody">
+
+ <section id="computation-of-coordinate-operations-between-two-crs">
+<span id="operations-computation"></span><h1>Computation of coordinate operations between two CRS<a class="headerlink" href="#computation-of-coordinate-operations-between-two-crs" title="Permalink to this headline">¶</a></h1>
+<dl class="field-list simple">
+<dt class="field-odd">Author</dt>
+<dd class="field-odd"><p>Even Rouault</p>
+</dd>
+<dt class="field-even">Last Updated</dt>
+<dd class="field-even"><p>2021-02-10</p>
+</dd>
+</dl>
+<section id="introduction">
+<h2>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline">¶</a></h2>
+<p>When using <strong class="command">projinfo -s {crs_def} -t {crs_def}</strong>,
+<strong class="command">cs2cs {crs_def} {crs_def}</strong> or the underlying
+<a class="reference internal" href="../development/reference/functions.html#c.proj_create_crs_to_crs" title="proj_create_crs_to_crs"><code class="xref c c-func docutils literal notranslate"><span class="pre">proj_create_crs_to_crs()</span></code></a> or <code class="xref cpp cpp-func docutils literal notranslate"><span class="pre">proj_create_operations()</span></code> functions,
+PROJ applies an algorithm to compute one or several candidate coordinate operations,
+that can be expressed as a PROJ <a class="reference internal" href="pipeline.html#pipeline"><span class="std std-ref">pipeline</span></a> to transform between the source
+and the target CRS. This document is about the description of this algorithm that
+finds the actual operations to apply to be able later to perform transform coordinates.
+So this is mostly about metadata management around coordinate operation methods,
+and not about the actual mathematics used to implement those methods.
+As a matter of fact with PROJ 6, there are about 60 000
+lines of code dealing with “metadata” management (including conversions between PROJ
+strings, all CRS WKT variants), to be compared to 30 000 for the purely computation part.</p>
+<p>This document is meant as a plain text explanation of the code for developers,
+but also as a in-depth examination of what happens under the hood for curious PROJ
+users. It is important to keep in mind that it is not meant to be the ultimate
+source of truth of how coordinate operations should be computed. There are clearly
+implementation choices and compromises that can be questioned.</p>
+<p>Let us start with an example to research operations between the NAD27 and NAD83
+geographic CRS:</p>
+<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>$ projinfo -s NAD27 -t NAD83 --summary --spatial-test intersects --grid-check none
+
+Candidate operations found: <span class="m">10</span>
+DERIVED_FROM<span class="o">(</span>EPSG<span class="o">)</span>:1312, NAD27 to NAD83 <span class="o">(</span><span class="m">3</span><span class="o">)</span>, <span class="m">1</span>.0 m, Canada
+DERIVED_FROM<span class="o">(</span>EPSG<span class="o">)</span>:1313, NAD27 to NAD83 <span class="o">(</span><span class="m">4</span><span class="o">)</span>, <span class="m">1</span>.5 m, Canada - NAD27, at least one grid missing
+DERIVED_FROM<span class="o">(</span>EPSG<span class="o">)</span>:1241, NAD27 to NAD83 <span class="o">(</span><span class="m">1</span><span class="o">)</span>, <span class="m">0</span>.15 m, USA - CONUS including EEZ
+DERIVED_FROM<span class="o">(</span>EPSG<span class="o">)</span>:1243, NAD27 to NAD83 <span class="o">(</span><span class="m">2</span><span class="o">)</span>, <span class="m">0</span>.5 m, USA - Alaska including EEZ
+DERIVED_FROM<span class="o">(</span>EPSG<span class="o">)</span>:1573, NAD27 to NAD83 <span class="o">(</span><span class="m">6</span><span class="o">)</span>, <span class="m">1</span>.5 m, Canada - Quebec, at least one grid missing
+EPSG:1462, NAD27 to NAD83 <span class="o">(</span><span class="m">5</span><span class="o">)</span>, <span class="m">1</span>.0 m, Canada - Quebec, at least one grid missing
+EPSG:9111, NAD27 to NAD83 <span class="o">(</span><span class="m">9</span><span class="o">)</span>, <span class="m">1</span>.5 m, Canada - Saskatchewan, at least one grid missing
+unknown id, Ballpark geographic offset from NAD27 to NAD83, unknown accuracy, World, has ballpark transformation
+EPSG:8555, NAD27 to NAD83 <span class="o">(</span><span class="m">7</span><span class="o">)</span>, <span class="m">0</span>.15 m, USA - CONUS and GoM, at least one grid missing
+EPSG:8549, NAD27 to NAD83 <span class="o">(</span><span class="m">8</span><span class="o">)</span>, <span class="m">0</span>.5 m, USA - Alaska, at least one grid missing
+</pre></div>
+</div>
+<p>The algorithm involves many cases, so we will progress in the explanation from
+the most simple case to more complex ones. We document here the working of this
+algorithm as implemented in PROJ 8.0.0.
+The results of some examples might also be quite sensitive to the content of the
+PROJ database and the PROJ version used.</p>
+<p>From a code point of view, the entry point of the algorithm is the C++
+<code class="xref cpp cpp-func docutils literal notranslate"><span class="pre">osgeo::proj::operation::CoordinateOperation::createOperations()</span></code> method.</p>
+<p>It combines several strategies:</p>
+<blockquote>
+<div><ul class="simple">
+<li><p>look up in the PROJ database for available operations</p></li>
+<li><p>consider the pair (source CRS, target CRS) to synthetize operations depending
+on the nature of the source and target CRS.</p></li>
+</ul>
+</div></blockquote>
+</section>
+<section id="geographic-crs-to-geographic-crs-with-known-identifiers">
+<h2>Geographic CRS to Geographic CRS, with known identifiers<a class="headerlink" href="#geographic-crs-to-geographic-crs-with-known-identifiers" title="Permalink to this headline">¶</a></h2>
+<p>With the above example of two geographic CRS, that have an identified identifier,
+(<strong class="program">projinfo</strong> internally resolves NAD27 to EPSG:4267 and NAD83 to EPSG:4269)
+the algorithm will first search
+in the coordinate operation related tables of the <code class="file docutils literal notranslate"><span class="pre">proj.db</span></code> if there are records
+that list direct transformations between the source and the target CRS. The
+transformations typically involve <a class="reference internal" href="transformations/helmert.html#helmert"><span class="std std-ref">Helmert</span></a>-style operations or datum shift based on
+grids (more esoteric operations are possible).</p>
+<p>A request similar to the following will be emitted:</p>
+<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>$ sqlite3 proj.db <span class="s2">&quot;SELECT auth_name, code, name, method_name, accuracy FROM \</span>
+<span class="s2"> coordinate_operation_view WHERE \</span>
+<span class="s2"> source_crs_auth_name = &#39;EPSG&#39; AND \</span>
+<span class="s2"> source_crs_code = &#39;4267&#39; AND \</span>
+<span class="s2"> target_crs_auth_name = &#39;EPSG&#39; AND \</span>
+<span class="s2"> target_crs_code = &#39;4269&#39;&quot;</span>
+
+EPSG<span class="p">|</span><span class="m">1241</span><span class="p">|</span>NAD27 to NAD83 <span class="o">(</span><span class="m">1</span><span class="o">)</span><span class="p">|</span>NADCON<span class="p">|</span><span class="m">0</span>.15
+EPSG<span class="p">|</span><span class="m">1243</span><span class="p">|</span>NAD27 to NAD83 <span class="o">(</span><span class="m">2</span><span class="o">)</span><span class="p">|</span>NADCON<span class="p">|</span><span class="m">0</span>.5
+EPSG<span class="p">|</span><span class="m">1312</span><span class="p">|</span>NAD27 to NAD83 <span class="o">(</span><span class="m">3</span><span class="o">)</span><span class="p">|</span>NTv1<span class="p">|</span><span class="m">1</span>.0
+EPSG<span class="p">|</span><span class="m">1313</span><span class="p">|</span>NAD27 to NAD83 <span class="o">(</span><span class="m">4</span><span class="o">)</span><span class="p">|</span>NTv2<span class="p">|</span><span class="m">1</span>.5
+EPSG<span class="p">|</span><span class="m">1462</span><span class="p">|</span>NAD27 to NAD83 <span class="o">(</span><span class="m">5</span><span class="o">)</span><span class="p">|</span>NTv1<span class="p">|</span><span class="m">1</span>.0
+EPSG<span class="p">|</span><span class="m">1573</span><span class="p">|</span>NAD27 to NAD83 <span class="o">(</span><span class="m">6</span><span class="o">)</span><span class="p">|</span>NTv2<span class="p">|</span><span class="m">1</span>.5
+EPSG<span class="p">|</span><span class="m">8549</span><span class="p">|</span>NAD27 to NAD83 <span class="o">(</span><span class="m">8</span><span class="o">)</span><span class="p">|</span>NADCON5 <span class="o">(</span>2D<span class="o">)</span><span class="p">|</span><span class="m">0</span>.5
+EPSG<span class="p">|</span><span class="m">8555</span><span class="p">|</span>NAD27 to NAD83 <span class="o">(</span><span class="m">7</span><span class="o">)</span><span class="p">|</span>NADCON5 <span class="o">(</span>2D<span class="o">)</span><span class="p">|</span><span class="m">0</span>.15
+EPSG<span class="p">|</span><span class="m">9111</span><span class="p">|</span>NAD27 to NAD83 <span class="o">(</span><span class="m">9</span><span class="o">)</span><span class="p">|</span>NTv2<span class="p">|</span><span class="m">1</span>.5
+ESRI<span class="p">|</span><span class="m">108003</span><span class="p">|</span>NAD_1927_To_NAD_1983_PR_VI<span class="p">|</span>NTv2<span class="p">|</span><span class="m">0</span>.05
+</pre></div>
+</div>
+<p>As we have found direct transformations, we will not attempt any more complicated
+research.
+One can note in the above result set that a ESRI:108003 operation was found,
+but as the source and target CRS are in the EPSG registry, and there are
+operations between those CRS in the EPSG registry itself, transformations from
+other authorities will be ignored (except if they are in the PROJ authority,
+which can be used as an override).</p>
+<p>As those results all involve operations that does not have a perfect accuracy and that
+does not cover the area of use of the 2 CRSs, a
+‘Ballpark geographic offset from NAD27 to NAD83’ operation is synthetized by PROJ
+(see <a class="reference internal" href="../glossary.html#term-Ballpark-transformation"><span class="xref std std-term">Ballpark transformation</span></a>)</p>
+</section>
+<section id="filtering-and-sorting-of-coordinate-operations">
+<h2>Filtering and sorting of coordinate operations<a class="headerlink" href="#filtering-and-sorting-of-coordinate-operations" title="Permalink to this headline">¶</a></h2>
+<p>The last step is to filter and sort results in order of relevance.</p>
+<p>The filtering takes into account the following criteria to decide which operations
+must be retained or discarded:</p>
+<ul class="simple">
+<li><p>a minimum accuracy that the user might have expressed,</p></li>
+<li><p>an area of use on which the coordinate operation(s) must apply</p></li>
+<li><p>if the absence of grids needed by an operation must result in discarding it.</p></li>
+</ul>
+<p>The sorting algorithm determines the order of relevance of the operations we got.
+A comparison function compares pair of operations to determine which of the
+two is the most relevant. This is implemented by the <code class="xref cpp cpp-func docutils literal notranslate"><span class="pre">operator</span> <span class="pre">()</span></code>
+method of the SortFunction structure.
+When comparing two operations, the following criteria are used. The tests are
+performed in the order they are listed below:</p>
+<ol class="arabic simple">
+<li><p>consider as more relevant an operation that can be expressed as a PROJ operation string
+(the database might list operations whose method is not (yet) implemented by PROJ)</p></li>
+<li><p>if both operations evaluate identically with respect to the above criterion,
+consider as more relevant an operation that does not include a synthetic
+ballpark vertical transformation (occurs when there is a geoid model).</p></li>
+<li><p>if both operations evaluate identically with respect to the above criterion,
+consider as more relevant an operation that does not include a synthetic
+ballpark horizontal transformation.</p></li>
+<li><p>consider as more relevant an operation that refers to shift grids that are locally available.</p></li>
+<li><p>consider as more relevant an operation that refers to grids that are available
+in one of the proj-datumgrid packages, but not necessarily locally available</p></li>
+<li><p>consider as more relevant an operation that has a known accuracy.</p></li>
+<li><p>if two operations have unknown accuracy, consider as more relevant an operation
+that uses grid(s) if the other one does not (grid based operations are assumed
+to be more precise than operations relying on a few parameters)</p></li>
+<li><p>consider as more relevant an operation whose area of use is larger
+(note: the computation of the are of use is approximate, based on a bounding box)</p></li>
+<li><p>consider as more relevant an operation that has a better accuracy.</p></li>
+<li><p>in case of same accuracy, consider as more relevant an operation that does
+not use grids (operations that use only parameters will be faster)</p></li>
+<li><p>consider as more relevant an operation that involves less transformation steps
+(transformation steps considered are the ones listed in the WKT output, not PROJ pipeline steps)</p></li>
+<li><p>and for completeness, if two operations are comparable given all the above criteria,
+consider as more relevant the one which has the shorter name, and if they
+have the same length, consider as more relevant the one whose name comes last in
+lexicographic order (e.g. “FOO to BAR (3)” will have higher precedence than
+“FOO to BAR (2)”)</p></li>
+</ol>
+<div class="admonition note">
+<p class="admonition-title">Note</p>
+<p><a class="reference internal" href="../development/reference/functions.html#c.proj_trans" title="proj_trans"><code class="xref c c-func docutils literal notranslate"><span class="pre">proj_trans()</span></code></a>, on the results returned by <a class="reference internal" href="../development/reference/functions.html#c.proj_create_crs_to_crs" title="proj_create_crs_to_crs"><code class="xref c c-func docutils literal notranslate"><span class="pre">proj_create_crs_to_crs()</span></code></a>,
+will not necessarily use the operation that
+is listed in first position due to the above algorithm. <a class="reference internal" href="../development/reference/functions.html#c.proj_trans" title="proj_trans"><code class="xref c c-func docutils literal notranslate"><span class="pre">proj_trans()</span></code></a>
+has more context, since it has the coordinate to transform, so it can compare
+this coordinate to the area of use of operations. Typically, the above criteria
+will favor an operation that has a larger area of use over another one with a
+smaller area, due to it being more generally applicable. But once coordinates are known,
+<a class="reference internal" href="../development/reference/functions.html#c.proj_trans" title="proj_trans"><code class="xref c c-func docutils literal notranslate"><span class="pre">proj_trans()</span></code></a> can select an operation with a smaller
+area of use that applies to the coordinate to transform.</p>
+</div>
+</section>
+<section id="geodetic-geographic-crs-to-geodetic-geographic-crs-without-known-identifiers">
+<h2>Geodetic/geographic CRS to Geodetic/geographic CRS, without known identifiers<a class="headerlink" href="#geodetic-geographic-crs-to-geodetic-geographic-crs-without-known-identifiers" title="Permalink to this headline">¶</a></h2>
+<p>In a number of situations, the source and/or target CRS do not have an identifier
+(WKT without identifier, PROJ string, ..)
+The first step is to try to find in the <code class="file docutils literal notranslate"><span class="pre">proj.db</span></code> a CRS of the same nature of
+the CRS to identify and whose name exactly matches the one provided to the
+<code class="xref c c-func docutils literal notranslate"><span class="pre">createOperations()</span></code> method. If there is exactly one match and that the CRS are
+“computationally” equivalent, then use the code of the CRS for further computations.</p>
+<p>If this search did not succeed, or if the previous case with known CRS identifiers
+did not result in matches in the database, the search will be based on the
+datums. That is, a list of geographic CRS whose datum matches the datum of the
+source and target CRS is searched for in the database (by querying the <cite>geodetic_crs</cite>
+database table). If the datum has a known
+identifier, we will use it, otherwise we will look for an equivalent datum in the
+database based on the datum name.</p>
+<p>Let’s consider the case where the datum of the source CRS is EPSG:6171 “Reseau
+Geodesique Francais 1993” and the datum of the target CRS is EPSG:6258 “European
+Terrestrial Reference System 1989”.
+For EPSG:6171, there are 10 matching (non-deprecated) geodetic CRSs:</p>
+<ul class="simple">
+<li><p>EPSG:4171, RGF93, geographic 2D</p></li>
+<li><p>EPSG:4964, RGF93, geocentric</p></li>
+<li><p>EPSG:4965, RGF93, geographic 3D</p></li>
+<li><p>EPSG:7042, RGF93 (lon-lat), geographic 3D</p></li>
+<li><p>EPSG:7084, RGF93 (lon-lat), geographic 2D</p></li>
+<li><p>IGNF:RGF93, RGF93 cartesiennes geocentriques, geocentric</p></li>
+<li><p>IGNF:RGF93GDD, RGF93 geographiques (dd),geographic 2D</p></li>
+<li><p>IGNF:RGF93GEODD, RGF93 geographiques (dd), geographic 3D</p></li>
+<li><p>IGNF:RGF93G, RGF93 geographiques (dms), geographic 2D</p></li>
+<li><p>IGNF:RGF93GEO, RGF93 geographiques (dms), geographic 3D</p></li>
+</ul>
+<p>The first three entries from the EPSG dataset are typical: for each datum,
+one can define a geographic 2D CRS (latitude, longitude), a geographic 3D crs
+(latitude, longitude, ellipsoidal height) and a geocentric one. For that particular
+case, the EPSG dataset has also included two extra definitions corresponding to a
+longitude, latitude, [ellipsoidal height] coordinate system, as found in the official
+French IGNF registry. This IGNF registry has also definitions for a geographic 2D
+CRS (with an extra subtlety with an entry using decimal degree as unit and another
+one degree-minute-second), geographic 3D and geocentric.</p>
+<p>For EPSG:6258, there are 7 matching (non-deprecated) geodetic CRSs:</p>
+<ul class="simple">
+<li><p>EPSG:4258, ETRS89, geographic 2D</p></li>
+<li><p>EPSG:4936, ETRS89, geocentric</p></li>
+<li><p>EPSG:4937, ETRS89, geographic 3D</p></li>
+<li><p>IGNF:ETRS89, ETRS89 cartesiennes geocentriques, geocentric</p></li>
+<li><p>IGNF:ETRS89G, ETRS89 geographiques (dms), geographic 2D</p></li>
+<li><p>IGNF:ETRS89GEO, ETRS89 geographiques (dms), geographic 3D</p></li>
+<li><p>ESRI:104129, GCS_EUREF_FIN, geographic 2D</p></li>
+</ul>
+<p>So the 3 typical EPSG entries, 3 equivalent (with long, lat ordering for the
+geographic CRS) and one from the ESRI registry;</p>
+<p>PROJ can now test 10 x 7 different combinations of source x target CRSs, using
+the database searching method explained in the previous section. As soon as
+one of this combination returns at least one non-ballpark combination, the result
+set coming from that combination is used. PROJ will then add before that
+transformation a conversion between the source CRS and the first intermediate CRS,
+and will add at the end a conversion between the second intermediate CRS and the
+target CRS. Those conversions are conversion between geographic 2D and geographic 3D
+CRS or geographic 2D/3D and geocentric CRS.</p>
+<p>This is done by the <code class="xref c c-func docutils literal notranslate"><span class="pre">createOperationsWithDatumPivot()</span></code> method.</p>
+<p>So if transforming between EPSG:7042, RGF93 (lon-lat), geographic 3D and
+EPSG:4936, ETRS89, geocentric, one get the following concatenated operation,
+chaining an axis order change, the null geocentric translation between
+RGF93 and ETRS89 (EPSG:1591), and a conversion between geographic and geocentric
+coordinates. This concatenated operation is assumed to have a perfect accuracy
+as both the initial and final operations are conversions, and the middle transformation
+accounts for the fact that the RGF93 datum is one realization of ETRS89, so they
+are equivalent for most purposes.</p>
+<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>$ projinfo -s EPSG:7042 -t EPSG:4936
+
+Candidate operations found: <span class="m">1</span>
+-------------------------------------
+Operation No. <span class="m">1</span>:
+
+unknown id, axis order change <span class="o">(</span>geographic3D horizontal<span class="o">)</span> + RGF93 to ETRS89 <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Conversion from ETRS89 <span class="o">(</span>geog2D<span class="o">)</span> to ETRS89 <span class="o">(</span>geocentric<span class="o">)</span>, <span class="m">0</span> m, France
+
+PROJ string:
++proj<span class="o">=</span>pipeline +step +proj<span class="o">=</span>unitconvert +xy_in<span class="o">=</span>deg +xy_out<span class="o">=</span>rad +step +proj<span class="o">=</span>cart +ellps<span class="o">=</span>GRS80
+
+WKT2:2019 string:
+CONCATENATEDOPERATION<span class="o">[</span><span class="s2">&quot;axis order change (geographic3D horizontal) + RGF93 to ETRS89 (1) + Conversion from ETRS89 (geog2D) to ETRS89 (geocentric)&quot;</span>,
+ SOURCECRS<span class="o">[</span>
+ GEOGCRS<span class="o">[</span><span class="s2">&quot;RGF93 (lon-lat)&quot;</span>,
+ <span class="o">[</span>...<span class="o">]</span>
+ ID<span class="o">[</span><span class="s2">&quot;EPSG&quot;</span>,7042<span class="o">]]]</span>,
+ TARGETCRS<span class="o">[</span>
+ GEODCRS<span class="o">[</span><span class="s2">&quot;ETRS89&quot;</span>,
+ <span class="o">[</span>...<span class="o">]</span>
+ ID<span class="o">[</span><span class="s2">&quot;EPSG&quot;</span>,4936<span class="o">]]]</span>,
+ STEP<span class="o">[</span>
+ CONVERSION<span class="o">[</span><span class="s2">&quot;axis order change (geographic3D horizontal)&quot;</span>,
+ METHOD<span class="o">[</span><span class="s2">&quot;Axis Order Reversal (Geographic3D horizontal)&quot;</span>,
+ ID<span class="o">[</span><span class="s2">&quot;EPSG&quot;</span>,9844<span class="o">]]</span>,
+ ID<span class="o">[</span><span class="s2">&quot;EPSG&quot;</span>,15499<span class="o">]]]</span>,
+ STEP<span class="o">[</span>
+ COORDINATEOPERATION<span class="o">[</span><span class="s2">&quot;RGF93 to ETRS89 (1)&quot;</span>,
+ <span class="o">[</span>...<span class="o">]</span>
+ METHOD<span class="o">[</span><span class="s2">&quot;Geocentric translations (geog2D domain)&quot;</span>,
+ ID<span class="o">[</span><span class="s2">&quot;EPSG&quot;</span>,9603<span class="o">]]</span>,
+ PARAMETER<span class="o">[</span><span class="s2">&quot;X-axis translation&quot;</span>,0,
+ LENGTHUNIT<span class="o">[</span><span class="s2">&quot;metre&quot;</span>,1<span class="o">]</span>,
+ ID<span class="o">[</span><span class="s2">&quot;EPSG&quot;</span>,8605<span class="o">]]</span>,
+ PARAMETER<span class="o">[</span><span class="s2">&quot;Y-axis translation&quot;</span>,0,
+ LENGTHUNIT<span class="o">[</span><span class="s2">&quot;metre&quot;</span>,1<span class="o">]</span>,
+ ID<span class="o">[</span><span class="s2">&quot;EPSG&quot;</span>,8606<span class="o">]]</span>,
+ PARAMETER<span class="o">[</span><span class="s2">&quot;Z-axis translation&quot;</span>,0,
+ LENGTHUNIT<span class="o">[</span><span class="s2">&quot;metre&quot;</span>,1<span class="o">]</span>,
+ ID<span class="o">[</span><span class="s2">&quot;EPSG&quot;</span>,8607<span class="o">]]</span>,
+ OPERATIONACCURACY<span class="o">[</span><span class="m">0</span>.0<span class="o">]</span>,
+ ID<span class="o">[</span><span class="s2">&quot;EPSG&quot;</span>,1591<span class="o">]</span>,
+ REMARK<span class="o">[</span><span class="s2">&quot;May be taken as approximate transformation RGF93 to WGS 84 - see code 1671.&quot;</span><span class="o">]]]</span>,
+ STEP<span class="o">[</span>
+ CONVERSION<span class="o">[</span><span class="s2">&quot;Conversion from ETRS89 (geog2D) to ETRS89 (geocentric)&quot;</span>,
+ METHOD<span class="o">[</span><span class="s2">&quot;Geographic/geocentric conversions&quot;</span>,
+ ID<span class="o">[</span><span class="s2">&quot;EPSG&quot;</span>,9602<span class="o">]]]]</span>,
+ USAGE<span class="o">[</span>
+ SCOPE<span class="o">[</span><span class="s2">&quot;unknown&quot;</span><span class="o">]</span>,
+ AREA<span class="o">[</span><span class="s2">&quot;France&quot;</span><span class="o">]</span>,
+ BBOX<span class="o">[</span><span class="m">41</span>.15,-9.86,51.56,10.38<span class="o">]]]</span>
+</pre></div>
+</div>
+</section>
+<section id="geodetic-geographic-crs-to-geodetic-geographic-crs-without-direct-transformation">
+<h2>Geodetic/geographic CRS to Geodetic/geographic CRS, without direct transformation<a class="headerlink" href="#geodetic-geographic-crs-to-geodetic-geographic-crs-without-direct-transformation" title="Permalink to this headline">¶</a></h2>
+<p>Still considering transformations between geodetic/geographic CRS, but let’s
+consider that the lookup in the database for a transformation between
+the source and target CRS (possibly going through the “equivalent” CRS based on
+the same datum as detailed in the previous section) leads to an empty set.</p>
+<p>Of course, as most operations are invertible, one first tries to do a lookup switching
+the source and target CRS, and inverting the resulting operation(s):</p>
+<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>$ projinfo -s NAD83 -t NAD27 --spatial-test intersects --summary
+
+Candidate operations found: <span class="m">10</span>
+INVERSE<span class="o">(</span>DERIVED_FROM<span class="o">(</span>EPSG<span class="o">))</span>:1312, Inverse of NAD27 to NAD83 <span class="o">(</span><span class="m">3</span><span class="o">)</span>, <span class="m">2</span>.0 m, Canada
+INVERSE<span class="o">(</span>DERIVED_FROM<span class="o">(</span>EPSG<span class="o">))</span>:1313, Inverse of NAD27 to NAD83 <span class="o">(</span><span class="m">4</span><span class="o">)</span>, <span class="m">1</span>.5 m, Canada - NAD27
+INVERSE<span class="o">(</span>DERIVED_FROM<span class="o">(</span>EPSG<span class="o">))</span>:1241, Inverse of NAD27 to NAD83 <span class="o">(</span><span class="m">1</span><span class="o">)</span>, <span class="m">0</span>.15 m, USA - CONUS including EEZ
+INVERSE<span class="o">(</span>DERIVED_FROM<span class="o">(</span>EPSG<span class="o">))</span>:1243, Inverse of NAD27 to NAD83 <span class="o">(</span><span class="m">2</span><span class="o">)</span>, <span class="m">0</span>.5 m, USA - Alaska including EEZ
+INVERSE<span class="o">(</span>DERIVED_FROM<span class="o">(</span>EPSG<span class="o">))</span>:1573, Inverse of NAD27 to NAD83 <span class="o">(</span><span class="m">6</span><span class="o">)</span>, <span class="m">1</span>.5 m, Canada - Quebec, at least one grid missing
+INVERSE<span class="o">(</span>EPSG<span class="o">)</span>:1462, Inverse of NAD27 to NAD83 <span class="o">(</span><span class="m">5</span><span class="o">)</span>, <span class="m">2</span>.0 m, Canada - Quebec, at least one grid missing
+INVERSE<span class="o">(</span>EPSG<span class="o">)</span>:9111, Inverse of NAD27 to NAD83 <span class="o">(</span><span class="m">9</span><span class="o">)</span>, <span class="m">1</span>.5 m, Canada - Saskatchewan, at least one grid missing
+unknown id, Ballpark geographic offset from NAD83 to NAD27, unknown accuracy, World, has ballpark transformation
+INVERSE<span class="o">(</span>EPSG<span class="o">)</span>:8555, Inverse of NAD27 to NAD83 <span class="o">(</span><span class="m">7</span><span class="o">)</span>, <span class="m">0</span>.15 m, USA - CONUS and GoM, at least one grid missing
+INVERSE<span class="o">(</span>EPSG<span class="o">)</span>:8549, Inverse of NAD27 to NAD83 <span class="o">(</span><span class="m">8</span><span class="o">)</span>, <span class="m">0</span>.5 m, USA - Alaska, at least one grid missing
+</pre></div>
+</div>
+<p>That was an easy case. Now let’s consider the transformation between the Australian
+CRS AGD84 and GDA2020. There is no direct transformation from AGD84 to GDA2020, or
+in the reverse direction, even when considering alternative geodetic CRS based on
+the underlying datums. PROJ will then do a cross-join in the coordinate_operation_view
+table to find the tuples (op1, op2) of coordinate operations such that:</p>
+<ul class="simple">
+<li><p>SOURCE_CRS = op1.source_crs AND op1.target_crs = op2.source_crs AND op2.target_crs = TARGET_CRS or</p></li>
+<li><p>SOURCE_CRS = op1.source_crs AND op1.target_crs = op2.target_crs AND op2.source_crs = TARGET_CRS or</p></li>
+<li><p>SOURCE_CRS = op1.target_crs AND op1.source_crs = op2.source_crs AND op2.target_crs = TARGET_CRS or</p></li>
+<li><p>SOURCE_CRS = op1.target_crs AND op1.source_crs = op2.target_crs AND op2.source_crs = TARGET_CRS</p></li>
+</ul>
+<p>Depending on which case is selected, op1 and op2 should be reversed, before
+being concatenated.</p>
+<p>This logic is implement by the <code class="docutils literal notranslate"><span class="pre">findsOpsInRegistryWithIntermediate()</span></code> method.</p>
+<p>Assuming that the proj-datumgrid-oceania package is installed, we get the
+following results for the AGD84 to GDA2020 coordinate operations lookup:</p>
+<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>$ projinfo -s AGD84 -t GDA2020 --spatial-test intersects -o PROJ
+
+Candidate operations found: <span class="m">4</span>
+-------------------------------------
+Operation No. <span class="m">1</span>:
+
+unknown id, AGD84 to GDA94 <span class="o">(</span><span class="m">5</span><span class="o">)</span> + GDA94 to GDA2020 <span class="o">(</span><span class="m">1</span><span class="o">)</span>, <span class="m">0</span>.11 m, Australia - AGD84
+
+PROJ string:
++proj<span class="o">=</span>pipeline +step +proj<span class="o">=</span>axisswap +order<span class="o">=</span><span class="m">2</span>,1 <span class="se">\</span>
+ +step +proj<span class="o">=</span>unitconvert +xy_in<span class="o">=</span>deg +xy_out<span class="o">=</span>rad <span class="se">\</span>
+ +step +proj<span class="o">=</span>hgridshift +grids<span class="o">=</span>National_84_02_07_01.gsb <span class="se">\</span>
+ +step +proj<span class="o">=</span>push +v_3 <span class="se">\</span>
+ +step +proj<span class="o">=</span>cart +ellps<span class="o">=</span>GRS80 <span class="se">\</span>
+ +step +proj<span class="o">=</span>helmert +x<span class="o">=</span><span class="m">0</span>.06155 +y<span class="o">=</span>-0.01087 +z<span class="o">=</span>-0.04019 <span class="se">\</span>
+ +rx<span class="o">=</span>-0.0394924 +ry<span class="o">=</span>-0.0327221 +rz<span class="o">=</span>-0.0328979 <span class="se">\</span>
+ +s<span class="o">=</span>-0.009994 +convention<span class="o">=</span>coordinate_frame <span class="se">\</span>
+ +step +inv +proj<span class="o">=</span>cart +ellps<span class="o">=</span>GRS80 <span class="se">\</span>
+ +step +proj<span class="o">=</span>pop +v_3 <span class="se">\</span>
+ +step +proj<span class="o">=</span>unitconvert +xy_in<span class="o">=</span>rad +xy_out<span class="o">=</span>deg <span class="se">\</span>
+ +step +proj<span class="o">=</span>axisswap +order<span class="o">=</span><span class="m">2</span>,1
+
+-------------------------------------
+Operation No. <span class="m">2</span>:
+
+unknown id, AGD84 to GDA94 <span class="o">(</span><span class="m">2</span><span class="o">)</span> + GDA94 to GDA2020 <span class="o">(</span><span class="m">1</span><span class="o">)</span>, <span class="m">1</span>.01 m, Australia - AGD84
+
+PROJ string:
++proj<span class="o">=</span>pipeline +step +proj<span class="o">=</span>axisswap +order<span class="o">=</span><span class="m">2</span>,1 <span class="se">\</span>
+ +step +proj<span class="o">=</span>unitconvert +xy_in<span class="o">=</span>deg +xy_out<span class="o">=</span>rad <span class="se">\</span>
+ +step +proj<span class="o">=</span>push +v_3 <span class="se">\</span>
+ +step +proj<span class="o">=</span>cart +ellps<span class="o">=</span>aust_SA <span class="se">\</span>
+ +step +proj<span class="o">=</span>helmert +x<span class="o">=</span>-117.763 +y<span class="o">=</span>-51.51 +z<span class="o">=</span><span class="m">139</span>.061 <span class="se">\</span>
+ +rx<span class="o">=</span>-0.292 +ry<span class="o">=</span>-0.443 +rz<span class="o">=</span>-0.277 +s<span class="o">=</span>-0.191 <span class="se">\</span>
+ +convention<span class="o">=</span>coordinate_frame <span class="se">\</span>
+ +step +proj<span class="o">=</span>helmert +x<span class="o">=</span><span class="m">0</span>.06155 +y<span class="o">=</span>-0.01087 +z<span class="o">=</span>-0.04019 <span class="se">\</span>
+ +rx<span class="o">=</span>-0.0394924 +ry<span class="o">=</span>-0.0327221 +rz<span class="o">=</span>-0.0328979 <span class="se">\</span>
+ +s<span class="o">=</span>-0.009994 +convention<span class="o">=</span>coordinate_frame <span class="se">\</span>
+ +step +inv +proj<span class="o">=</span>cart +ellps<span class="o">=</span>GRS80 <span class="se">\</span>
+ +step +proj<span class="o">=</span>pop +v_3 <span class="se">\</span>
+ +step +proj<span class="o">=</span>unitconvert +xy_in<span class="o">=</span>rad +xy_out<span class="o">=</span>deg <span class="se">\</span>
+ +step +proj<span class="o">=</span>axisswap +order<span class="o">=</span><span class="m">2</span>,1
+
+-------------------------------------
+Operation No. <span class="m">3</span>:
+
+unknown id, AGD84 to GDA94 <span class="o">(</span><span class="m">5</span><span class="o">)</span> + GDA94 to GDA2020 <span class="o">(</span><span class="m">2</span><span class="o">)</span>, <span class="m">0</span>.15 m, unknown domain of validity
+
+PROJ string:
++proj<span class="o">=</span>pipeline +step +proj<span class="o">=</span>axisswap +order<span class="o">=</span><span class="m">2</span>,1 <span class="se">\</span>
+ +step +proj<span class="o">=</span>unitconvert +xy_in<span class="o">=</span>deg +xy_out<span class="o">=</span>rad <span class="se">\</span>
+ +step +proj<span class="o">=</span>hgridshift +grids<span class="o">=</span>National_84_02_07_01.gsb <span class="se">\</span>
+ +step +proj<span class="o">=</span>hgridshift +grids<span class="o">=</span>GDA94_GDA2020_conformal_and_distortion.gsb <span class="se">\</span>
+ +step +proj<span class="o">=</span>unitconvert +xy_in<span class="o">=</span>rad +xy_out<span class="o">=</span>deg <span class="se">\</span>
+ +step +proj<span class="o">=</span>axisswap +order<span class="o">=</span><span class="m">2</span>,1
+
+-------------------------------------
+Operation No. <span class="m">4</span>:
+
+unknown id, AGD84 to GDA94 <span class="o">(</span><span class="m">5</span><span class="o">)</span> + GDA94 to GDA2020 <span class="o">(</span><span class="m">3</span><span class="o">)</span>, <span class="m">0</span>.15 m, unknown domain of validity
+
+PROJ string:
++proj<span class="o">=</span>pipeline +step +proj<span class="o">=</span>axisswap +order<span class="o">=</span><span class="m">2</span>,1 <span class="se">\</span>
+ +step +proj<span class="o">=</span>unitconvert +xy_in<span class="o">=</span>deg +xy_out<span class="o">=</span>rad <span class="se">\</span>
+ +step +proj<span class="o">=</span>hgridshift +grids<span class="o">=</span>National_84_02_07_01.gsb <span class="se">\</span>
+ +step +proj<span class="o">=</span>hgridshift +grids<span class="o">=</span>GDA94_GDA2020_conformal.gsb <span class="se">\</span>
+ +step +proj<span class="o">=</span>unitconvert +xy_in<span class="o">=</span>rad +xy_out<span class="o">=</span>deg <span class="se">\</span>
+ +step +proj<span class="o">=</span>axisswap +order<span class="o">=</span><span class="m">2</span>,1
+</pre></div>
+</div>
+<p>One can see that the selected intermediate CRS that has been used is GDA94.
+This is a completely novel behavior of PROJ 6 as opposed to the logic of PROJ.4
+where datum transformations implied using EPSG:4326 / WGS 84 has the mandatory
+datum hub. PROJ 6 no longer hardcodes it as the mandatory datum hub, and relies
+on the database to find the appropriate hub(s).
+Actually, WGS 84 has been considered during the above lookup, because there are
+transformations between AGD84 and WGS 84 and WGS 84 and GDA2020. However those
+have been discarded in a step which we did not mention previously: just after
+the initial filtering of results and their sorting, there is a final filtering
+that is done. In the list of sorted results, given two operations A and B that
+have the same area of use, if B has an accuracy lower than A, and A does not use
+grids, or all the needed grids are available, then B is discarded.</p>
+<p>If one forces the datum hub to be considered to be EPSG:4326, ones gets:</p>
+<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>$ projinfo -s AGD84 -t GDA2020 --spatial-test intersects --pivot-crs EPSG:4326 -o PROJ
+
+Candidate operations found: <span class="m">2</span>
+-------------------------------------
+Operation No. <span class="m">1</span>:
+
+unknown id, AGD84 to WGS <span class="m">84</span> <span class="o">(</span><span class="m">7</span><span class="o">)</span> + Inverse of GDA2020 to WGS <span class="m">84</span> <span class="o">(</span><span class="m">2</span><span class="o">)</span>, <span class="m">4</span> m, Australia - AGD84
+
+PROJ string:
++proj<span class="o">=</span>pipeline +step +proj<span class="o">=</span>axisswap +order<span class="o">=</span><span class="m">2</span>,1 <span class="se">\</span>
+ +step +proj<span class="o">=</span>unitconvert +xy_in<span class="o">=</span>deg +xy_out<span class="o">=</span>rad <span class="se">\</span>
+ +step +proj<span class="o">=</span>push +v_3 <span class="se">\</span>
+ +step +proj<span class="o">=</span>cart +ellps<span class="o">=</span>aust_SA <span class="se">\</span>
+ +step +proj<span class="o">=</span>helmert +x<span class="o">=</span>-117.763 +y<span class="o">=</span>-51.51 +z<span class="o">=</span><span class="m">139</span>.061 <span class="se">\</span>
+ +rx<span class="o">=</span>-0.292 +ry<span class="o">=</span>-0.443 +rz<span class="o">=</span>-0.277 <span class="se">\</span>
+ +s<span class="o">=</span>-0.191 +convention<span class="o">=</span>coordinate_frame <span class="se">\</span>
+ +step +inv +proj<span class="o">=</span>cart +ellps<span class="o">=</span>GRS80 <span class="se">\</span>
+ +step +proj<span class="o">=</span>pop +v_3 <span class="se">\</span>
+ +step +proj<span class="o">=</span>unitconvert +xy_in<span class="o">=</span>rad +xy_out<span class="o">=</span>deg <span class="se">\</span>
+ +step +proj<span class="o">=</span>axisswap +order<span class="o">=</span><span class="m">2</span>,1
+
+-------------------------------------
+Operation No. <span class="m">2</span>:
+
+unknown id, AGD84 to WGS <span class="m">84</span> <span class="o">(</span><span class="m">9</span><span class="o">)</span> + Inverse of GDA2020 to WGS <span class="m">84</span> <span class="o">(</span><span class="m">2</span><span class="o">)</span>, <span class="m">4</span> m, Australia - AGD84
+
+PROJ string:
++proj<span class="o">=</span>pipeline +step +proj<span class="o">=</span>axisswap +order<span class="o">=</span><span class="m">2</span>,1 <span class="se">\</span>
+ +step +proj<span class="o">=</span>unitconvert +xy_in<span class="o">=</span>deg +xy_out<span class="o">=</span>rad <span class="se">\</span>
+ +step +proj<span class="o">=</span>hgridshift +grids<span class="o">=</span>National_84_02_07_01.gsb <span class="se">\</span>
+ +step +proj<span class="o">=</span>unitconvert +xy_in<span class="o">=</span>rad +xy_out<span class="o">=</span>deg <span class="se">\</span>
+ +step +proj<span class="o">=</span>axisswap +order<span class="o">=</span><span class="m">2</span>,1
+</pre></div>
+</div>
+<p>Those operations are less accurate, since WGS 84 is assumed to be equivalent to
+GDA2020 with an accuracy of 4 metre. This is an instance demonstrating that using
+WGS 84 as a hub systematically can be sub-optimal.</p>
+<p>There are still situations where the attempt to find a hub CRS does not work,
+because there is no such hub. This can occur for example when transforming from
+GDA94 to the latest realization at time of writing of WGS 84, WGS 84 (G1762).
+There are transformations between WGS 84 (G1762). Using the above described
+techniques, we would only find one non-ballpark operation taking the route:
+1. Conversion from GDA94 (geog2D) to GDA94 (geocentric): synthetized by PROJ
+2. Inverse of ITRF2008 to GDA94 (1): from EPSG
+3. Inverse of WGS 84 (G1762) to ITRF2008 (1): from EPSG
+4. Conversion from WGS 84 (G1762) (geocentric) to WGS 84 (G1762): synthetized by PROJ</p>
+<p>This is not bad, but the global validity area of use is “Australia - onshore and EEZ”,
+whereas GDA94 has a larger area of use.
+There is another road that can be taken by going through GDA2020 instead of ITRF2008.
+The GDA94 to GDA2020 transformations operate on the respective geographic CRS,
+whereas GDA2020 to WGS 84 (G1762) operate on the geocentric CRS. Consequently,
+GDA2020 cannot be identifier as a hub by a “simple” self-join SQL request on
+the coordinate operation table. This requires to do the join based on the datum
+referenced by the source and target CRS of each operation rather than the
+source and target CRS themselves. When there is a match, PROJ inserts the required
+conversions between geographic and geocentric CRS to have a consistent concatenated
+operation, like the following:
+1. GDA94 to GDA2020 (1): from EPSG
+2. Conversion from GDA2020 (geog2D) to GDA2020 (geocentric): synthetized by PROJ
+3. GDA2020 to WGS 84 (G1762) (1): from EPSG
+4. Conversion from WGS 84 (G1762) (geocentric) to WGS 84 (G1762) (geog2D): synthetized by PROJ</p>
+</section>
+<section id="projected-crs-to-any-target-crs">
+<h2>Projected CRS to any target CRS<a class="headerlink" href="#projected-crs-to-any-target-crs" title="Permalink to this headline">¶</a></h2>
+<p>This actually extends to any Derived CRS, whose Projected CRS is a well-known
+particular case. Such transformations are done in 2 steps:</p>
+<ol class="arabic simple">
+<li><p>Use the inverse conversion of the derived CRS to its base CRS, typically an
+inverse map projection.</p></li>
+<li><p>Find transformations from this base CRS to the target CRS. If the base CRS
+is the target CRS, this step can be skipped.</p></li>
+</ol>
+<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>$ projinfo -s EPSG:32631 -t RGF93
+
+Candidate operations found: <span class="m">1</span>
+-------------------------------------
+Operation No. <span class="m">1</span>:
+
+unknown id, Inverse of UTM zone 31N + Inverse of RGF93 to WGS <span class="m">84</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span>, <span class="m">1</span> m, France
+
+PROJ string:
++proj<span class="o">=</span>pipeline +step +inv +proj<span class="o">=</span>utm +zone<span class="o">=</span><span class="m">31</span> +ellps<span class="o">=</span>WGS84 +step +proj<span class="o">=</span>unitconvert +xy_in<span class="o">=</span>rad +xy_out<span class="o">=</span>deg +step +proj<span class="o">=</span>axisswap +order<span class="o">=</span><span class="m">2</span>,1
+</pre></div>
+</div>
+<p>This is implemented by the <code class="docutils literal notranslate"><span class="pre">createOperationsDerivedTo</span></code> method</p>
+<p>For the symmetric case, source CRS to a derived CRS, the above algorithm is applied
+by switching the source and target CRS, and then inverting the resulting operation(s).
+This is mostly a matter of avoiding to write very similar code twice. This logic
+is also applied to all below cases when considering the transformation between 2 different
+types of objects.</p>
+</section>
+<section id="vertical-crs-to-a-geographic-crs">
+<span id="verttogeog"></span><h2>Vertical CRS to a Geographic CRS<a class="headerlink" href="#vertical-crs-to-a-geographic-crs" title="Permalink to this headline">¶</a></h2>
+<p>Such transformation is normally not meant as being used as standalone by PROJ
+users, but as an internal computation step of a Compound CRS to a target CRS.</p>
+<p>In cases where we are lucky, the PROJ database will have a transformation registered
+between those:</p>
+<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>$ projinfo -s <span class="s2">&quot;NAVD88 height&quot;</span> -t <span class="s2">&quot;NAD83(2011)&quot;</span> -o PROJ --spatial-test intersects
+Candidate operations found: <span class="m">11</span>
+-------------------------------------
+Operation No. <span class="m">1</span>:
+
+INVERSE<span class="o">(</span>DERIVED_FROM<span class="o">(</span>EPSG<span class="o">))</span>:9229, Inverse of NAD83<span class="o">(</span><span class="m">2011</span><span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">3</span><span class="o">)</span>, <span class="m">0</span>.015 m, USA - CONUS - onshore
+
+PROJ string:
++proj<span class="o">=</span>vgridshift +grids<span class="o">=</span>g2018u0.gtx +multiplier<span class="o">=</span><span class="m">1</span>
+</pre></div>
+</div>
+<p>But in cases where there is no match, the <code class="docutils literal notranslate"><span class="pre">createOperationsVertToGeog</span></code> method
+will be used to synthetize a ballpark vertical transformation, just taking care
+of unit changes, and axis reversal in case the vertical CRS was a depth rather than
+a height. Of course the results of such an operation are questionable, hence the
+ballpark qualifier and a unknown accuracy advertized for such an operation.</p>
+</section>
+<section id="vertical-crs-to-a-vertical-crs">
+<h2>Vertical CRS to a Vertical CRS<a class="headerlink" href="#vertical-crs-to-a-vertical-crs" title="Permalink to this headline">¶</a></h2>
+<p>Overall logic is similar to the above case. There might be direct operations in
+the PROJ database, involving grid transformations or simple offsets. The fallback
+case is to synthetize a ballpark transformation.</p>
+<p>This is implemented by the <code class="docutils literal notranslate"><span class="pre">createOperationsVertToVert</span></code> method</p>
+<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>$ projinfo -s <span class="s2">&quot;NGVD29 depth (ftUS)&quot;</span> -t <span class="s2">&quot;NAVD88 height&quot;</span> --spatial-test intersects -o PROJ
+
+Candidate operations found: <span class="m">3</span>
+-------------------------------------
+Operation No. <span class="m">1</span>:
+
+unknown id, Inverse of NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NGVD29 depth <span class="o">(</span>ftUS<span class="o">)</span> + NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NGVD29 height <span class="o">(</span>m<span class="o">)</span> + NGVD29 height <span class="o">(</span>m<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">3</span><span class="o">)</span>, <span class="m">0</span>.02 m, USA - CONUS east of <span class="m">89</span>°W - onshore
+
+PROJ string:
++proj<span class="o">=</span>pipeline +step +proj<span class="o">=</span>axisswap +order<span class="o">=</span><span class="m">1</span>,2,-3 +step +proj<span class="o">=</span>unitconvert +z_in<span class="o">=</span>us-ft +z_out<span class="o">=</span>m +step +proj<span class="o">=</span>vgridshift +grids<span class="o">=</span>vertcone.gtx +multiplier<span class="o">=</span><span class="m">0</span>.001
+
+-------------------------------------
+Operation No. <span class="m">2</span>:
+
+unknown id, Inverse of NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NGVD29 depth <span class="o">(</span>ftUS<span class="o">)</span> + NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NGVD29 height <span class="o">(</span>m<span class="o">)</span> + NGVD29 height <span class="o">(</span>m<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">2</span><span class="o">)</span>, <span class="m">0</span>.02 m, USA - CONUS <span class="m">89</span>°W-107°W - onshore
+
+PROJ string:
++proj<span class="o">=</span>pipeline +step +proj<span class="o">=</span>axisswap +order<span class="o">=</span><span class="m">1</span>,2,-3 +step +proj<span class="o">=</span>unitconvert +z_in<span class="o">=</span>us-ft +z_out<span class="o">=</span>m +step +proj<span class="o">=</span>vgridshift +grids<span class="o">=</span>vertconc.gtx +multiplier<span class="o">=</span><span class="m">0</span>.001
+
+-------------------------------------
+Operation No. <span class="m">3</span>:
+
+unknown id, Inverse of NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NGVD29 depth <span class="o">(</span>ftUS<span class="o">)</span> + NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NGVD29 height <span class="o">(</span>m<span class="o">)</span> + NGVD29 height <span class="o">(</span>m<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">1</span><span class="o">)</span>, <span class="m">0</span>.02 m, USA - CONUS west of <span class="m">107</span>°W - onshore
+
+PROJ string:
++proj<span class="o">=</span>pipeline +step +proj<span class="o">=</span>axisswap +order<span class="o">=</span><span class="m">1</span>,2,-3 +step +proj<span class="o">=</span>unitconvert +z_in<span class="o">=</span>us-ft +z_out<span class="o">=</span>m +step +proj<span class="o">=</span>vgridshift +grids<span class="o">=</span>vertconw.gtx +multiplier<span class="o">=</span><span class="m">0</span>.001
+</pre></div>
+</div>
+</section>
+<section id="compound-crs-to-a-geographic-crs">
+<h2>Compound CRS to a Geographic CRS<a class="headerlink" href="#compound-crs-to-a-geographic-crs" title="Permalink to this headline">¶</a></h2>
+<p>A typical example of a Compound CRS is a CRS made of a geographic or projected CRS
+as the horizontal component, and a vertical CRS. E.g. “NAD83 + NAVD88 height”</p>
+<p>When the horizontal component of the compound source CRS is a projected CRS, we
+first look for the operation from this source CRS to another compound CRS made
+of the geographic CRS base of the projected CRS,
+like “NAD83 / California zone 1 (ftUS) + NAVD88 height” to “NAD83 + NAVD88 height”,
+which ultimately goes to one of the above described case. Then we can consider
+the transformation from a compound CRS made of a geographic CRS to another geographic CRS.</p>
+<p>It first starts by the vertical transformations from the vertical CRS of the
+source compound CRS to the target geographic CRS, using the strategy detailed
+in <a class="reference internal" href="#verttogeog"><span class="std std-ref">Vertical CRS to a Geographic CRS</span></a></p>
+<p>What we did not mention is that when there is not a transformation registered
+between the vertical CRS and the target geographic CRS, PROJ attempts to find
+transformations between that vertical CRS and any other geographic CRS. This is
+clearly an approximation.
+If the research of the vertical CRS to the target geographic CRS resulted in
+operations that use grids that are not available, as another approximation, we
+research operations from the vertical CRS to the source geographic CRS for the
+vertical component.</p>
+<p>Once we got those more or less accurate vertical transformations, we must consider
+the horizontal transformation(s). The algorithm iterates over all found vertical
+transformations and look for their target geographic CRS. This will be used as
+the interpolation CRS for horizontal transformations. PROJ will then look for
+available transformations from the source geographic CRS to the interpolation CRS
+and from the interpolation CRS to the target geographic CRS. There is then a
+3-level loop to create the final set of operations chaining together:</p>
+<ul class="simple">
+<li><p>the horizontal transformation from the source geographic CRS to the interpolation CRS</p></li>
+<li><p>the vertical transformation from the source vertical CRS to the interpolation CRS</p></li>
+<li><p>the horizontal transformation from the interpolation CRS to the target geographic CRS.</p></li>
+</ul>
+<p>This is implemented by the <code class="docutils literal notranslate"><span class="pre">createOperationsCompoundToGeog</span></code> method</p>
+<p>Example:</p>
+<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>$ projinfo -s <span class="s2">&quot;NAD83(NSRS2007) + NAVD88 height&quot;</span> -t <span class="s2">&quot;WGS 84 (G1762)&quot;</span> --spatial-test intersects --summary
+
+Candidate operations found: <span class="m">21</span>
+unknown id, Inverse of NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">1</span><span class="o">)</span> + NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + WGS <span class="m">84</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span>, <span class="m">3</span>.05 m, USA - CONUS - onshore
+unknown id, Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">7</span><span class="o">)</span> + NAD83<span class="o">(</span>HARN<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + WGS <span class="m">84</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span>, <span class="m">3</span>.15 m, USA - CONUS south of <span class="m">41</span>°N, <span class="m">95</span>°W to <span class="m">78</span>°W - onshore
+unknown id, Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">7</span><span class="o">)</span> + NAD83<span class="o">(</span>HARN<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">3</span><span class="o">)</span> + WGS <span class="m">84</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span>, <span class="m">3</span>.15 m, USA - CONUS south of <span class="m">41</span>°N, <span class="m">95</span>°W to <span class="m">78</span>°W - onshore
+unknown id, Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">6</span><span class="o">)</span> + NAD83<span class="o">(</span>HARN<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + WGS <span class="m">84</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span>, <span class="m">3</span>.15 m, USA - CONUS south of <span class="m">41</span>°N, <span class="m">112</span>°W to <span class="m">95</span>°W - onshore
+unknown id, Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">6</span><span class="o">)</span> + NAD83<span class="o">(</span>HARN<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">3</span><span class="o">)</span> + WGS <span class="m">84</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span>, <span class="m">3</span>.15 m, USA - CONUS south of <span class="m">41</span>°N, <span class="m">112</span>°W to <span class="m">95</span>°W - onshore
+unknown id, Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">2</span><span class="o">)</span> + NAD83<span class="o">(</span>HARN<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + WGS <span class="m">84</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span>, <span class="m">3</span>.15 m, USA - CONUS north of <span class="m">41</span>°N, <span class="m">112</span>°W to <span class="m">95</span>°W
+unknown id, Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">2</span><span class="o">)</span> + NAD83<span class="o">(</span>HARN<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">3</span><span class="o">)</span> + WGS <span class="m">84</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span>, <span class="m">3</span>.15 m, USA - CONUS north of <span class="m">41</span>°N, <span class="m">112</span>°W to <span class="m">95</span>°W
+unknown id, Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">3</span><span class="o">)</span> + NAD83<span class="o">(</span>HARN<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + WGS <span class="m">84</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span>, <span class="m">3</span>.15 m, USA - CONUS north of <span class="m">41</span>°N, <span class="m">95</span>°W to <span class="m">78</span>°W
+unknown id, Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">3</span><span class="o">)</span> + NAD83<span class="o">(</span>HARN<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">3</span><span class="o">)</span> + WGS <span class="m">84</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span>, <span class="m">3</span>.15 m, USA - CONUS north of <span class="m">41</span>°N, <span class="m">95</span>°W to <span class="m">78</span>°W
+unknown id, Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">5</span><span class="o">)</span> + NAD83<span class="o">(</span>HARN<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + WGS <span class="m">84</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span>, <span class="m">3</span>.15 m, USA - CONUS south of <span class="m">41</span>°N, west of <span class="m">112</span>°W - onshore
+unknown id, Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">5</span><span class="o">)</span> + NAD83<span class="o">(</span>HARN<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">3</span><span class="o">)</span> + WGS <span class="m">84</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span>, <span class="m">3</span>.15 m, USA - CONUS south of <span class="m">41</span>°N, west of <span class="m">112</span>°W - onshore
+unknown id, Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">1</span><span class="o">)</span> + NAD83<span class="o">(</span>HARN<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + WGS <span class="m">84</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span>, <span class="m">3</span>.15 m, USA - CONUS north of <span class="m">41</span>°N, west of <span class="m">112</span>°W - onshore
+unknown id, Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">1</span><span class="o">)</span> + NAD83<span class="o">(</span>HARN<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">3</span><span class="o">)</span> + WGS <span class="m">84</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span>, <span class="m">3</span>.15 m, USA - CONUS north of <span class="m">41</span>°N, west of <span class="m">112</span>°W - onshore
+unknown id, Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">4</span><span class="o">)</span> + NAD83<span class="o">(</span>HARN<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + WGS <span class="m">84</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span>, <span class="m">3</span>.15 m, USA - CONUS north of <span class="m">41</span>°N, east of <span class="m">78</span>°W - onshore
+unknown id, Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">4</span><span class="o">)</span> + NAD83<span class="o">(</span>HARN<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">3</span><span class="o">)</span> + WGS <span class="m">84</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span>, <span class="m">3</span>.15 m, USA - CONUS north of <span class="m">41</span>°N, east of <span class="m">78</span>°W - onshore
+unknown id, Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">8</span><span class="o">)</span> + NAD83<span class="o">(</span>HARN<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + WGS <span class="m">84</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span>, <span class="m">3</span>.15 m, USA - CONUS south of <span class="m">41</span>°N, east of <span class="m">78</span>°W - onshore
+unknown id, Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Inverse of NAD83<span class="o">(</span>HARN<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">8</span><span class="o">)</span> + NAD83<span class="o">(</span>HARN<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">3</span><span class="o">)</span> + WGS <span class="m">84</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span>, <span class="m">3</span>.15 m, USA - CONUS south of <span class="m">41</span>°N, east of <span class="m">78</span>°W - onshore
+unknown id, Ballpark geographic offset from NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> to NAD83<span class="o">(</span>FBN<span class="o">)</span> + Inverse of NAD83<span class="o">(</span>FBN<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Ballpark geographic offset from NAD83<span class="o">(</span>FBN<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span>, unknown accuracy, USA - CONUS - onshore, has ballpark transformation
+unknown id, Ballpark geographic offset from NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> to NAD83<span class="o">(</span><span class="m">2011</span><span class="o">)</span> + Inverse of NAD83<span class="o">(</span><span class="m">2011</span><span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">3</span><span class="o">)</span> + Ballpark geographic offset from NAD83<span class="o">(</span><span class="m">2011</span><span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span>, unknown accuracy, USA - CONUS - onshore, has ballpark transformation
+unknown id, Ballpark geographic offset from NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> to NAD83<span class="o">(</span><span class="m">2011</span><span class="o">)</span> + Inverse of NAD83<span class="o">(</span><span class="m">2011</span><span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">3</span><span class="o">)</span> + Conversion from NAD83<span class="o">(</span><span class="m">2011</span><span class="o">)</span> <span class="o">(</span>geog2D<span class="o">)</span> to NAD83<span class="o">(</span><span class="m">2011</span><span class="o">)</span> <span class="o">(</span>geocentric<span class="o">)</span> + Inverse of ITRF2008 to NAD83<span class="o">(</span><span class="m">2011</span><span class="o">)</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Inverse of WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span> to ITRF2008 <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Conversion from WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span> <span class="o">(</span>geocentric<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span> <span class="o">(</span>geog2D<span class="o">)</span>, unknown accuracy, USA - CONUS - onshore, has ballpark transformation
+unknown id, NAD83<span class="o">(</span>NSRS2007<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + WGS <span class="m">84</span> to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span> + Transformation from NAVD88 height to WGS <span class="m">84</span> <span class="o">(</span>G1762<span class="o">)</span> <span class="o">(</span>ballpark vertical transformation, without ellipsoid height to vertical height correction<span class="o">)</span>, unknown accuracy, USA - CONUS and Alaska<span class="p">;</span> PRVI, has ballpark transformation
+</pre></div>
+</div>
+</section>
+<section id="compoundcrs-to-compoundcrs">
+<h2>CompoundCRS to CompoundCRS<a class="headerlink" href="#compoundcrs-to-compoundcrs" title="Permalink to this headline">¶</a></h2>
+<p>There is some similarity with the previous paragraph. We first research the
+vertical transformations between the two vertical CRS.</p>
+<ol class="arabic">
+<li><p>If there is such a transformation, be it direct, or if both vertical CRS
+relate to a common intermediate CRS.
+If it has a registered interpolation geographic CRS, then it is used.
+Otherwise we fallback to the geographic CRS of the source CRS.</p>
+<p>Finally, a 3-level loop to create the final set of operations chaining together:</p>
+<ul class="simple">
+<li><p>the horizontal transformation from the source CRS to the interpolation CRS</p></li>
+<li><p>the vertical transformation</p></li>
+<li><p>the horizontal transformation from the interpolation CRS to the target CRS.</p></li>
+</ul>
+<blockquote>
+<div><p>Example:</p>
+<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>$ projinfo -s <span class="s2">&quot;NAD27 + NGVD29 height (ftUS)&quot;</span> -t <span class="s2">&quot;NAD83 + NAVD88 height&quot;</span> --spatial-test intersects --summary
+
+Candidate operations found: <span class="m">20</span>
+unknown id, NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">3</span><span class="o">)</span> + NAD27 to NAD83 <span class="o">(</span><span class="m">1</span><span class="o">)</span>, <span class="m">0</span>.17 m, USA - CONUS east of <span class="m">89</span>°W - onshore
+unknown id, NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">2</span><span class="o">)</span> + NAD27 to NAD83 <span class="o">(</span><span class="m">1</span><span class="o">)</span>, <span class="m">0</span>.17 m, USA - CONUS <span class="m">89</span>°W-107°W - onshore
+unknown id, NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">1</span><span class="o">)</span> + NAD27 to NAD83 <span class="o">(</span><span class="m">1</span><span class="o">)</span>, <span class="m">0</span>.17 m, USA - CONUS west of <span class="m">107</span>°W - onshore
+unknown id, NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">3</span><span class="o">)</span> + NAD27 to NAD83 <span class="o">(</span><span class="m">3</span><span class="o">)</span>, <span class="m">1</span>.02 m, unknown domain of validity
+unknown id, NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">2</span><span class="o">)</span> + NAD27 to NAD83 <span class="o">(</span><span class="m">3</span><span class="o">)</span>, <span class="m">1</span>.02 m, unknown domain of validity
+unknown id, NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">1</span><span class="o">)</span> + NAD27 to NAD83 <span class="o">(</span><span class="m">3</span><span class="o">)</span>, <span class="m">1</span>.02 m, unknown domain of validity
+unknown id, NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">3</span><span class="o">)</span> + NAD27 to NAD83 <span class="o">(</span><span class="m">5</span><span class="o">)</span>, <span class="m">1</span>.02 m, unknown domain of validity, at least one grid missing
+unknown id, NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">3</span><span class="o">)</span> + NAD27 to NAD83 <span class="o">(</span><span class="m">6</span><span class="o">)</span>, <span class="m">1</span>.52 m, unknown domain of validity, at least one grid missing
+unknown id, NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">2</span><span class="o">)</span> + NAD27 to NAD83 <span class="o">(</span><span class="m">9</span><span class="o">)</span>, <span class="m">1</span>.52 m, unknown domain of validity, at least one grid missing
+unknown id, NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">1</span><span class="o">)</span> + NAD27 to NAD83 <span class="o">(</span><span class="m">9</span><span class="o">)</span>, <span class="m">1</span>.52 m, unknown domain of validity, at least one grid missing
+unknown id, NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">3</span><span class="o">)</span> + Ballpark geographic offset from NAD27 to NAD83, unknown accuracy, USA - CONUS east of <span class="m">89</span>°W - onshore, has ballpark transformation
+unknown id, NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">2</span><span class="o">)</span> + Ballpark geographic offset from NAD27 to NAD83, unknown accuracy, USA - CONUS <span class="m">89</span>°W-107°W - onshore, has ballpark transformation
+unknown id, NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Ballpark geographic offset from NAD27 to NAD83, unknown accuracy, USA - CONUS west of <span class="m">107</span>°W - onshore, has ballpark transformation
+unknown id, Transformation from NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span>ballpark vertical transformation<span class="o">)</span> + NAD27 to NAD83 <span class="o">(</span><span class="m">1</span><span class="o">)</span>, unknown accuracy, USA - CONUS including EEZ, has ballpark transformation
+unknown id, Transformation from NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span>ballpark vertical transformation<span class="o">)</span> + NAD27 to NAD83 <span class="o">(</span><span class="m">3</span><span class="o">)</span>, unknown accuracy, Canada, has ballpark transformation
+unknown id, Transformation from NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span>ballpark vertical transformation<span class="o">)</span> + NAD27 to NAD83 <span class="o">(</span><span class="m">4</span><span class="o">)</span>, unknown accuracy, Canada - NAD27, has ballpark transformation
+unknown id, Transformation from NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span>ballpark vertical transformation<span class="o">)</span> + NAD27 to NAD83 <span class="o">(</span><span class="m">5</span><span class="o">)</span>, unknown accuracy, Canada - Quebec, has ballpark transformation, at least one grid missing
+unknown id, Transformation from NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span>ballpark vertical transformation<span class="o">)</span> + NAD27 to NAD83 <span class="o">(</span><span class="m">6</span><span class="o">)</span>, unknown accuracy, Canada - Quebec, has ballpark transformation, at least one grid missing
+unknown id, Transformation from NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span>ballpark vertical transformation<span class="o">)</span> + NAD27 to NAD83 <span class="o">(</span><span class="m">9</span><span class="o">)</span>, unknown accuracy, Canada - Saskatchewan, has ballpark transformation, at least one grid missing
+unknown id, Transformation from NGVD29 height <span class="o">(</span>ftUS<span class="o">)</span> to NAVD88 height <span class="o">(</span>ballpark vertical transformation<span class="o">)</span> + Ballpark geographic offset from NAD27 to NAD83, unknown accuracy, World, has ballpark transformation
+</pre></div>
+</div>
+</div></blockquote>
+</li>
+<li><p>Otherwise, when there is no such transformation, we decompose into 3 steps:</p>
+<ul class="simple">
+<li><p>transform from the source CRS to the geographic 3D CRS corresponding to it</p></li>
+<li><p>transform from the geographic 3D CRS corresponding to the source CRS to the
+geographic 3D CRS corresponding to the target CRS</p></li>
+<li><p>transform from the geographic 3D CRS corresponding to the target CRS to the
+target CRS.</p></li>
+</ul>
+<blockquote>
+<div><p>Example:</p>
+<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>$ projinfo -s <span class="s2">&quot;WGS 84 + EGM96 height&quot;</span> -t <span class="s2">&quot;ETRS89 + Belfast height&quot;</span> --spatial-test intersects --summary
+
+Candidate operations found: <span class="m">7</span>
+unknown id, Inverse of WGS <span class="m">84</span> to EGM96 height <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Inverse of ETRS89 to WGS <span class="m">84</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + ETRS89 to Belfast height <span class="o">(</span><span class="m">2</span><span class="o">)</span>, <span class="m">2</span>.014 m, UK - Northern Ireland - onshore
+unknown id, Inverse of WGS <span class="m">84</span> to EGM96 height <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Inverse of ETRS89 to WGS <span class="m">84</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span> + ETRS89 to Belfast height <span class="o">(</span><span class="m">1</span><span class="o">)</span>, <span class="m">2</span>.03 m, UK - Northern Ireland - onshore, at least one grid missing
+unknown id, Inverse of WGS <span class="m">84</span> to EGM96 height <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Null geographic offset from WGS <span class="m">84</span> <span class="o">(</span>geog3D<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span>geog2D<span class="o">)</span> + Inverse of OSGB <span class="m">1936</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">4</span><span class="o">)</span> + OSGB <span class="m">1936</span> to ETRS89 <span class="o">(</span><span class="m">2</span><span class="o">)</span> + Null geographic offset from ETRS89 <span class="o">(</span>geog2D<span class="o">)</span> to ETRS89 <span class="o">(</span>geog3D<span class="o">)</span> + ETRS89 to Belfast height <span class="o">(</span><span class="m">2</span><span class="o">)</span>, <span class="m">19</span>.044 m, unknown domain of validity
+unknown id, Inverse of WGS <span class="m">84</span> to EGM96 height <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Null geographic offset from WGS <span class="m">84</span> <span class="o">(</span>geog3D<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span>geog2D<span class="o">)</span> + Inverse of OSGB <span class="m">1936</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">2</span><span class="o">)</span> + OSGB <span class="m">1936</span> to ETRS89 <span class="o">(</span><span class="m">2</span><span class="o">)</span> + Null geographic offset from ETRS89 <span class="o">(</span>geog2D<span class="o">)</span> to ETRS89 <span class="o">(</span>geog3D<span class="o">)</span> + ETRS89 to Belfast height <span class="o">(</span><span class="m">2</span><span class="o">)</span>, <span class="m">11</span>.044 m, unknown domain of validity
+unknown id, Inverse of WGS <span class="m">84</span> to EGM96 height <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Null geographic offset from WGS <span class="m">84</span> <span class="o">(</span>geog3D<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span>geog2D<span class="o">)</span> + Inverse of TM75 to WGS <span class="m">84</span> <span class="o">(</span><span class="m">2</span><span class="o">)</span> + TM75 to ETRS89 <span class="o">(</span><span class="m">3</span><span class="o">)</span> + Null geographic offset from ETRS89 <span class="o">(</span>geog2D<span class="o">)</span> to ETRS89 <span class="o">(</span>geog3D<span class="o">)</span> + ETRS89 to Belfast height <span class="o">(</span><span class="m">2</span><span class="o">)</span>, <span class="m">2</span>.424 m, UK - Northern Ireland - onshore, at least one grid missing
+unknown id, Inverse of WGS <span class="m">84</span> to EGM96 height <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Null geographic offset from WGS <span class="m">84</span> <span class="o">(</span>geog3D<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span>geog2D<span class="o">)</span> + Inverse of TM75 to WGS <span class="m">84</span> <span class="o">(</span><span class="m">2</span><span class="o">)</span> + TM75 to ETRS89 <span class="o">(</span><span class="m">3</span><span class="o">)</span> + Null geographic offset from ETRS89 <span class="o">(</span>geog2D<span class="o">)</span> to ETRS89 <span class="o">(</span>geog3D<span class="o">)</span> + ETRS89 to Belfast height <span class="o">(</span><span class="m">1</span><span class="o">)</span>, <span class="m">2</span>.44 m, UK - Northern Ireland - onshore, at least one grid missing
+unknown id, Inverse of WGS <span class="m">84</span> to EGM96 height <span class="o">(</span><span class="m">1</span><span class="o">)</span> + Null geographic offset from WGS <span class="m">84</span> <span class="o">(</span>geog3D<span class="o">)</span> to WGS <span class="m">84</span> <span class="o">(</span>geog2D<span class="o">)</span> + Inverse of OSGB <span class="m">1936</span> to WGS <span class="m">84</span> <span class="o">(</span><span class="m">4</span><span class="o">)</span> + OSGB <span class="m">1936</span> to ETRS89 <span class="o">(</span><span class="m">2</span><span class="o">)</span> + Null geographic offset from ETRS89 <span class="o">(</span>geog2D<span class="o">)</span> to ETRS89 <span class="o">(</span>geog3D<span class="o">)</span> + ETRS89 to Belfast height <span class="o">(</span><span class="m">1</span><span class="o">)</span>, <span class="m">19</span>.06 m, unknown domain of validity, at least one grid missing
+</pre></div>
+</div>
+</div></blockquote>
+</li>
+</ol>
+<p>This is implemented by the <code class="docutils literal notranslate"><span class="pre">createOperationsCompoundToCompound</span></code> method</p>
+</section>
+<section id="when-the-source-or-target-crs-is-a-boundcrs">
+<h2>When the source or target CRS is a BoundCRS<a class="headerlink" href="#when-the-source-or-target-crs-is-a-boundcrs" title="Permalink to this headline">¶</a></h2>
+<p>The BoundCRS concept is an hybrid concept where a CRS is linked to a transformation
+from it to a hub CRS, typically WGS 84. This is a long-time practice in PROJ.4
+strings with the <code class="docutils literal notranslate"><span class="pre">+towgs84</span></code>, <code class="docutils literal notranslate"><span class="pre">+nadgrids</span></code> and <code class="docutils literal notranslate"><span class="pre">+geoidgrids</span></code> keywords, or the
+<code class="docutils literal notranslate"><span class="pre">TOWGS84[]</span></code> node of WKT 1. When encountering those attributes when parsing
+a CRS string, PROJ will create a BoundCRS object capturing this transformation.
+A BoundCRS object can also be provided with a WKT2 string, and in that case with
+a hub CRS being potentially different from WGS 84.</p>
+<p>Let’s consider the case of a transformation between a BoundCRS
+(“+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000
++ellps=airy +towgs84=446.448,-125.157,542.06,0.15,0.247,0.842,-20.489 +units=m”
+which used to be the PROJ.4 definition of “OSGB 1936 / British National Grid”)
+and a target Geographic CRS, ETRS89.</p>
+<p>We apply the following steps:</p>
+<ul class="simple">
+<li><p>transform from the base of the source CRS (that is the CRS wrapped by BoundCRS,
+here a ProjectedCRS) to the geographic CRS of this base CRS</p></li>
+<li><p>apply the transformation of the BoundCRS to go from the geographic CRS of this base CRS
+to the hub CRS of the BoundCRS, in that instance WGS 84.</p></li>
+<li><p>apply a transformation from the hub CRS to the target CRS.</p></li>
+</ul>
+<p>This is implemented by the <code class="docutils literal notranslate"><span class="pre">createOperationsBoundToGeog</span></code> method</p>
+<p>Example:</p>
+<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>$ projinfo -s <span class="s2">&quot;+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +towgs84=446.448,-125.157,542.06,0.15,0.247,0.842,-20.489 +units=m +type=crs&quot;</span> -t ETRS89 -o PROJ
+
+Candidate operations found: <span class="m">1</span>
+-------------------------------------
+Operation No. <span class="m">1</span>:
+
+unknown id, Inverse of unknown + Transformation from unknown to WGS84 + Inverse of ETRS89 to WGS <span class="m">84</span> <span class="o">(</span><span class="m">1</span><span class="o">)</span>, unknown accuracy, Europe - ETRS89
+
+PROJ string:
++proj<span class="o">=</span>pipeline +step +inv +proj<span class="o">=</span>tmerc +lat_0<span class="o">=</span><span class="m">49</span> +lon_0<span class="o">=</span>-2 +k<span class="o">=</span><span class="m">0</span>.9996012717 +x_0<span class="o">=</span><span class="m">400000</span> +y_0<span class="o">=</span>-100000 +ellps<span class="o">=</span>airy +step +proj<span class="o">=</span>push +v_3 +step +proj<span class="o">=</span>cart +ellps<span class="o">=</span>airy +step +proj<span class="o">=</span>helmert +x<span class="o">=</span><span class="m">446</span>.448 +y<span class="o">=</span>-125.157 +z<span class="o">=</span><span class="m">542</span>.06 +rx<span class="o">=</span><span class="m">0</span>.15 +ry<span class="o">=</span><span class="m">0</span>.247 +rz<span class="o">=</span><span class="m">0</span>.842 +s<span class="o">=</span>-20.489 +convention<span class="o">=</span>position_vector +step +inv +proj<span class="o">=</span>cart +ellps<span class="o">=</span>GRS80 +step +proj<span class="o">=</span>pop +v_3 +step +proj<span class="o">=</span>unitconvert +xy_in<span class="o">=</span>rad +xy_out<span class="o">=</span>deg +step +proj<span class="o">=</span>axisswap +order<span class="o">=</span><span class="m">2</span>,1
+</pre></div>
+</div>
+<p>There are other situations with BoundCRS, involving vertical transformations,
+or transforming to other objects than a geographic CRS, but the curious reader
+will have to inspect the code for the actual gory details.</p>
+</section>
+</section>
+
+
+ </div>
+ </div>
+ <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer">
+ <a href="pipeline.html" class="btn btn-neutral float-left" title="The pipeline operator" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
+ <a href="../resource_files.html" class="btn btn-neutral float-right" title="Resource files" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
+ </div>
+
+ <hr/>
+
+ <div role="contentinfo">
+ <p>&#169; Copyright 1983-2022.
+ <span class="lastupdated">Last updated on 22 Mar 2022.
+ </span></p>
+ </div>
+
+ Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
+ <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
+ provided by <a href="https://readthedocs.org">Read the Docs</a>.
+
+
+</footer>
+ </div>
+ </div>
+ </section>
+ </div>
+ <script>
+ jQuery(function () {
+ SphinxRtdTheme.Navigation.enable(true);
+ });
+ </script>
+
+</body>
+</html> \ No newline at end of file