Circle line-segment de l'algorithme de détection de collision?
J'ai une ligne de A à B et un cercle placé à C avec le rayon R.
Qu'est ce qu'un bon algorithme à utiliser pour vérifier que la ligne coupe le cercle? Et à quel coordonner le long de cercles bord il eu lieu?
- Hmm. Une question: parlez-vous de la ligne infinie par A et B, ou de la limite de segment de ligne de A à B?
- Dans ce cas, sa finis segment de ligne. Est "ligne" appelé quelque chose d'autre en fonction de si son fini ou infini?
- Est-il une exigence de performance ? Devrait-il être une méthode rapide ?
- À ce point, non, tous les algorithmes d'ici que j'ai essayé de ne pas ralentir l'application vers le bas de façon notable.
- oui, ils sont appelés à autre chose: des segments de ligne. Si vous venez de dire "ligne", il est sous-entendu un infini.
- Si vous faites de la détection de collision dans le jeu en 2D, alors vous voulez voir ma réponse
Vous devez vous connecter pour publier un commentaire.
Prendre
De calcul:
d = L - E ( vecteur de Direction de ray, du début à la fin )
f = E - C ( Vecteur à partir du centre de la sphère de rayon démarrer )
Alors l'intersection est trouvé par..
Brancher:
P = E + t * d
C'est une équation paramétrique:
Px = Ex + tdx
Pa = Ea + tda
en
(x - h)2 + (y - k)2 = r2
(h,k) = centre du cercle.
pour obtenir:
x2 - 2xh + h2 + y2 - 2yk + k2 - r2 = 0
x = ex + tdx
y = fa + tda
( ex + tdx )2 - 2( ex + tdx )h + h2 +
( ea + tda )2 - 2( ea + tda )k + k2 - r2 = 0
ex2 + 2extdx + t2dx2 - 2exh - 2tdxh + h2 +
ea2 + 2eatda + t2da2 - 2eak - 2tdak + k2 - r2 = 0
t2( dx2 + da2 ) +
2t( exdx + eada - dxh - dak ) +
ex2 + ea2 -
2exh - 2eak + h2 + k2 - r2 = 0
t2( _d * _d ) + 2t( _e * _d - _d * _c ) + _e * _e - 2( _e*_c ) + _c * _c - r2 = 0
*Où _d est le vecteur d et * est le produit scalaire.*
t2( _d * _d ) + 2t( _d * ( _e - _c ) ) + ( _e - _c ) * ( _e - _c ) - r2 = 0
t2( _d * _d ) + 2t( _d * _f ) + _f * _f - r2 = 0
Nous avons donc:
t2 * (d DOT d) + 2t*( f DOT d ) + ( f DOT f - r2 ) = 0
Si la résolution de l'équation du second degré:
P = E + t * d
Qu'est-ce quet
?P = E + t * d
,P
est un point dans l'espace, nous aurons à EN COMMENÇANT àE
, puis en déplaçantt
unités le long du vecteur de directiond
.t
est une variable qui décrit dans quelle mesure le long de la direction du vecteurd
nous sommesPersonne ne semble envisager de projection, suis-je complètement à côté de la piste ici?
Projet le vecteur
AC
surAB
. La projection du vecteur,AD
, donne le nouveau point deD
.Si la distance entre
D
etC
est inférieure (ou égale à)R
nous avons une intersection.Comme ceci:
P1
&P2
,Px
en général) sont des points surAB
qui sont exactementr
distance deC
- il suffit de calculer |CD| distance et de Pyth de vous savez que |CD|^2+|PxD|^2 = r^2 - ce qui en fait trivial si vous savez comment calculer la ligne de l'équation paramétrique (qui, je suppose que vous devriez).CD
est une projection, il est perpendiculaire, par définition.(projectionPointInCircle and projectionPointOnLine) or endPointsInCircle
Dernier est nécessaire de vérifier depuis segment de ligne peut pénétrer le cercle et la finition avant, il va passé center. les points de terminaison de se référer à des points de début et de fin de segment de ligne.Je voudrais utiliser l'algorithme pour calculer la distance entre un point du cercle de centre) et une droite (AB). Cela peut ensuite être utilisé pour déterminer les points d'intersection de la droite avec le cercle.
Laisser dire que nous avons les points A, B, C. Ax et Ay sont les composants x et y de la Un points. De même pour B et C. Le scalaire R est le rayon du cercle.
Cet algorithme nécessite que A, B et C sont des points distincts et que le R n'est pas 0.
Voici l'algorithme
t+dt
une fois ett-dt
dans un autre point? Pourquoi avez-vous un moment plus et l'autre soustraire?t+dt
ett-dt
sur la ligne.t
est le point sur la ligne la plus proche du centre du cercle. Les points d'intersection avec le cercle sont à un symétrique distance det
. Les points d'intersection sont à "distance"t-dt
ett+dt
. J'ai cité la distance parce que c'est pas la distance euclidienne. Pour obtenir la distance euclidienne deA
oùt=0
, vous devez multiplier la valeur parLAB
.t=0
. Le Point B surt=LAB
. Lorsque les deux points d'intersection (t1=t-td
ett2=t+td
) ont des valeurs négatives que les intersections sont à l'extérieur de la section (derrière le point A la recherche de la section de côté le point). Lorsque t1 et t2 sont plus gros LABORATOIRE alors qu'ils sont à l'extérieur (derrière le point B). Intersection t1 (ou t2) se produit entre A et B uniquement lorsque t1 (ou t2) est compris entre 0 et en LABORATOIRE.Bon, je ne vais pas vous donner le code, mais puisque vous avez coché cette algorithme, je ne pense pas que vous importe.
Tout d'abord, vous devez obtenir un vecteur perpendiculaire à la ligne.
Vous aurez une variable inconnue dans
y = ax + c
(c
sera inconnu )Pour résoudre cela, Calculer sa valeur lorsque la ligne passe par le centre du cercle.
Qui est,
Branchez l'emplacement du cercle de centre à la ligne de l'équation et la résoudre pour
c
.Puis calculer le point d'intersection de la ligne d'origine et de sa normale.
Cela va vous donner le point le plus proche sur la ligne du cercle.
Calculer la distance entre ce point et le cercle de centre (à l'aide de la magnitude du vecteur).
Si ce dernier est inférieur au rayon du cercle - voila, nous avons un carrefour!
Une autre méthode utilise le triangle ABC de la zone formule. L'intersection de test est plus simple et plus efficace que la méthode de projection, mais de trouver les coordonnées du point d'intersection nécessite plus de travail. Au moins, il sera en retard pour le point qu'il est nécessaire.
La formule pour calculer l'aire du triangle est : zone = bh/2
où b est la longueur de la base et h la hauteur. Nous avons choisi le segment AB à la base de sorte que h est la distance la plus courte à partir de C, le cercle de centre à la ligne.
Depuis l'aire du triangle peut aussi être calculée par un vecteur produit scalaire, on peut déterminer h.
Mise à JOUR 1 :
Vous pouvez optimiser le code en utilisant la rapide inverse de la racine carrée de calcul décrite ici pour obtenir une bonne approximation de 1/LAB.
Le calcul du point d'intersection n'est pas que difficile. Ici, il va
Si h = R puis la ligne AB est tangente au cercle et la valeur dt = 0 et E = F. Le point de coordonnées sont celles de E et de F.
Vous devez vérifier que A est différent de B et la longueur de segment n'est pas nul, si cela peut se produire dans votre application.
J'ai écrit un petit script pour tester l'intersection de la projection du cercle de centre le point à la ligne.
http://jsfiddle.net/ercang/ornh3594/1/
Si vous avez besoin de vérifier la collision avec le segment, vous devez également considérer le cercle de centre à distance aux points de début et fin.
https://jsfiddle.net/ercang/menp0991/
Cette solution que j'ai trouvé semble un peu plus facile à suivre que certains des autres.
Prendre:
Je voudrais résoudre l'équation de la droite de pente à l'origine de la forme. Cependant, je ne voulais pas avoir à faire face à de difficiles équations avec
c
comme un point, donc j'ai juste modifié le système de coordonnées de sorte que le cercle est à0,0
Par la façon dont, à chaque fois que je l'ai enlevé de points les uns des autres, je suis en soustrayant la
x
's et puis en soustrayant lay
's, et de les mettre dans un nouveau point, juste au cas où quelqu'un ne le savait pas.De toute façon, j'ai maintenant résoudre l'équation de la droite avec
p3
etp4
:Ok. Maintenant j'ai besoin de ces équations égal. D'abord j'ai besoin pour résoudre le cercle de l'équation pour
x
Puis j'ai mis de l'égalité:
Et les solutions de l'équation quadratique (
0 = ax^2 + bx + c
):Maintenant, j'ai mon
a
,b
, etc
.Alors j'ai mis ça dans la formule quadratique:
Et les remplacer par les valeurs de simplifier autant que possible:
C'est presque aussi loin que vous le simplifier. Enfin, la séparation des équations avec l' ±:
Puis branchez simplement le résultat de ces deux équations dans le
x
dansmx + b
. Pour plus de clarté, j'ai écrit un peu de code JavaScript pour montrer comment l'utiliser ceci:J'espère que cela aide!
P. S. Si quelqu'un trouve des erreurs ou des suggestions, s'il vous plaît commentaire. Je suis très nouveau et bienvenue à tous de l'aide/suggestions.
underRadical
extra ')'Vous pouvez trouver un point sur une ligne infinie qui est la plus proche de cercle de centre par la projection du vecteur AC sur le vecteur AB. Calculer la distance entre ce point et le cercle de centre. Si c'est plus grand que R, il n'y a pas d'intersection. Si la distance est égale à R, la ligne est à la tangente du cercle et le point le plus proche de cercle de centre est en fait le point d'intersection. Si la distance moins de R, alors il y a 2 points d'intersection. Ils se trouvent à la même distance du point le plus proche de cercle de centre. Cette distance peut être facilement calculé en utilisant le théorème de Pythagore. Voici l'algorithme en pseudo-code:
EDIT: ajout de code pour vérifier si trouvé des points d'intersection sont réellement à l'intérieur de segment de ligne.
Bizarrement je peux répondre, mais pas de commentaire...
J'ai aimé Multitaskpro de l'approche de déplacement, le tout afin de rendre le centre du cercle de tomber sur l'origine. Malheureusement, il y a deux problèmes dans son code. D'abord dans le sous-les-racine carrée de la partie, vous devez supprimer le double de la puissance. Donc pas:
var underRadical = Math.pow((Math.pow(r,2)*(Math.pow(m,2)+1)),2)-Math.pow(b,2));
mais:
var underRadical = Math.pow(r,2)*(Math.pow(m,2)+1)) - Math.pow(b,2);
Dans les coordonnées finales il oublie de décalage de la solution. Donc pas:
var i1 = {x:t1,y:m*t1+b}
mais:
var i1 = {x:t1+c.x, y:m*t1+b+c.y};
L'ensemble de la fonction devient alors:
Vous aurez besoin de maths ici:
Supposons que A = (Xa, Ya), B = (Xb, Yb) et C = (Xc, Yc). Un point sur la ligne de A à B a pour coordonnées (alpha*Xa + (1-alpha)Xb, alphaYa + (1-alpha)*Yb) = P
Si le point P est la distance R à C, il doit être sur le cercle. Ce que vous voulez est de résoudre
qui est
si vous appliquez le ABC-formule de cette équation à résoudre pour l'alpha, et de calculer les coordonnées de P à l'aide de la solution(s) pour l'alpha, vous obtenez les points d'intersection, le cas échéant.
Si vous trouver la distance entre le centre de la sphère (puisque c'est de la 3D je suppose que vous voulez dire de la sphère et pas de cercle) et de la ligne, puis vérifier si cette distance est inférieure au rayon qui va faire l'affaire.
Le point de collision est évidemment le point le plus proche entre la ligne et la sphère (qui sera calculé lorsque vous êtes le calcul de la distance entre la sphère et la ligne)
Distance entre un point et une ligne à:
http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
Voici une implémentation en Javascript. Mon approche est d'abord convertir le segment de ligne dans une ligne infinie puis de trouver le point d'intersection(s). À partir de là, j'ai vérifier si le point(s) trouvés sont sur le segment de ligne. Le code est bien documenté, vous devriez être en mesure de la suivre.
Vous pouvez essayer le code ici, sur ce démonstration en direct.
Le code a été prise à partir de mon les algorithmes de repo.
Dans ce post, cercle de la ligne de collision sera vérifié par la vérification de la distance entre le cercle de centre et le point sur le segment de ligne (Ipoint) qui représentent le point d'intersection entre la normale N (Image 2) du cercle de centre de segment de ligne.
(https://i.stack.imgur.com/3o6do.png)
Sur l'image 1 d'un cercle et une ligne sont affichées, le vecteur d'Un point à la ligne point de départ, le vecteur B, point à la ligne point de fin, le vecteur C, point de cercle de centre. Maintenant, nous devons trouver le vecteur E (à partir de la ligne de point de départ pour le cercle de centre) et le vecteur D (à partir de la ligne de point de départ à l'extrémité de la ligne de point) ce calcul est indiqué sur l'image 1.
(https://i.stack.imgur.com/7098a.png)
À l'image 2, on peut voir que le vecteur E est projetée sur le Vecteur D par "produit scalaire" de vecteur E et le vecteur unitaire D, le résultat du produit scalaire scalaire est Xp qui représentent la distance entre le point de départ et le point d'intersection (Ipoint) de vecteurs N et le vecteur D.
Suivant le vecteur X est obtenu en multipliant l'unité de vecteur D et scalaire Xp.
Maintenant, nous avons besoin de trouver le vecteur Z (vecteur de Ipoint), sa facilité de sa simple addition vectorielle de vecteur A (start point à la ligne) et le vecteur X. Ensuite, nous devons faire face à des cas particuliers, il doit vérifier est Ipoint sur le segment de ligne, si ce n'est pas nous devons savoir est-il à gauche ou à droite de celui-ci, nous allons utiliser le vecteur le plus proche pour déterminer le point le plus proche de cercle.
(https://i.stack.imgur.com/p9WIr.png)
Lors de la projection Xp est négatif Ipoint est à gauche du segment de ligne, le vecteur le plus proche est égal au vecteur de la ligne de point de départ, lors de la projection Xp est supérieure à la magnitude du vecteur D, puis Ipoint est à droite de la ligne de segment le plus proche du vecteur est égale au vecteur de fin de ligne point dans les autres cas le plus proche du vecteur est égale au vecteur Z.
Maintenant, quand nous avons le plus proche du vecteur , nous avons besoin de trouver le vecteur de cercle de centre à Ipoint (dist vecteur), sa simple nous avons juste besoin de soustraire le plus proche du vecteur de centre de vecteur. Ensuite il suffit de vérifier si le vecteur dist ampleur est à moins de cercle de rayon si c'est pour qu'ils entrent en collision, si ce n'est pas il n'y a pas de collision.
(https://i.stack.imgur.com/QJ63q.png)
Pour finir, nous pouvons revenir à des valeurs pour la résolution de collision , le plus simple est de retour chevauchement de collision (soustraire rayon de vecteur dist ampleur) et le retour de l'axe de collision, de son vecteur D. Également le point d'intersection est le vecteur Z si nécessaire.
Si la ligne des coordonnées A. x, A. y et B. x, B. y et les cercles de centre C. x, C. y ensuite les lignes sont les formules:
x = A. x * t + B. x * (1 - t)
y = A. y * t + B. y * (1 - t)
où 0<=t<=1
et le cercle est
(C. x - x)^2 + (C. y - y)^2 = R^2
si l'on remplace x et y les formules de la ligne dans les cercles de la formule, vous obtenez un deuxième ordre de l'équation de t et ses solutions sont les points d'intersection (si il y en a). Si vous obtenez un t qui est inférieure à 0 ou supérieure à 1, alors ce n'est pas une solution, mais il montre que la ligne est "pointage" à la direction du cercle.
Simplement un ajout à ce fil...
Ci-dessous est une version du code posté par pahlevan, mais pour C#/XNA et rangé un peu:
Ray.Intersects(BoundingSphere)
J'ai créé cette fonction pour iOS à la suite de la réponse donnée par
chmike
Cercle est vraiment un mauvais gars 🙂 Donc un bon moyen est d'éviter de vrai cercle, si vous le pouvez. Si vous effectuez le contrôle des collisions pour les jeux, vous pouvez aller avec quelques simplifications et ont seulement 3 point des produits, et un peu de comparaisons.
J'appelle cela le "gros point" ou "mince cercle". son genre d'une ellipse avec un rayon de braquage nul dans une direction parallèle à un segment. mais plein de rayon dans une direction perpendiculaire à un segment
Tout d'abord, je voudrais envisager de renommer et de commutation du système de coordonnées pour éviter les excès de données:
Deuxième, l'indice de h dans hvec2f signifie que le vecteur doit favoriser horizontale des opérations telles que le point()/det(). Ce qui signifie que ses composants doivent être placés dans un document distinct registres xmm, pour éviter de brassage/ddp require/hsub pratiquent. Et ici, nous allons, avec plus performantes en version plus simple de détection de collision pour un jeu en 2D:
Je doute que vous pouvez l'optimiser un peu plus loin. Je l'utilise pour le réseau neuronal conduit de course de voiture de détection de collision, de traiter des millions de millions d'itération des étapes.
Ce Java Fonction renvoie un DVec2 Objet. Il faut un DVec2 pour le centre du cercle, le rayon du cercle, et une Ligne.
Un autre en c# (partielle de la classe Circle).
Testé et fonctionne comme un charme.
Requis:
Ici est la bonne solution en JavaScript (avec tout le nécessaire de mathématiques et de vivre de l'illustration)
https://bl.ocks.org/milkbread/11000965
Si
is_on
fonction dans cette solution a besoin de modifications:JS:
Voici ma solution en caractères d'imprimerie, en suivant l'idée que @Mizipzor suggéré (à l'aide de projection):
Voici une solution écrite en golang. La méthode est analogue à celle de certaines autres réponses postées ici, mais pas tout à fait la même. Il est facile à mettre en œuvre, et a été testé. Voici les étapes:
Les valeurs de A, B et C de l'équation du second degré sont dérivées ici, où (n-he) et (m-dt) sont les équations de la ligne de coordonnées x et y, respectivement. r est le rayon du cercle.
Donc A = ee+dd, B = - 2(fr + dm), et C = nn + mm - rr.
Ici est la golang code de la fonction:
Je l'ai testé avec cette fonction, ce qui confirme que la solution des points sont dans le segment de la ligne et sur le cercle. Il fait un test de segment et il balaie autour du cercle:
Voici la sortie de l'épreuve:
Enfin, la méthode est facilement extensible pour le cas d'un rayon, en commençant à un point, passant à travers l'autre et s'étendant à l'infini, par un seul test si t > 0 ou t < 1, mais pas les deux.
J'ai juste besoin que, donc, je suis venu avec cette solution. La langue est maxscript, mais il doit être facile à traduire dans une autre langue.
cotea, coteb et CircleRadius sont des scalaires, le reste des variables sont des points que [x,y,z]. Je suis en supposant que z=0 à résoudre sur le plan XY