| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- <?php
- namespace App\Doctrine\ORM\AST;
- use Doctrine\ORM\Query\AST\ASTException;
- use Doctrine\ORM\Query\AST\Functions\FunctionNode;
- use Doctrine\ORM\Query\AST\Node;
- use Doctrine\ORM\Query\Lexer;
- use Doctrine\ORM\Query\Parser;
- use Doctrine\ORM\Query\QueryException;
- use Doctrine\ORM\Query\SqlWalker;
- /**
- * SphericalDistanceFunction ::= "SPHERICAL_DISTANCE" "(" ArithmeticPrimary "," ArithmeticPrimary "," ArithmeticPrimary "," ArithmeticPrimary ")".
- *
- * Calcule la distance en km à vol d'oiseau entre les coordonnées géographiques données (latitude, longitude) de deux points.
- *
- * Implémentation de la formule de Haversine, dont la précision est de l'ordre de la dizaine de mètres dans les cas les plus courants.
- *
- * Pour utiliser la fonction :
- *
- * SPHERICAL_DISTANCE(latitude1, longitude1, latitude2, longitude2)
- *
- * WARNING: passing latitude2 and longitude2 as parameter, even named, is not properly interpreted, pass them directly.
- *
- * @see https://fr.wikipedia.org/wiki/Coordonn%C3%A9es_sph%C3%A9riques
- * @see https://fr.wikipedia.org/wiki/Formule_de_haversine
- */
- class SphericalDistance extends FunctionNode
- {
- protected Node|string $latitude1;
- protected Node|string $longitude1;
- protected Node|string $latitude2;
- protected Node|string $longitude2;
- /**
- * Parse DQL Function.
- *
- * @throws QueryException
- */
- public function parse(Parser $parser): void
- {
- $parser->match(Lexer::T_IDENTIFIER);
- $parser->match(Lexer::T_OPEN_PARENTHESIS);
- $this->latitude1 = $parser->ArithmeticPrimary();
- $parser->match(Lexer::T_COMMA);
- $this->longitude1 = $parser->ArithmeticPrimary();
- $parser->match(Lexer::T_COMMA);
- $this->latitude2 = $parser->ArithmeticPrimary();
- $parser->match(Lexer::T_COMMA);
- $this->longitude2 = $parser->ArithmeticPrimary();
- $parser->match(Lexer::T_CLOSE_PARENTHESIS);
- }
- /**
- * Get SQL.
- *
- * @throws ASTException
- */
- public function getSql(SqlWalker $sqlWalker): string
- {
- $R = 6371; // Rayon terrestre, en km
- $lat2 = $this->latitude2->dispatch($sqlWalker);
- $lat1 = $this->latitude1->dispatch($sqlWalker);
- // Call two additional dispatch so doctrine complete the parameters stack (careful: the order is important)
- $this->latitude1->dispatch($sqlWalker);
- $this->latitude2->dispatch($sqlWalker);
- $lon1 = $this->longitude1->dispatch($sqlWalker);
- $lon2 = $this->longitude2->dispatch($sqlWalker);
- // Latitudes et longitudes en radians
- $rLat1 = "($lat1 * PI() / 180)";
- $rLon1 = "($lon1 * PI() / 180)";
- $rLat2 = "($lat2 * PI() / 180)";
- $rLon2 = "($lon2 * PI() / 180)";
- return "2 * $R * ASIN(SQRT(POW(SIN(($rLat2 - $rLat1) / 2), 2) + COS($rLat1) * COS($rLat2) * POW(SIN(($rLon2 - $rLon1) / 2), 2)))";
- }
- }
|