Bienvenue, Invité. Veuillez vous connecter ou vous inscrire.
Avez-vous perdu votre courriel d'activation?
Connexion avec identifiant, mot de passe et durée de la session

 
avancée

254678 Messages dans 14036 Fils de discussion- par 6616 Membres - Dernier membre: louloufcb

22 Mai 2012 à 16:57:38
GTAOnline.frSan Andreas MultiplayerScripting SA-MP [Pawn center]Tutoriels et références SA:MP (Modérateurs: S!m, Xartrick)[TUTO] Bien faire ses tests de distance/position
Pages: [1]   Bas de page
Imprimer
Auteur Fil de discussion: [TUTO] Bien faire ses tests de distance/position  (Lu 573 fois)
0 Membres et 1 Invité sur ce fil de discussion.
S!m
Hors ligne Hors ligne


Moderateur
GTAOnline Fan Boy
*

Messages: 2260


« le: 26 Juillet 2011 à 01:03:37 »

Bien faire ses tests de distance

Table des matières

1. Présentation

2. Mathématiques

   2.1 Calcul de distance
   2.2 Tests de position

3. Fonctions en PAWN

4. Conclusion


1. Présentation

Salut et bienvenue à vous sur ce tutoriel.

Des votre arrivée à la programmation sur SA:MP, vous avez surement eu des idées nécessitant des tests de distance ou de position.
Ce tutoriel est très simple, il présente des fonctions permettant d'effectuer ces tests, explique leur fonctionnement, leur provenance (pour les simplifications mathématiques) et leur utilisation.

J'espère donc que vous apprendrez beaucoup grâce à cette lecture. Grimaçant

2. Développement mathématique des formules de base

La section suivante comporte les développements mathématiques des formules utilisées pour les tests de position et de distance. Je cherche ici à faire comprendre d'où proviennent les codes en question, mais vous pouvez néanmoins sauter et passer directement aux codes si vous ne désirez pas comprendre.

2.1 Calcul de distance
Le calcul de distance consiste simplement à l'évaluation de la distance entre deux points.
Ce calcul est simplement l'évaluation de la norme d'un vecteur en trois dimension.
Il s'agit du vecteur reliant les deux points en question.
Pour ceux qui ne sont pas familier avec les vecteurs, on peut voir ce calcul comme une généralisation du théorème de Pythagore.

Mathématique

Ceux qui connaissent bien le côté mathématique de ce type de calcul, vous pouvez passer à la section implantation.
Dans les formules que j'utiliserai prochainement pour montrer le principe de ce type de calcul, j'utiliserai la nomenclature suivante:

  • X1 = position sur l'axe X du point 1
  • Y1 = position sur l'axe Y du point 1
  • Z1 = position sur l'axe Z du point 1
  • X2 = position sur l'axe X du point 2
  • Y2 = position sur l'axe Y du point 2
  • Z2 = position sur l'axe Z du point 2
  • dX = différence des positions des points sur l'axe X
  • dY = différence des positions des points sur l'axe Y
  • dZ = différence des positions des points sur l'axe Z
Donc, quand on parle du théorème de pythagore, on pense tout de suite à la formule suivante:

A² + B² = C²


En posant un point sur chaque coin du triangle, on obtient la figure suivante:

IMAGES À REDIMENSIONNER

Ainsi:
  • A est la distance entre le point 1 et le 3
  • B est la distance entre le point 2 et le 3
  • C est la distance entre le point 1 et le 2
En utilisant le système de coordonnée illustré et les conventions décrites ci-haut, nous obtenons les informations suivantes:

A = Y1 - Y3
B = X2 - X3

Nous pouvons désormais substituer ces données dans la formule de Pythagore:

(Y1 - Y3)² + (X2 - X3)² = C²

Le résultat recherché est donc la distance entre le point 1 et le point 2, ce qui correspond donc à C.
La formule précédente nous donne la valeur de C, mais comporte deux inconvénients majeurs:

  • Nous devons passer par un troisième point hypothétique pour trouver la réponse
  • Nous n'obtenons pas la valeur de C mais son carré

Pour résoudre ces problèmes, il va falloir réfléchir un peu...
que peut-on faire... Substituer? trouver des équivalence? un peu d'algèbre?...

Commençons par régler le problème du carré.
Au fond, il nous faut simplement trouver l'inverse du carré afin d'isoler notre C.
Quel exposant annule l'exposant 2? 0.5 bien sur! Il s'agit de la racine carrée.

Concernant le problème du troisième point, il faut chercher un peu plus.
Il faut principalement utiliser un dessin bien fait pour nous mettre la puce à l'oreille.
Comme nos axes concordent avec les cathètes de notre triangle, les coordonnées Y2 et Y3 sont en fait identiques, de même que X3 et X1.

On peut donc substituer dans la formule:

(Y1 - Y2)² + (X2 - X1)² = C²

Et en ajoutant la racine carrée:

((Y1 - Y2)² + (X2 - X1)²)½ = C = Distance

Nous avons donc finalement atteint notre formule finale, celle qui donne directement la distance, sans passer par un point fictif ni besoin de calcul supplémentaire.

Petit ennui par contre: GTA:SA est en 3D, pas en 2D!!!

Alors là, je vous demande de me croire sur parole (on peut refaire le même principe avec un triangle supplémentaire, le A de ce nouveau triangle serait le C de celui que nous avons vu et le B l'axe des Z), nous avons la formule suivante:

((Z1 - Z2)² + (Y1 - Y2)² + (X2 - X1)²)½ = C = Distance

2.2 Tests de position

Dans la section précédente, j'ai donné le développement de la formule pour évaluer la distance entre deux points.
Toutefois, il faut remarquer que dans une majorité de cas, on veut savoir si la distance entre les points est inférieur à une autre distance (souvent constante) ou si un point se trouve dans une zone.
C'est le genre de tâche qui est effectué par la fonction PlayerToPoint (qui est obsolète, désormais IsPlayerInRangeOfPoint) ou encore IsPlayerInZone (qui test une zone carrée).
Heureusement, quand on ne veut que savoir si la distance est inférieur à une autre distance, il existe une optimisation au niveau mathématique, ce qui nous permettra d'améliorer l'efficacité de notre fonction.
Par contre, pour savoir si un joueur est dans un rectangle (zone), il n'existe pas vraiment d'optimisation possible, il ne s'agit que de bien faire sa fonction.

Tests de distance

Nous avons vu précédemment la formule suivante:

((Z1 - Z2)² + (Y1 - Y2)² + (X2 - X1)²)½ = C = Distance

Nous avions ajouté la racine carrée afin d'avoir la valeur exacte de la distance. Dans ce cas ci, nous comparons deux distances. La formules est donc transformée à quelque chose de ce genre:

((Z1 - Z2)² + (Y1 - Y2)² + (X2 - X1)²)½ <= Distance max

Nous savons tous, n'es-ce pas, qu'il est relativement difficile d'implanter la racine carrée, la fonction est relativement complexe et demande beaucoup de calcul. Nous voudrions donc éviter d'utiliser cette fonction démoniaque  F&acirc;ch&eacute;.
Quelle est la fonction inverse de la racine carrée?
Mais l'exposant 2 bien sur!
Attention: il faut appliquer l'opération des deux côtés de l'inégalité, nous conservons ainsi notre test. Si une valeur était plus petite avant d'être mise au carrée, elle le sera toujours après.
En l'appliquant de chaque côté, et sachant que les exposant ainsi placés se multiplient, nous avons:

(((Z1 - Z2)² + (Y1 - Y2)² + (X2 - X1)²)½)² <= (Distance max)²
(Z1 - Z2)² + (Y1 - Y2)² + (X2 - X1)² <= (Distance max)²

Nous avons donc grandement réduit notre temps de calcul. La fonction permettant d'obtenir l'exponentielle d'une valeur est avantageuse lorsque l'exposant est relativement grand, dans le cas de 2, il vaut mieux simplement utiliser : x² = x * x.

Tests de zone

Les tests de zone sont très simples, il ne s'agit que de vérifier si la position d'un point est entre certaines bornes.

En gros:

minimum X <= X     ET     maximum X >= X

Le tout se fait sur chacun des axes testés (2 ou 3 selon une zone de forme rectangulaire ou un prisme à base rectangulaire).

3. Fonctions de tests (PAWN)

Commençons avec une fonction qui permet de connaître la distance entre deux points:

Code:
DistanceBetweenPoints(Float:X1, Float:Y1, Float:Z1, Float:X2, Float:Y2, Float:Z2)
{
new Float:dX, Float:dY, Float:dZ;

dX = X1 - X2;
dY = Y1 - Y2;
dZ = Z1 - Z2;

return floatsqroot(dX * dX + dY * dY + dZ * dZ);
}

Explication:
J'utilise des variables intermédiaires pour les distances sur chaque axe pour éviter de faire ces calculs 2 fois, on gagne ainsi en efficacité. Pour le reste, la multiplication des distances par elles-mêmes permet de les mettre au carrée de façon plus efficace que floatpower.
Cette fonction retourne la valeur CORRECTE de la distance entre les deux points passés en paramètres.

On peut utiliser cette fonction dans d'autres fonctions pour la distance entre différents éléments, voici quelques exemples:

Code:
Float:DistanceBetweenPlayerAndPoint(playerid, Float:X, Float:Y, Float:Z)
{
new Float:pX, Float:pY, Float:pZ, Float:distance = 999999999.9999;//je préférerais utiliser NAN au lieu de 9999999999.9999

if(IsPlayerConnected(playerid))
{
GetPlayerPos(playerid, pX, pY, pZ);

distance = DistanceBetweenPoints(pX, pY, pZ, X, Y, Z);//récupération de la distance
}

return distance;
}

Float:DistanceBetweenPlayerAndVehicle(playerid, vehicleid)
{
new Float:pX, Float:pY, Float:pZ;
new Float:vX, Float:vY, Float:vZ;
new Float:distance = 999999999.9999;//je préférerais utiliser NAN au lieu de 9999999999.9999

if(IsPlayerConnected(playerid) && GetVehicleModel(vehicleid) >= 200)//permet de savoir si le véhicule est valide
{
GetPlayerPos(playerid, pX, pY, pZ);
GetVehiclePos(vehicleid, vX, vY, vZ);

distance = DistanceBetweenPoints(pX, pY, pZ, vX, vY, vZ);//récupération de la distance
}

return distance;
}

Maintenant, on passe à la seconde explication: Le tests de grandeur de distance.

Code:
PointToPoint(Float:X1, Float:Y1, Float:Z1, Float:X2, Float:Y2, Float:Z2, Float:distanceMax)
{
new Float:dX, Float:dY, Float:dZ;

dX = X1 - X2;
dY = Y1 - Y2;
dZ = Z1 - Z2;

return (dX * dX + dY * dY + dZ * dZ <= distanceMax * distanceMax);
}

Explication:
Tout comme dans la fonction précédente, nous calculons en premier lieu la différence de position sur chacun des axes. Par la suite, nous additionnons les carrées de chaque différence et comparons la valeur (la distance au carrée entre les points) avec la valeur de la distance maximale autorisée mise au carré. De la même façon, nous pouvons nous en servir pour créer des fonctions subalternes.

Finalement, nous arrivons au test de position de type test de zone.

Code:
//on peut retirer le Z des paramètres, mais gardons le pour les apparences (question d'uniformité)
IsPointInZone(Float:X, Float:Y, Float:Z, Float:minX, Float:maxX, Float:minY, Float:maxY)
{
return ((X >= minX && X <= maxX) && (Y >= minY && Y <= maxY));
}

IsPointInCube(Float:X, Float:Y, Float:Z, Float:minX, Float:maxX, Float:minY, Float:maxY, Float:minZ, Float:maxZ)
{
return ((X >= minX && X <= maxX) && (Y >= minY && Y <= maxY) && (Z >= minZ && Z <= maxZ));
}

Explication:

Il y a très peu à expliquer ici, j'ai fait le tout sur une ligne, sans condition pour réduire les calculs inutiles.

4. Conclusion

....À FAIRE

Merci de passer vos commentaires, si vous ne trouver pas que mon explication est claire, avez des idées pour améliorer, formulations différentes peut-être... voir passer par un chemin complètement différent.

Concernant le niveau de difficulté, je ne sais pas quoi mettre, mais comme le côté programmation est très très simple...
Journalisée





Xolokos
PAWN/XHTML/CSS
Hors ligne Hors ligne


GTAOnline Big Member
*

IA n'est rien comparé a la stupidité naturel.

Messages: 486


Xolokos

« Répondre #1 le: 26 Juillet 2011 à 11:06:28 »

J'y pensé la nuit mais plus dans le sens graphique absice ordonnée.
Tu me diras c'est un peut la même chose.
Merci pour les formules.
Journalisée

Ssk
Développeur d'Open SA-MP
Hors ligne Hors ligne


Sous-admin
GTAOnline Legend
*

Open-SA-MP - Unlimited Experience

Messages: 3726


WWW



sasuke78200

« Répondre #2 le: 26 Juillet 2011 à 12:40:09 »

Salut, le tuto est bien écris malgré quelques petites fautes d'orthographes qui se sont glissées dans le tuto qui reste avant tout bien compréhensible, tu expliques très bien les différentes formules mathématiques permettant de calculer les distances, tu abordes aussi l'optimisation du code. GG


Xolokos oui c'est exactement ça, les coordonnées X et Y représente les abscisses ainsi que les ordonnées, la dimension Z représente ce que l'on peut qualifier de hauteur (certains préféreront dire profondeur).


Et merci Sim pour ce tuto, rare sont les Français (Francophone) qui à l'image d'Y_Less essayent de faire en sorte que tout le monde puissent comprendre certaines choses dans la programmation.
Journalisée






Derrière tout programme se cache un programmeur, je considère le monde comme un programme.
Mon blog
Gilux
Hors ligne Hors ligne

GTAOnline Addict
*

Messages: 1296


WWW
« Répondre #3 le: 26 Juillet 2011 à 12:58:16 »

Merci, en plus de m'avoir appris ça, tu viens de m'apprendre à faire des ancres dans un post, ce qui va me permettre de mieux organiser mon tuto x)

++
Journalisée


R@f
Administrateur Système de GTAOnline.fr
Hors ligne Hors ligne


Administrateur
GTAOnline Fan Boy
*

Messages: 2924


WWW



« Répondre #4 le: 26 Juillet 2011 à 14:11:20 »

Ah sympa, un tuto avec un peu de maths Tr&egrave;s souriant

Bon boulot Sim.

++
R@f
Journalisée


Mon FlickrMon Twitter - Saxoboy




Non non non, je ne donne pas d'aide par PM, y a le forum pour ça. Et non, je n'hébergerais pas votre serveur, donc inutile de m'envoyer un PM pour ça aussi.
cristab
Hors ligne Hors ligne


Admin V.I.P
GTAOnline Legend
*

Messages: 7333


« Répondre #5 le: 26 Juillet 2011 à 14:44:24 »

superbe :o
Journalisée

Syg
Expert programmeur C/C++/PAWN
Hors ligne Hors ligne


Administrateur
GTAOnline Legend
*

The GTAOnline Jesus

Messages: 3760


« Répondre #6 le: 26 Juillet 2011 à 16:11:34 »

Pour tes fonctions DistanceBetweenXXX, tu peux utiliser -1.0 comme distance par défaut au lieu de 999999999.9999.
Une distance étant toujours positive, le fait de retourner une valeur négative montre qu'il y a eu une erreur.

Sinon, dans tes schémas, il n'est pas très heureux de donner des chiffres comme nom pour les sommets du triangle.
Il vaut mieux les appeler A, B et C. De cette façon, on sait tout de suite que la distance AB est la distance entre le point A et le point B. Dans ton cas, ce n'est pas très intuitif.
De plus, les coordonnées de A sont (Xa;Ya) ce qui reste très intuitif aussi.

++
Syg
Journalisée

Courtesy of GtaManiac
S!m
Hors ligne Hors ligne


Moderateur
GTAOnline Fan Boy
*

Messages: 2260


« Répondre #7 le: 27 Juillet 2011 à 00:01:32 »

Salut,

merci à tous pour les commentaires Tire la langue

Pour tes fonctions DistanceBetweenXXX, tu peux utiliser -1.0 comme distance par défaut au lieu de 999999999.9999.
Une distance étant toujours positive, le fait de retourner une valeur négative montre qu'il y a eu une erreur.

Ah j'avais en tête une fonction qui retourne la distance de l'élément le plus proche, c'est pour ça que j'ai mis une grande valeur... merci de la remarque

En ce qui concerne les lettres, je vais changer ça en même temps de changer la valeur de la distance, merci^^

++Sim++
Journalisée





Pages: [1]   Haut de page
Imprimer
Aller à:  

Theme créé par padexx et modifié par GTAOnline.fr
Page générée en 0.196 secondes avec 24 requêtes.
Forum GTAOnline.fr 2.0 | Design par : Lalu et GtaManiac
Merci a toute la communaute pour son support !
Copyright © 2004-2012 - GTAOnline.fr | GTAPro.com | Contact