Calculer la norme, la normale et le milieu d’un segment

Dans cet article on va parler de comment calculer simplement la norme, la normale et le milieu d’un segment en 2 dimensions. L’intérêt est multiple, mais en ce moment, ces trois calculs me servent à afficher les normales des murs des secteurs dans l’éditeur de mon moteur de musée virtuel. Je m’en suis servit en partie dans Demiurge, en 3D, sauf pour la normale qui nécessite l’utilisation d’un produit en croix pour les surfaces (cross product en anglais).

Le milieu d’un segment

Commençons par le milieu d’un segment qui ne nécessite pas les deux autres pour être calculé. En 2D, pour calculer simplement le milieu d’un segment, il suffit tout d’abord de ramener le segment à son vecteur directeur, ici non normalisé, comme on la vue dans l’article sur le calcul du sens d’un segment. L’équation est simple, je le rappelle ici :

Vecteur = (xB - xA, yB - yA)

Ce vecteur, contrairement, au segment (sauf cas particulier) a sa position aux coordonnées (0, 0) et donc les coordonnées de la pointe du vecteur correspondent logiquement à la soustraction du deuxième point du segment par le premier point. Il s’agit d’une simplification du segment qui permet de lui faire toutes sortes de choses et notamment trouver le milieu, mais aussi sa normale. Mais, on verra après pour la normale 🙂

Pour trouver le milieu du segment, il reste deux étapes toutes simple. La première consiste à diviser par 2 les coordonnées du vecteur non normalisé. Ainsi, on obtient la moitié du vecteur. Puis, la deuxième et dernière étape consiste à ramener le vecteur à sa place en l’additionnant avec le premier point du segment.

DemiVecteur = (Vecteur.x / 2, Vecteur.y / 2)
Milieu = (xA + DemiVecteur.x, xB + DemiVecteur.y)

La norme du segment

La norme d’un segment est la distance entre le premier et le deuxième point qui le constitue. C’est à dire, pour faire simple, sa longueur. Peu importe que votre segment se trouve sur une grille de pixels, et donc soumis à un repère, il s’agit là de la longueur que vous obtiendriez si vous aviez une règle est mesureriez le segment 🙂

La formule de la norme est un peu plus compliqué et gourmand en ressources pour un ordinateur que ce qu’on a fait précédemment. Heureusement pour nous, elle a au moins le mérite de tenir sur une seule ligne :p

Norme = √(Vecteur.x²+Vecteur.y²)

Je le réécris différemment pour plus de lisibilité et de compréhension.

Norme = RacineCarrée( Carré(Vecteur.x) + Carré(Vecteur.y) )

J’ai utilisé ici le vecteur de tout à l’heure. En effet, on ne calcule pas directement la norme d’un segment, mais celui de son vecteur non normalisé. Et si depuis tout à l’heure je n’ai pas normalisé mon vecteur, c’est précisément parce que normaliser signifie qu’on le ramène à une norme de 1, hors nous voulons mesurer notre segment, ce serait donc absurde 🙂

Avec une norme on peut faire le calcul du milieu du segment d’une façon différente que la méthode précédente, mais aussi faire d’autres choses comme calculer la trajectoire d’un projectile par exemple. Cependant, pour y arriver, il va normaliser le vecteur. Je vais vous expliquer comment en même temps que le calcul de la normale d’un segment ou d’une droite 🙂

Normaliser un segment et calculer sa normale

Comme je l’ai dit tout à l’heure, normaliser un vecteur, c’est mettre sa norme à 1. Et pour faire cela, rien de plus simple 🙂

Normalisé = (Vecteur.x / norme, Vecteur.y / norme)

Voilà, c’est fait 😀 Il suffisait tout simplement de diviser les coordonnées du vecteur précédemment obtenu. C’est assez logique, puisque la norme est la longueur du vecteur de départ. Et c’est pour cette raison qu’un vecteur normalisé est très utile pour une trajectoire de projectile par exemple, puisque entre le moment où un personnage fait feu et un instant T, le projectile aura parcouru une certaine distance. Ainsi, connaître son vecteur directeur permet de simplement le multiplier par la distance parcouru pour trouver les coordonnées du projectile :p Si vous voulez par exemple, afficher un objet se déplaçant suivant un vecteur, vous pouvez associer une distance pour chaque quantum de temps (fraction du temps) et additionner ces distances à chaque instant pour ensuite le multiplier par le vecteur. A chaque quantum de temps, votre ordinateur affichera votre objet aux bonnes coordonnées et vous le verrez se déplacer sur votre trajectoire. Ajoutez à ceci, un vecteur de gravité, qui irait toujours vers le bas, soit ceci (0, y), et vous aurez la base d’un jeu de missile, sniper ou d’archer, et une part non négligeable d’un Worms x)

Bon, je vous raconte tout ça, mais il me reste un truc à vous expliquer. C’est le calcul de la normale au segment, ou plus tôt au vecteur. La normale d’un vecteur est un vecteur perpendiculaire au premier. Là encore, en 2 dimensions, trouver la normale d’un vecteur est simplicime. Voici la formule :

Normale =(-Normalisé.y, Normalisé.x)

Et voilà, hihihihi 😀 Tout simplement, la coordonnées X de la normale est égale à la coordonnées Y en négatif du vecteur directeur, et la coordonnées Y de la normale est égale à la coordonnées X du vecteur directeur. Ni plus, ni moins 🙂 Il n’y a donc pas réellement de calcules à faire, mais juste des assignations de valeurs.

C’est lorsqu’on fait des tests sur un papier ou à l’écran, qu’on comprend l’utilité de calculer le sens d’un segment comme je l’ai proposé en premier article de la série sur l’algorithmie. En effet, si vous placez les points de votre segment dans un ordre ou dans un autre, vous changerez nécessairement l’ordre de ces derniers dans les opérations précédemment expliqué ici. Ainsi, votre normale ne sera pas dans le même sens non plus. Pour un ligne horizontale par exemple, la normale sera soit vers le haut, soit vers le bas, selon l’ordre dans lequel vous avez entré vos deux points du segment. Cette propriété peut provoquer des erreurs d’affichages, de physique dans un moteur physique, mais aussi, bien exploitée, permettre de déterminer l’intérieur et l’extérieur d’un monde comme dans mon moteur de musée 🙂

Bonus : Dessiner une normale au milieu d’un segment

TimidouvegMuseum_2017-07-26Je vous mets un petit algorithme qui utilise tout ce qui est au-dessus pour dessiner la normale d’un segment.

DessinerSegment(xA, yA, xB, yB);
Vecteur(xB-xA, yB-yA);
Norme = RacineCarré(Carré(Vecteur.x) + Carré(Vecteur.y));
Normalisé = (Vecteur.x/Norme, Vecteur.y/Norme);
Normale = (-Normalisé.y, Normalisé.x);
Milieu = (xA+Vecteur.x/2, yA+Vecteur.y/2);
DessinerNormale(Milieu.x, Milieu.y, Milieu.x+Normale.x, Milieu.y+Normale.y);

Si les unités de votre dessin sont les pixels, la normale ne fera qu’un seule pixel et dans certains cas, il ne pourra pas s’afficher. Vous pouvez donc multiplier ses coordonnées par un nombre raisonnable pour bien voir la ligne s’afficher et apprécier la perpendiculaire a votre segment 🙂

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

recaptcha/recaptchalib.php at 1.0.0 · google/recaptcha · GitHub
Skip to content
Permalink
Switch branches/tags
Find file
8a45f9d Dec 1, 2014
141 lines (129 sloc) 4.47 KB
<?php
/**
* This is a PHP library that handles calling reCAPTCHA.
* - Documentation and latest version
* https://developers.google.com/recaptcha/docs/php
* - Get a reCAPTCHA API Key
* https://www.google.com/recaptcha/admin/create
* - Discussion group
* http://groups.google.com/group/recaptcha
*
* @copyright Copyright (c) 2014, Google Inc.
* @link http://www.google.com/recaptcha
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* A ReCaptchaResponse is returned from checkAnswer().
*/
class ReCaptchaResponse
{
public $success;
public $errorCodes;
}
class ReCaptcha
{
private static $_signupUrl = "https://www.google.com/recaptcha/admin";
private static $_siteVerifyUrl =
"https://www.google.com/recaptcha/api/siteverify?";
private $_secret;
private static $_version = "php_1.0";
/**
* Constructor.
*
* @param string $secret shared secret between site and ReCAPTCHA server.
*/
function ReCaptcha($secret)
{
if ($secret == null || $secret == "") {
die("To use reCAPTCHA you must get an API key from <a href='"
. self::$_signupUrl . "'>" . self::$_signupUrl . "</a>");
}
$this->_secret=$secret;
}
/**
* Encodes the given data into a query string format.
*
* @param array $data array of string elements to be encoded.
*
* @return string - encoded request.
*/
private function _encodeQS($data)
{
$req = "";
foreach ($data as $key => $value) {
$req .= $key . '=' . urlencode(stripslashes($value)) . '&';
}
// Cut the last '&'
$req=substr($req, 0, strlen($req)-1);
return $req;
}
/**
* Submits an HTTP GET to a reCAPTCHA server.
*
* @param string $path url path to recaptcha server.
* @param array $data array of parameters to be sent.
*
* @return array response
*/
private function _submitHTTPGet($path, $data)
{
$req = $this->_encodeQS($data);
$response = file_get_contents($path . $req);
return $response;
}
/**
* Calls the reCAPTCHA siteverify API to verify whether the user passes
* CAPTCHA test.
*
* @param string $remoteIp IP address of end user.
* @param string $response response string from recaptcha verification.
*
* @return ReCaptchaResponse
*/
public function verifyResponse($remoteIp, $response)
{
// Discard empty solution submissions
if ($response == null || strlen($response) == 0) {
$recaptchaResponse = new ReCaptchaResponse();
$recaptchaResponse->success = false;
$recaptchaResponse->errorCodes = 'missing-input';
return $recaptchaResponse;
}
$getResponse = $this->_submitHttpGet(
self::$_siteVerifyUrl,
array (
'secret' => $this->_secret,
'remoteip' => $remoteIp,
'v' => self::$_version,
'response' => $response
)
);
$answers = json_decode($getResponse, true);
$recaptchaResponse = new ReCaptchaResponse();
if (trim($answers ['success']) == true) {
$recaptchaResponse->success = true;
} else {
$recaptchaResponse->success = false;
$recaptchaResponse->errorCodes = $answers [error-codes];
}
return $recaptchaResponse;
}
}
?>
You can't perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.

Fatal error: Class 'ReCaptcha' not found in /homepages/39/d436294224/htdocs/clickandbuilds/TheeDonistMonk/index.php on line 29