Skip to content

Commit

Permalink
Remove usage of built-in EPSG concatenated operations and complexitie…
Browse files Browse the repository at this point in the history
…s surrounding them, can work them out at runtime
  • Loading branch information
dvdoug committed Sep 25, 2021
1 parent 74074d8 commit 0f595a1
Show file tree
Hide file tree
Showing 16 changed files with 207 additions and 1,962 deletions.
2 changes: 1 addition & 1 deletion docs/coordinate_conversions_easy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ between almost any two CRSs is possible as long as they have a common link.
.. note::

Calculating every single possible permutation of chain between two CRSs is very computationally expensive
and so for practicality PHPCoord limits the chain depth to 5 (i.e. the source CRS, 3 intermediate CRSs and
and so for practicality PHPCoord limits the chain depth to 7 (i.e. the source CRS, 5 intermediate CRSs and
the target CRS). If you know a transformation should be possible, but PHPCoord cannot find it you may wish
to try an explicit 2-stage conversion (e.g. source to WGS84, WGS84 to target).

Expand Down
54 changes: 29 additions & 25 deletions src/CoordinateOperation/AutoConversion.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
*/
trait AutoConversion
{
private int $maxChainDepth = 5; // if traits could have constants...
private int $maxChainDepth = 7; // if traits could have constants...

protected static array $methodsThatRequireCoordinateEpoch = [ // if traits could have constants...
CoordinateOperationMethods::EPSG_TIME_DEPENDENT_COORDINATE_FRAME_ROTATION_GEOCEN => CoordinateOperationMethods::EPSG_TIME_DEPENDENT_COORDINATE_FRAME_ROTATION_GEOCEN,
Expand All @@ -56,7 +56,9 @@ trait AutoConversion
CoordinateOperationMethods::EPSG_TIME_SPECIFIC_POSITION_VECTOR_TRANSFORM_GEOCEN => CoordinateOperationMethods::EPSG_TIME_SPECIFIC_POSITION_VECTOR_TRANSFORM_GEOCEN,
];

private static array $pathCache = [];
private static array $completePathCache = [];

private static array $incompletePathCache = [];

private static array $transformationsByCRS = [];

Expand Down Expand Up @@ -117,30 +119,28 @@ protected function validatePath(array $candidatePath, ?GeographicValue $boundary
}
}

$operations = static::resolveConcatenatedOperations($pathStep['operation'], false);
$operation = CoordinateOperations::getOperationData($pathStep['operation']);

foreach ($operations as $operationId => $operation) {
//filter out operations that require an epoch if we don't have one
if (isset(self::$methodsThatRequireCoordinateEpoch[$operation['method']]) && !$this->getCoordinateEpoch()) {
return false;
}
//filter out operations that require an epoch if we don't have one
if (isset(self::$methodsThatRequireCoordinateEpoch[$operation['method']]) && !$this->getCoordinateEpoch()) {
return false;
}

$params = CoordinateOperationParams::getParamData($operationId);
$params = CoordinateOperationParams::getParamData($pathStep['operation']);

//filter out operations that require a specific epoch
if (isset(self::$methodsThatRequireASpecificEpoch[$operation['method']]) && $this->getCoordinateEpoch()) {
$pointEpoch = Year::fromDateTime($this->getCoordinateEpoch());
if (!(abs($pointEpoch->getValue() - $params['transformationReferenceEpoch']['value']) <= 0.001)) {
return false;
}
//filter out operations that require a specific epoch
if (isset(self::$methodsThatRequireASpecificEpoch[$operation['method']]) && $this->getCoordinateEpoch()) {
$pointEpoch = Year::fromDateTime($this->getCoordinateEpoch());
if (!(abs($pointEpoch->getValue() - $params['transformationReferenceEpoch']['value']) <= 0.001)) {
return false;
}
}

//filter out operations that require a grid file that we don't have, or where boundaries are not being
//checked (a formula-based conversion will always return *a* result, outside a grid boundary does not...
foreach ($params as $param) {
if (isset($param['fileProvider']) && (!$boundaryCheckPoint || !class_exists($param['fileProvider']))) {
return false;
}
//filter out operations that require a grid file that we don't have, or where boundaries are not being
//checked (a formula-based conversion will always return *a* result, outside a grid boundary does not...
foreach ($params as $param) {
if (isset($param['fileProvider']) && (!$boundaryCheckPoint || !class_exists($param['fileProvider']))) {
return false;
}
}
}
Expand All @@ -156,14 +156,17 @@ protected function buildTransformationPathsToCRS(CoordinateReferenceSystem $sour
$iterations = 1;
$sourceSRID = $source->getSRID();
$targetSRID = $target->getSRID();
$simplePaths = [[$sourceSRID]];
self::$incompletePathCache[$sourceSRID . '|' . $targetSRID . '|0'] = [[$sourceSRID]];

while ($iterations < $this->maxChainDepth) {
$cacheKey = $sourceSRID . '|' . $targetSRID . '|' . $iterations;
$cacheKeyMinus1 = $sourceSRID . '|' . $targetSRID . '|' . ($iterations - 1);

if (!isset(self::$pathCache[$cacheKey])) {
if (!isset(self::$completePathCache[$cacheKey])) {
$completePaths = [];

$simplePaths = self::$incompletePathCache[$cacheKeyMinus1];

foreach ($simplePaths as $key => $simplePath) {
$current = end($simplePath);
if ($current === $targetSRID) {
Expand All @@ -186,11 +189,12 @@ protected function buildTransformationPathsToCRS(CoordinateReferenceSystem $sour
$paths[] = ['path' => $fullPath, 'accuracy' => array_sum(array_column($fullPath, 'accuracy'))];
}

self::$pathCache[$cacheKey] = $paths;
self::$incompletePathCache[$cacheKey] = $simplePaths;
self::$completePathCache[$cacheKey] = $paths;
}

++$iterations;
yield self::$pathCache[$cacheKey];
yield self::$completePathCache[$cacheKey];
}
}

Expand Down
Loading

0 comments on commit 0f595a1

Please sign in to comment.