Je n'ai pas encore parcouru les équations complètes pour cela, mais voici quelques visuels pour nous aider à comprendre ce problème. Cela se résume à une certaine géométrie:
( Icônes de voiture via Kenney )
À partir de n'importe quel point de départ et orientation, nous pouvons dessiner deux cercles avec notre rayon de braquage minimum - un à gauche, un à droite. Ceux-ci décrivent les points sur le début le plus serré possible de notre chemin.
Nous pouvons faire de même pour n'importe quelle position finale et orientation souhaitées. Ces cercles décrivent la fin la plus étroite possible de notre chemin.
Maintenant, le problème se résume à trouver un chemin qui relie l'un des cercles de départ à l'un des cercles de fin, en embrassant chacun le long de sa tangente.
(Cela suppose que nous n'avons pas besoin de rechercher des obstacles entre les deux, ce qui n'était pas mentionné dans la question. La réponse de Stormwind explique comment utiliser les informations du graphique de navigation pour ces types de problèmes. Une fois que nous avons la séquence de nœuds pour passer, nous pouvons appliquer la méthode ci-dessous à chaque segment du plan.)
Si, pour plus de simplicité, nous utilisons des lignes droites, nous obtenons quelque chose comme ceci:
Cela nous donne le cas limite. Une fois que vous avez trouvé un chemin par cette méthode, vous pouvez gonfler artificiellement un ou les deux cercles de début et de fin pour obtenir un chemin moins direct mais plus lisse, jusqu'au point où les deux cercles s'embrassent.
Calcul de ces chemins
Étudions les cas pour un sens de rotation - disons que nous commençons notre chemin en tournant à droite.
Le centre de notre cercle de braquage à droite est:
startRightCenter = carStart.position + carStart.right * minRadius
Appelons l'angle de la section droite de notre chemin (mesuré à partir de l'axe x positif) pathAngle
Si nous dessinons un vecteur du rightCenter
point où nous quittons le cercle de rotation (auquel point nous devons faire face à pathAngle), alors ce vecteur est ...
startOffset = minRadius * (-cos(pathAngle), sin(pathAngle))
Cela signifie que le point où nous quittons le cercle doit être ...
departure = startRightCenter + startOffset
Le point où nous rentrons dans un cercle de virage dépend de si nous visons à terminer par un virage à gauche ou à droite:
// To end with a right turn:
reentry = endRightCenter + startOffset
// To end with a left turn: (crossover)
reentry = endLeftCenter - startOffset
Maintenant, si nous avons bien fait notre travail, la ligne se joignant departure
à reentry
doit être perpendiculaire à startOffset
:
dot(reentry - departure, startOffset) = 0
Et la résolution de cette équation nous donnera l'angle (s) auquel cela est vrai. (J'utilise un pluriel ici parce que techniquement il y a deux de ces angles, mais l'un d'eux implique de conduire en marche arrière, ce qui n'est généralement pas ce que nous voulons)
Remplaçons le virage à droite par un virage à droite comme exemple:
dot(endRightCenter + startOffset - startRightCenter - startOffset, startOffset) = 0
dot(endRightCenter - startRightCenter, startOffset) = 0
pathAngle = atan2(endRightCenter - startRightCenter)
Le cas du crossover est plus compliqué - c'est celui pour lequel je n'ai pas encore calculé tous les calculs. Je posterai la réponse sans pour l'instant, au cas où cela vous serait utile pendant que je travaille sur les détails restants.
Modifier: destination à l'intérieur du rayon de braquage minimum
Il s'avère que cette méthode fonctionne souvent prête à l'emploi même lorsque la destination est plus proche que notre distance de virage minimale. Au moins une partie de l'un des cercles de rentrée se retrouve en dehors du rayon de virage, ce qui nous permet de trouver un chemin viable tant que cela ne nous dérange pas de devenir un peu bretzel ...
Si nous n'aimons pas le chemin que nous obtenons de cette façon (ou si un n'est pas faisable - je n'ai pas vérifié tous les cas de manière exhaustive - peut-être qu'il y en a des impossibles), nous pouvons toujours continuer tout droit ou en arrière jusqu'à ce que nous obtenions un véhicule approprié baiser le contact entre un cercle de début et de fin, comme illustré ci-dessus.