diff --git a/src/Application/Exception/BothDirectionsNotSupportedAtPointNumbers.php b/src/Application/Exception/BothDirectionsNotSupportedAtPointNumbers.php new file mode 100644 index 000000000..7e5d328fb --- /dev/null +++ b/src/Application/Exception/BothDirectionsNotSupportedAtPointNumbers.php @@ -0,0 +1,9 @@ +command; + + [$command->fromSide, $command->toSide] = $this->pointNumberSideDetector->detect( + $command->direction, + $command->administrator, + $command->roadNumber, + $command->fromPointNumber, + $command->fromAbscissa ?? 0, + $command->toPointNumber, + $command->toAbscissa ?? 0, + ); + if ($query->geometry) { return $query->geometry; } diff --git a/src/Application/RoadGeocoderInterface.php b/src/Application/RoadGeocoderInterface.php index f7738844c..d00ef5fae 100644 --- a/src/Application/RoadGeocoderInterface.php +++ b/src/Application/RoadGeocoderInterface.php @@ -30,4 +30,10 @@ public function findRoadNames(string $search, string $cityCode): array; public function findSectionsInArea(string $areaGeometry, array $excludeTypes = [], ?bool $clipToArea = false): string; public function convertPolygonRoadToLines(string $geometry): string; + + public function getAvailableSidesAtPointNumber( + string $administrator, + string $roadNumber, + string $pointNumber, + ): array; } diff --git a/src/Domain/Regulation/Location/NumberedRoad.php b/src/Domain/Regulation/Location/NumberedRoad.php index 8276ac14a..ba47ee9b1 100644 --- a/src/Domain/Regulation/Location/NumberedRoad.php +++ b/src/Domain/Regulation/Location/NumberedRoad.php @@ -97,4 +97,17 @@ public function update( $this->toSide = $toSide; $this->direction = $direction; } + + /** + * Compare two PR+abs. + * Return -1 if A < B, 0 if A === B, or 1 if A > B + */ + public static function comparePointNumber( + string $pointNumberA, + int $abscissaA, + string $pointNumberB, + int $abscissaB, + ): int { + return 0; + } } diff --git a/src/Infrastructure/Adapter/BdTopoRoadGeocoder.php b/src/Infrastructure/Adapter/BdTopoRoadGeocoder.php index 64f77ceb6..88d75d810 100644 --- a/src/Infrastructure/Adapter/BdTopoRoadGeocoder.php +++ b/src/Infrastructure/Adapter/BdTopoRoadGeocoder.php @@ -414,4 +414,34 @@ public function convertPolygonRoadToLines(string $geometry): string return $row['geom']; } + + public function getAvailableSidesAtPointNumber( + string $administrator, + string $roadNumber, + string $pointNumber, + ): array { + $rows = $this->bdtopoConnection->fetchAllAssociative( + \sprintf( + 'SELECT p.cote AS side + FROM point_de_repere AS p + WHERE p.gestionnaire = :administrator + AND p.route = :roadNumber + AND p.numero = :pointNumber + ', + ), + [ + 'administrator' => $administrator, + 'roadNumber' => $roadNumber, + 'pointNumber' => $pointNumber, + ], + ); + + $sides = []; + + foreach ($rows as $row) { + $sides[] = $row['side']; + } + + return $sides; + } } diff --git a/src/Infrastructure/Adapter/PointNumberSideDetector.php b/src/Infrastructure/Adapter/PointNumberSideDetector.php new file mode 100644 index 000000000..e1ea2d8fa --- /dev/null +++ b/src/Infrastructure/Adapter/PointNumberSideDetector.php @@ -0,0 +1,80 @@ +roadGeocoder->getAvailableSidesAtPointNumber( + $administrator, + $roadNumber, + $fromPointNumber, + ); + + $sidesAtToPoint = $this->roadGeocoder->getAvailableSidesAtPointNumber( + $administrator, + $roadNumber, + $toPointNumber, + ); + + $isSingleWayAtFromPoint = \in_array(RoadSideEnum::U->value, $sidesAtFromPoint); + $isSingleWayAtToPoint = \in_array(RoadSideEnum::U->value, $sidesAtToPoint); + + if ($isSingleWayAtFromPoint || $isSingleWayAtToPoint) { + // L'un des deux PR au moins est sur une chaussée unique + // On doit forcément utiliser des PR de type U. + return [RoadSideEnum::U->value, RoadSideEnum::U->value]; + } + + // Les deux PR se trouvent sur une section à chaussée séparée. + // A priori, les deux côtés G ou D sont possibles au niveau de chaque PR. + // On choisit le côté adéquat en fonction de la direction demandée et de l'ordre + // des PR dans le sens des PR croissants. + // Le "Double sens" n'est pas supporté pour l'instant, il faut saisir deux localisations, + // une dans chaque sens. + + if ($direction === DirectionEnum::BOTH->value) { + // TODO: handle in controller + throw new BothDirectionsNotSupportedAtPointNumbers(); + } + + if (NumberedRoad::comparePointNumber($fromPointNumber, $fromAbscissa, $toPointNumber, $toAbscissa) <= 0) { + // Le PR A est situé avant le PR B, dans l'ordre des PR croissants. + // On doit choisir le côté D si le sens A -> B est demandé, et le côté G sinon. + $side = $direction === DirectionEnum::A_TO_B->value + ? RoadSideEnum::D->value + : RoadSideEnum::G->value; + + return [$side, $side]; + } + + // Le PR A est situé après le PR B, donc on choisit le côté G si A->B est demandé, et le côté D sinon. + $side = $direction === DirectionEnum::A_TO_B->value + ? RoadSideEnum::G->value + : RoadSideEnum::D->value; + + return [$side, $side]; + } +} diff --git a/src/Infrastructure/Form/Regulation/NumberedRoadFormType.php b/src/Infrastructure/Form/Regulation/NumberedRoadFormType.php index 3cc84c180..b2840e9b3 100644 --- a/src/Infrastructure/Form/Regulation/NumberedRoadFormType.php +++ b/src/Infrastructure/Form/Regulation/NumberedRoadFormType.php @@ -6,7 +6,6 @@ use App\Application\Regulation\Command\Location\SaveNumberedRoadCommand; use App\Domain\Regulation\Enum\DirectionEnum; -use App\Domain\Regulation\Enum\RoadSideEnum; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\HiddenType; @@ -43,11 +42,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'help' => 'regulation.location.referencePoint.pointNumber.help', ], ) - ->add( - 'fromSide', - ChoiceType::class, - options: $this->getRoadSideOptions(), - ) ->add( 'toPointNumber', TextType::class, @@ -56,11 +50,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'help' => 'regulation.location.referencePoint.pointNumber.help', ], ) - ->add( - 'toSide', - ChoiceType::class, - options: $this->getRoadSideOptions(), - ) ->add( 'fromAbscissa', IntegerType::class, @@ -92,23 +81,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void }); } - private function getRoadSideOptions(): array - { - $choices = []; - - foreach (RoadSideEnum::cases() as $case) { - $choices[\sprintf('regulation.location.road.side.%s', $case->value)] = $case->value; - } - - return [ - 'choices' => array_merge( - $choices, - ), - 'label' => 'regulation.location.road.side', - 'help' => 'regulation.location.road.side.help', - ]; - } - private function getAdministratorOptions(array $administrators, string $roadType): array { $choices = []; diff --git a/templates/regulation/fragments/_measure_form.html.twig b/templates/regulation/fragments/_measure_form.html.twig index 394ef6d06..2c7e32ffd 100644 --- a/templates/regulation/fragments/_measure_form.html.twig +++ b/templates/regulation/fragments/_measure_form.html.twig @@ -238,7 +238,6 @@