# Prérequis Python et Algèbre Linéaire pour la 3D

> Où en êtes-vous en Python et en algèbre linéaire pour la 3D ? Un test de 20 questions en 10 minutes, qui vous renvoie aux sections à revoir, et le guide des bases.

- Adresse : https://fr.learngeodata.eu/blog/prerequis-python-algebre-3d
- Rubrique : Articles techniques
- Langue : fr
- Auteur : Dr. Florent Poux (https://fr.learngeodata.eu/formateur/florent-poux)
- Éditeur : 3D Geodata Academy (organisme de formation, France)
- Index du site pour les assistants : https://fr.learngeodata.eu/llms.txt
- Publié le 2026-01-31, mis à jour le 2026-09-11

---
Commencez par le test

20 questions, 10 minutes, votre niveau tout de suite

Dix questions de Python, dix d'algèbre linéaire. À la fin, chaque réponse fausse vous renvoie à la section qui l'explique : vous ne révisez que ce qui vous manque. Le repère de confort est de 16/20 : le test est informatif, il ne conditionne pas l'inscription.

Où mènent ces bases : un scan d'intérieur de 5 364 551 points découpé en 4 563 segments. Tableaux NumPy, normales, matrices de transformation : chaque étape repose sur ce que couvre cet article.

## 1. Installer Python : votre laboratoire de travail

La première étape est de disposer d'un environnement `Python` propre et reproductible. `Miniconda` est la référence pour la data science et le calcul scientifique, car il gère nativement les dépendances compilées (`C++`, `CUDA`, `Fortran`).

```
# 1. Télécharger Miniconda (Linux/macOS/Windows)
# https://docs.conda.io/en/latest/miniconda.html

# 2. Créer un environnement dédié
conda create -n prereq-3d python=3.12 -y
conda activate prereq-3d

# 3. Installer les bibliothèques essentielles
pip install numpy matplotlib
```

Vérifiez que tout fonctionne en lançant `python --version` dans votre terminal. Vous devez obtenir `Python 3.12.x`. Passons maintenant aux briques fondamentales du langage.

## 2. Les fondamentaux Python en 30 minutes

Inutile de lire un livre de 500 pages. Pour la 3D, vous avez besoin de maîtriser un sous-ensemble précis du langage. Voici l'essentiel, condensé.

### 2.1 Variables et types

Python est un langage à typage dynamique. Les types fondamentaux pour la 3D sont `int`, `float`, `str`, `bool` et `list`.

```
# Variables numériques (coordonnées d'un point 3D)
x = 1.5
y = -3.2
z = 0.8

# Chaîne de caractères
label = "bâtiment"

# Booléen
est_classifie = True

# Vérifier le type
print(type(x))   # <class 'float'>
print(type(label)) # <class 'str'>
```

### 2.2 Listes et dictionnaires

Les `listes` stockent des séquences ordonnées. Les `dictionnaires` associent des clés à des valeurs. En 3D, une liste de coordonnées et un dictionnaire de métadonnées sont omniprésents.

```
# Liste : un point 3D
point = [1.5, -3.2, 0.8]
print(point[0])  # 1.5 (indexation commence à 0)

# Liste de points (nuage simplifié)
nuage = [
    [1.5, -3.2, 0.8],
    [2.1, 0.4, 1.2],
    [-0.3, 1.7, 0.1],
]

# Dictionnaire : métadonnées d'un scan
scan_info = {
    "source": "LiDAR Terrestre",
    "nb_points": 5_000_000,
    "format": "LAZ",
    "crs": "EPSG:2154",
}
print(scan_info["nb_points"])  # 5000000
```

### 2.3 Boucles et conditions

Les boucles `for` parcourent des séquences. Les conditions `if/elif/else` contrôlent le flux. En 3D, on itère souvent sur des points pour les filtrer ou les transformer.

```
# Filtrer les points au-dessus de z = 0.5
points_hauts = []
for point in nuage:
    if point[2] > 0.5:
        points_hauts.append(point)

print(f"Points au-dessus de 0.5m : {len(points_hauts)}")

# Compréhension de liste (syntaxe compacte)
points_hauts = [p for p in nuage if p[2] > 0.5]

# La même syntaxe calcule une liste à partir d'une autre
carres = [x**2 for x in range(4)]
print(carres)  # [0, 1, 4, 9]

# Boucle avec index (enumerate)
for i, p in enumerate(nuage):
    print(f"Point {i} : x={p[0]}, y={p[1]}, z={p[2]}")
```

### 2.4 Fonctions

Les fonctions encapsulent une logique réutilisable. Dans un pipeline 3D, chaque étape de traitement est typiquement une fonction.

```
def distance_3d(p1, p2):
    """Calcule la distance euclidienne entre deux points 3D."""
    dx = p1[0] - p2[0]
    dy = p1[1] - p2[1]
    dz = p1[2] - p2[2]
    return (dx**2 + dy**2 + dz**2) ** 0.5

a = [0, 0, 0]
b = [1, 1, 1]
print(f"Distance : {distance_3d(a, b):.4f} m")
# Distance : 1.7321 m
```

## 3. NumPy : le moteur du calcul vectoriel

`NumPy` est la bibliothèque fondamentale pour le calcul numérique en Python. En 3D, vous manipulez des millions de points : les boucles Python sont trop lentes. NumPy exécute chaque opération en `C` compilé, sur tout le tableau d'un coup : c'est ce qui rend possible le traitement de millions de points.

### 3.1 Créer et manipuler des tableaux

```
import numpy as np

# Créer un array à partir d'une liste
point = np.array([1.5, -3.2, 0.8])
print(point.shape)  # (3,) : vecteur 3D

# Nuage de 5 points (matrice 5x3)
nuage = np.array([
    [1.5, -3.2, 0.8],
    [2.1,  0.4, 1.2],
    [-0.3, 1.7, 0.1],
    [0.0,  0.0, 0.0],
    [3.4, -1.1, 2.5],
])
print(nuage.shape)  # (5, 3) : 5 points, 3 dimensions

# Accéder à toutes les coordonnées Z
z_coords = nuage[:, 2]
print(z_coords)  # [0.8, 1.2, 0.1, 0.0, 2.5]
```

### 3.2 Opérations vectorisées et broadcasting

Le `broadcasting` est la capacité de NumPy à appliquer une opération entre des arrays de formes différentes. C'est ce qui rend le calcul 3D possible sans boucles.

```
# Translation : déplacer tout le nuage de (+10, +20, +5)
translation = np.array([10, 20, 5])
nuage_deplace = nuage + translation  # Broadcasting automatique !

# Centrer le nuage sur son barycentre
centroid = np.mean(nuage, axis=0)
nuage_centre = nuage - centroid

# Calculer la distance de chaque point à l'origine
distances = np.linalg.norm(nuage, axis=1)
print(distances)  # [3.62, 2.45, 1.73, 0.00, 4.36]

# Filtrage vectorisé : points à moins de 3m de l'origine
masque = distances < 3.0
points_proches = nuage[masque]
print(f"Points proches : {len(points_proches)}")
```

## 4. Lire et écrire des fichiers

En 3D, les données transitent souvent sous forme de fichiers texte (`CSV`, `TXT`) ou structurés (`JSON`). Savoir les lire et les écrire est un prérequis non négociable.

```
import numpy as np
import json

# ---- CSV : écrire puis relire un nuage de points ----
nuage = np.array([[ 1.5, -3.2, 0.8],
                  [ 2.1,  0.4, 1.2],
                  [-0.3,  1.7, 0.1]])
np.savetxt("points.csv", nuage, delimiter=",", header="x,y,z", comments="")

nuage_lu = np.loadtxt("points.csv", delimiter=",", skiprows=1)
print(f"Chargé {nuage_lu.shape[0]} points")  # Chargé 3 points

# Sauvegarder les seuls points au-dessus de 0,5 m
np.savetxt("points_filtres.csv", nuage_lu[nuage_lu[:, 2] > 0.5],
           delimiter=",", header="x,y,z", comments="")

# ---- JSON : métadonnées de projet ----
config = {"crs": "EPSG:2154", "nb_points": len(nuage_lu), "bbox": [0, 0, 100, 100]}
with open("projet.json", "w") as f:
    json.dump(config, f, indent=2)

with open("projet.json") as f:
    print(json.load(f)["crs"])  # EPSG:2154
```

## 5. Visualiser avec Matplotlib

`Matplotlib` permet de créer des graphiques 2D et 3D. Indispensable pour vérifier visuellement vos données avant de les injecter dans un pipeline de traitement.

```
import matplotlib.pyplot as plt
import numpy as np

# Générer un nuage de points aléatoire
np.random.seed(42)
nuage = np.random.randn(200, 3)

# Visualisation 3D
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
ax.scatter(nuage[:, 0], nuage[:, 1], nuage[:, 2],
           c=nuage[:, 2], cmap='viridis', s=5)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.set_title('Nuage de Points 3D')
plt.show()
```

## 6. Exercice : charger et afficher des coordonnées 3D

Mettez en pratique tout ce que vous venez d'apprendre. L'objectif : créer un fichier CSV de coordonnées, le charger avec NumPy, calculer des statistiques, et afficher le résultat en 3D.

```
import numpy as np
import matplotlib.pyplot as plt

# 1. Créer un fichier CSV de test
np.random.seed(0)
points = np.random.uniform(-10, 10, size=(500, 3))
np.savetxt("nuage_test.csv", points, delimiter=",",
           header="x,y,z", comments="")

# 2. Charger le fichier
data = np.loadtxt("nuage_test.csv", delimiter=",", skiprows=1)
print(f"Nombre de points : {data.shape[0]}")

# 3. Statistiques
print(f"Barycentre : {np.mean(data, axis=0)}")
print(f"Étendue Z  : {data[:, 2].min():.2f} à {data[:, 2].max():.2f}")

# 4. Filtrer : garder seulement les points avec z > 0
data_filtre = data[data[:, 2] > 0]
print(f"Points avec z > 0 : {len(data_filtre)}")

# 5. Visualiser
fig = plt.figure(figsize=(12, 5))

ax1 = fig.add_subplot(121, projection='3d')
ax1.scatter(data[:, 0], data[:, 1], data[:, 2],
            c=data[:, 2], cmap='coolwarm', s=2)
ax1.set_title('Nuage complet')

ax2 = fig.add_subplot(122, projection='3d')
ax2.scatter(data_filtre[:, 0], data_filtre[:, 1], data_filtre[:, 2],
            c=data_filtre[:, 2], cmap='coolwarm', s=2)
ax2.set_title('Filtré (z > 0)')

plt.tight_layout()
plt.show()
```

Ce que doit afficher votre script : à gauche les 500 points tirés entre -10 et 10, colorés par leur hauteur ; à droite les 251 points qui ont z > 0.

## 7. Vecteurs 2D et 3D : la brique élémentaire

Un vecteur est une quantité qui a une **direction** et une **magnitude**. En 3D, un vecteur est un triplet `(x, y, z)`. Les opérations sur les vecteurs sont le fondement de toute géométrie computationnelle.

```
import numpy as np

# Définir deux vecteurs 3D
u = np.array([3, 1, 4])
v = np.array([1, 5, -2])

# Addition et soustraction
somme = u + v       # [4, 6, 2]
diff = u - v        # [2, -4, 6]

# Multiplication par un scalaire
double_u = 2 * u    # [6, 2, 8]

# Norme (longueur) du vecteur
norme_u = np.linalg.norm(u)
print(f"||u|| = {norme_u:.4f}")  # 5.0990

# Vecteur unitaire (normalisation)
u_hat = u / norme_u
print(f"Direction de u : {u_hat}")
print(f"Vérification : ||u_hat|| = {np.linalg.norm(u_hat):.1f}")  # 1.0
```

| Opération | Notation | NumPy | Résultat |
| --- | --- | --- | --- |
| Addition | u + v | `u + v` | Vecteur |
| Soustraction | u - v | `u - v` | Vecteur |
| Scalaire | k * u | `k * u` | Vecteur |
| Norme | \|\|u\|\| | `np.linalg.norm(u)` | Scalaire |

## 8. Produit scalaire

Le produit scalaire de deux vecteurs donne un **nombre** (scalaire). Il mesure à quel point deux vecteurs pointent dans la même direction. Son application 3D principale : calculer l'** angle entre deux vecteurs**.

```
import numpy as np

u = np.array([1, 0, 0])  # Axe X
v = np.array([0, 1, 0])  # Axe Y
w = np.array([1, 1, 0])  # Diagonale XY

# Produit scalaire
print(np.dot(u, v))  # 0 : vecteurs perpendiculaires !
print(np.dot(u, w))  # 1

# Angle entre u et w
cos_angle = np.dot(u, w) / (np.linalg.norm(u) * np.linalg.norm(w))
angle_rad = np.arccos(cos_angle)
angle_deg = np.degrees(angle_rad)
print(f"Angle entre u et w : {angle_deg:.1f}°")  # 45.0°
```

## 9. Produit vectoriel et normale à un plan

Le produit vectoriel de deux vecteurs donne un **troisième vecteur** perpendiculaire aux deux premiers. C'est l'outil fondamental pour calculer la **normale d'une surface** en 3D.

```
import numpy as np

# Trois points définissent un plan
A = np.array([0, 0, 0])
B = np.array([1, 0, 0])
C = np.array([0, 1, 0])

# Deux vecteurs dans le plan
AB = B - A  # [1, 0, 0]
AC = C - A  # [0, 1, 0]

# Normale au plan = produit vectoriel
normale = np.cross(AB, AC)
print(f"Normale : {normale}")  # [0, 0, 1] : pointe vers le haut

# Normaliser pour obtenir un vecteur unitaire
normale_unit = normale / np.linalg.norm(normale)
print(f"Normale unitaire : {normale_unit}")

# Aire du triangle ABC
aire = 0.5 * np.linalg.norm(normale)
print(f"Aire du triangle : {aire} m²")  # 0.5 m²
```

Les valeurs des sections 7 et 9, dessinées. À gauche, u et v se complètent en u + v, diagonale du parallélogramme. À droite, le produit vectoriel de AB et AC donne la normale au plan ABC, perpendiculaire au triangle.

La même opération à l'échelle d'un vrai nuage : une normale par point, colorée selon sa direction. Le sol ressort d'une seule teinte, chaque mur prend la couleur de son orientation.

## 10. Matrices : multiplication, transposée et inverse

Les matrices sont des tableaux 2D de nombres. En 3D, elles servent à représenter des **transformations géométriques** (rotation, mise à l'échelle) et à résoudre des systèmes d'équations.

```
import numpy as np

# Créer une matrice 3x3
M = np.array([
    [2, 0, 0],
    [0, 3, 0],
    [0, 0, 1],
])

# Multiplication matrice x vecteur
v = np.array([1, 1, 1])
resultat = M @ v  # Opérateur @ = multiplication matricielle
print(resultat)   # [2, 3, 1] : mise à l'échelle !

# Transposée
print(M.T)

# Inverse (si elle existe)
M_inv = np.linalg.inv(M)
print(M_inv @ M)  # Matrice identité (aux erreurs flottantes près)

# Déterminant
det = np.linalg.det(M)
print(f"Déterminant : {det}")  # 6.0
```

| Opération | NumPy | Signification Géométrique |
| --- | --- | --- |
| Multiplication | `A @ B` | Composition de transformations |
| Transposée | `A.T` | Miroir par rapport à la diagonale |
| Inverse | `np.linalg.inv(A)` | Transformation inverse (annuler) |
| Déterminant | `np.linalg.det(A)` | Facteur de changement de volume |

## 11. Transformations 3D : rotation, translation, échelle

Toute manipulation géométrique en 3D se ramène à une combinaison de trois opérations fondamentales. Comprendre comment les appliquer avec des matrices est essentiel pour travailler avec des nuages de points.

### 11.1 Matrice de rotation

Une rotation autour de l'axe Z d'un angle `theta` s'exprime par une matrice 3x3. Les rotations autour de X et Y suivent le même principe.

```
import numpy as np

def rotation_z(theta_deg):
    """Matrice de rotation autour de l'axe Z."""
    theta = np.radians(theta_deg)
    c, s = np.cos(theta), np.sin(theta)
    return np.array([
        [ c, -s, 0],
        [ s,  c, 0],
        [ 0,  0, 1],
    ])

def rotation_x(theta_deg):
    """Matrice de rotation autour de l'axe X."""
    theta = np.radians(theta_deg)
    c, s = np.cos(theta), np.sin(theta)
    return np.array([
        [1,  0,  0],
        [0,  c, -s],
        [0,  s,  c],
    ])

def rotation_y(theta_deg):
    """Matrice de rotation autour de l'axe Y."""
    theta = np.radians(theta_deg)
    c, s = np.cos(theta), np.sin(theta)
    return np.array([
        [ c, 0, s],
        [ 0, 1, 0],
        [-s, 0, c],
    ])

# Rotation de 45° autour de Z
R = rotation_z(45)
point = np.array([1, 0, 0])
point_tourne = R @ point
print(f"Avant : {point}")
print(f"Après : {point_tourne}")  # [0.707, 0.707, 0]
```

### 11.2 Translation et changement d'échelle

```
# Translation : simple addition vectorielle
nuage = np.random.randn(100, 3)
translation = np.array([10, 20, 5])
nuage_deplace = nuage + translation

# Changement d'échelle : multiplication par une matrice diagonale
S = np.diag([2.0, 2.0, 0.5])  # Double en X/Y, moitié en Z
nuage_scale = (S @ nuage.T).T

# Combinaison : d'abord rotation, puis translation
R = rotation_z(30)
nuage_transforme = (R @ nuage.T).T + translation
```

## 12. Systèmes de coordonnées et projections

En géospatial, les données proviennent de capteurs utilisant différents systèmes de coordonnées. Il est crucial de savoir passer d'un repère à un autre.

| Système | Type | Usage Typique | Unité |
| --- | --- | --- | --- |
| WGS84 (EPSG:4326) | Géographique | GPS, données mondiales | Degrés |
| Lambert 93 (EPSG:2154) | Projeté | France métropolitaine | Mètres |
| UTM | Projeté | Universel par zones | Mètres |
| Local / Scanner | Cartésien | LiDAR terrestre, BIM | Mètres |

Le passage d'un repère local à un repère géoréférencé se fait par une transformation rigide (rotation + translation), souvent via une matrice 4x4 obtenue par recalage de cibles connues.

```
import numpy as np

# Projection orthogonale d'un vecteur u sur un vecteur v
def projection(u, v):
    """Projette u sur v."""
    return (np.dot(u, v) / np.dot(v, v)) * v

u = np.array([3, 4, 0])
v = np.array([1, 0, 0])  # Axe X

proj = projection(u, v)
print(f"Projection de u sur X : {proj}")  # [3, 0, 0]

# Composante perpendiculaire
perp = u - proj
print(f"Composante perpendiculaire : {perp}")  # [0, 4, 0]
```

## 13. Exercice : faire tourner un nuage de points

Exercice de synthèse : générez un nuage de points en forme de "L", appliquez une rotation de 90 degrés autour de l'axe Z, puis visualisez le résultat avant/après.

```
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(1)  # même tirage pour tout le monde

# 1. Créer un nuage en forme de L
branche_h = np.random.uniform([0, 0, 0], [5, 1, 1], size=(200, 3))
branche_v = np.random.uniform([0, 0, 0], [1, 4, 1], size=(200, 3))
nuage = np.vstack([branche_h, branche_v])

# 2. Matrice de rotation (90° autour de Z)
theta = np.radians(90)
R = np.array([
    [np.cos(theta), -np.sin(theta), 0],
    [np.sin(theta),  np.cos(theta), 0],
    [0,              0,             1],
])

# 3. Appliquer la rotation à chaque point
# nuage.T = (3, 400), R @ nuage.T = (3, 400), .T = (400, 3)
nuage_tourne = (R @ nuage.T).T

# 4. Visualiser avant / après, vus de dessus et à la même échelle :
#    une rotation autour de Z se lit alors directement dans le plan XY
fig = plt.figure(figsize=(12, 6))
for i, (pts, couleur, titre) in enumerate([(nuage, '#8b5cf6', 'Original'),
                                           (nuage_tourne, '#d946ef', 'Après rotation 90° (Z)')]):
    ax = fig.add_subplot(1, 2, i + 1, projection='3d')
    ax.scatter(pts[:, 0], pts[:, 1], pts[:, 2], c=couleur, s=3)
    ax.set_xlim(-5, 5); ax.set_ylim(-5, 5); ax.set_zlim(0, 1)
    ax.view_init(elev=90, azim=-90)
    ax.set_zticks([])  # vu de dessus, l'axe Z n'apporte rien
    ax.set_title(titre)
    ax.set_xlabel('X'); ax.set_ylabel('Y')

plt.tight_layout()
plt.show()

# Vérification : le barycentre a-t-il bien tourné ?
c_avant = np.mean(nuage, axis=0)
c_apres = np.mean(nuage_tourne, axis=0)
print(f"Barycentre avant  : {c_avant}")
print(f"Barycentre après  : {c_apres}")
print(f"Distance conservée : {np.linalg.norm(c_avant):.4f} vs {np.linalg.norm(c_apres):.4f}")
```

Le résultat attendu, vu de dessus : le L tourne de 90° autour de l'axe Z, dans le sens trigonométrique. Ses dimensions ne changent pas, et la distance du barycentre à l'origine non plus (1,9897 dans les deux cas).

## 14. Le test de positionnement

Ce questionnaire vous permet d'évaluer votre niveau avant de rejoindre la formation. 20 questions, 4 choix, une seule bonne réponse. Répondez honnêtement : il n'y a aucun piège, juste une vérification de vos acquis.

## Test de Positionnement

10 questions Python + 10 questions Algèbre Linéaire. Durée estimée : 10 minutes.

1 Quel est le résultat de `type(3.14)` en Python ?

- `<class 'int'>`
- `<class 'float'>`
- `<class 'str'>`
- `<class 'decimal'>`

2 Comment accéder au troisième élément d'une liste `L` ?

- `L[3]`
- `L[2]`
- `L(3)`
- `L{2}`

3 Quelle instruction crée un dictionnaire en Python ?

- `d = ["clé", "valeur"]`
- `d = ("clé": "valeur")`
- `d = {"clé": "valeur"}`
- `d = dict["clé", "valeur"]`

4 Que retourne `len([1, 2, 3, 4])` ?

- 3
- 4
- 5
- Une erreur

5 Quelle est la sortie de : `[x** 2 for x in range(4)]` ?

- `[1, 4, 9, 16]`
- `[0, 1, 4, 9]`
- `[0, 2, 4, 6]`
- `[1, 2, 3, 4]`

6 Quelle bibliothèque utilise-t-on pour charger un fichier CSV sous forme de tableau numérique ?

- `os`
- `json`
- `numpy`
- `sys`

7 Quel est le résultat de `np.array([1,2,3]).shape` ?

- `(1, 3)`
- `(3,)`
- `(3, 1)`
- `3`

8 Comment sélectionner toutes les lignes de la deuxième colonne d'un array `A` de shape (100, 3) ?

- `A[1, :]`
- `A[:, 1]`
- `A[2]`
- `A[:][1]`

9 Que fait `np.mean(A, axis=0)` sur un array de shape (100, 3) ?

- Calcule la moyenne de chaque ligne (résultat de shape (100,))
- Calcule la moyenne de chaque colonne (résultat de shape (3,))
- Calcule la moyenne globale (un seul nombre)
- Retourne une erreur

10 Quelle fonction Python permet de définir un bloc de code réutilisable ?

- `class`
- `def`
- `lambda`
- `return`

11 Quelle est la norme du vecteur (3, 4, 0) ?

- 7
- 5
- 25
- 12

12 Quel est le produit scalaire de (1, 0, 0) et (0, 1, 0) ?

- 1
- -1
- 0
- (0, 0, 1)

13 Que signifie un produit scalaire nul entre deux vecteurs non nuls ?

- Les vecteurs sont parallèles
- Les vecteurs sont perpendiculaires (orthogonaux)
- Les vecteurs sont de même longueur
- Un des vecteurs est le vecteur nul

14 Quel est le produit vectoriel de (1, 0, 0) et (0, 1, 0) ?

- (0, 0, 0)
- (1, 1, 0)
- (0, 0, 1)
- (0, 0, -1)

15 Quelle est la dimension du résultat de la multiplication d'une matrice (3x3) par un vecteur (3x1) ?

- 3x3
- 3x1
- 1x3
- 1x1

16 Que représente la matrice identité (I) en géométrie 3D ?

- Une rotation de 360 degrés
- Aucune transformation (le point reste inchangé)
- Une mise à l'échelle de facteur 2
- Une projection sur le plan XY

17 Si une matrice de rotation R tourne un objet de 30 degrés, que fait R inverse ?

- Tourne de 60 degrés
- Tourne de -30 degrés (annule la rotation)
- Double la taille de l'objet
- Supprime l'objet

18 Quelle matrice effectue un changement d'échelle qui double toutes les dimensions ?

- `np.eye(3)`
- `np.ones((3,3))`
- `2 * np.eye(3)`
- `np.zeros((3,3))`

19 Quelle propriété est conservée par une matrice de rotation ?

- Les coordonnées absolues des points
- Les distances entre les points
- La position du barycentre
- Le nombre de points

20 En NumPy, quel opérateur effectue une multiplication matricielle ?

- `*`
- `@`
- `**`
- `&`

### Votre score

### Et après les prérequis ?

Ces bases sont le premier maillon. Le guide gratuit **Architecte IA de Systèmes 3D** montre où elles mènent : du nuage de points brut au Smart Point Cloud et aux agents spatiaux, en 24 chapitres et 172 pages, à lire en ligne ou en PDF.

La formation, elle, reprend chaque maillon sur des projets concrets.

[Le programme et les tarifs →](https://fr.learngeodata.eu/tarifs)
