Calcolare L’Angolo Di 2 Vettori 3D Python

Calcolatore Angolo tra 2 Vettori 3D

Inserisci le componenti dei due vettori 3D per calcolare l’angolo tra loro in gradi e radianti

Guida Completa: Come Calcolare l’Angolo tra Due Vettori 3D in Python

Il calcolo dell’angolo tra due vettori in uno spazio tridimensionale è un’operazione fondamentale in molti campi scientifici e ingegneristici, tra cui la fisica, la computer grafica, la robotica e l’apprendimento automatico. Questa guida ti fornirà una comprensione approfondita del processo matematico e della sua implementazione in Python.

Fondamenti Matematici

L’angolo θ tra due vettori a e b in uno spazio 3D può essere calcolato utilizzando il prodotto scalare (dot product) e le magnitudini dei vettori. La formula fondamentale è:

cos(θ) = (a · b) / (||a|| × ||b||)

Dove:

  • a · b è il prodotto scalare dei vettori
  • ||a|| e ||b|| sono le magnitudini (lunghezze) dei vettori
  • θ è l’angolo tra i due vettori

Passaggi per il Calcolo

  1. Calcolare il prodotto scalare: a·b = axbx + ayby + azbz
  2. Calcolare le magnitudini:
    • ||a|| = √(ax² + ay² + az²)
    • ||b|| = √(bx² + by² + bz²)
  3. Calcolare il coseno dell’angolo: cos(θ) = (a·b) / (||a|| × ||b||)
  4. Ottenere l’angolo: θ = arccos(cos(θ))
  5. Convertire in gradi (se necessario): θ° = θ × (180/π)

Implementazione in Python

Python offre diversi approcci per implementare questo calcolo. Ecco le soluzioni più efficaci:

1. Utilizzando NumPy (metodo consigliato)

NumPy è la libreria più efficienti per operazioni matematiche in Python:

import numpy as np

def angle_between_vectors(a, b):
    # Calcola il prodotto scalare
    dot_product = np.dot(a, b)

    # Calcola le magnitudini
    magnitude_a = np.linalg.norm(a)
    magnitude_b = np.linalg.norm(b)

    # Evita divisione per zero
    if magnitude_a == 0 or magnitude_b == 0:
        return 0

    # Calcola il coseno dell'angolo
    cos_theta = dot_product / (magnitude_a * magnitude_b)

    # Limita il valore tra -1 e 1 per evitare errori di arccos
    cos_theta = np.clip(cos_theta, -1.0, 1.0)

    # Calcola l'angolo in radianti e converti in gradi
    theta_rad = np.arccos(cos_theta)
    theta_deg = np.degrees(theta_rad)

    return theta_deg, theta_rad

# Esempio di utilizzo
vector1 = np.array([3, 4, 0])
vector2 = np.array([1, 0, 5])
degrees, radians = angle_between_vectors(vector1, vector2)
print(f"Angolo: {degrees:.2f}° o {radians:.2f} rad")
        

2. Implementazione Pura Python (senza librerie)

Per progetti dove non si possono usare librerie esterne:

import math

def angle_between_vectors_pure(a, b):
    # Prodotto scalare
    dot_product = a[0]*b[0] + a[1]*b[1] + a[2]*b[2]

    # Magnitudini
    magnitude_a = math.sqrt(a[0]**2 + a[1]**2 + a[2]**2)
    magnitude_b = math.sqrt(b[0]**2 + b[1]**2 + b[2]**2)

    if magnitude_a == 0 or magnitude_b == 0:
        return 0, 0

    # Coseno dell'angolo
    cos_theta = dot_product / (magnitude_a * magnitude_b)
    cos_theta = max(min(cos_theta, 1.0), -1.0)  # Clip per evitare errori

    # Angolo in radianti e gradi
    theta_rad = math.acos(cos_theta)
    theta_deg = math.degrees(theta_rad)

    return theta_deg, theta_rad

# Esempio
vector1 = [3, 4, 0]
vector2 = [1, 0, 5]
degrees, radians = angle_between_vectors_pure(vector1, vector2)
        

Casi Particolari e Gestione degli Errori

Quando si implementa questo calcolo, è importante considerare alcuni casi particolari:

  1. Vettori nulli: Se uno dei vettori ha magnitudine zero, l’angolo è indefinito. La nostra implementazione restituisce 0 in questo caso.
  2. Errori di arrotondamento: A causa della precisione finita dei float, il valore di cos(θ) può essere leggermente fuori dall’intervallo [-1, 1], causando errori in arccos. Usiamo np.clip() per risolvere questo problema.
  3. Vettori paralleli:
    • Se i vettori sono paralleli e nello stesso verso, θ = 0°
    • Se sono paralleli ma in versi opposti, θ = 180°
  4. Vettori perpendicolari: Se il prodotto scalare è zero, θ = 90°

Applicazioni Pratiche

Il calcolo dell’angolo tra vettori ha numerose applicazioni:

Campo di Applicazione Utilizzo Specifico Esempio Pratico
Computer Grafica Calcolo illuminazione (shading) Determinare l’angolo tra la luce e la normale alla superficie per calcolare l’intensità luminosa
Robotica Pianificazione del movimento Calcolare l’angolo tra la posizione corrente e l’obiettivo per ottimizzare il percorso
Fisica Meccanica classica Determinare l’angolo tra forze applicate per calcolare la risultante
Machine Learning Similarità tra vettori Calcolare la similarità coseno tra word embeddings in NLP
Geometria Computazionale Intersezione di linee Determinare se due segmenti si intersecano basandosi sull’angolo tra le loro direzioni

Ottimizzazione delle Prestazioni

Per applicazioni che richiedono il calcolo di angoli tra molti vettori (ad esempio in machine learning), è fondamentale ottimizzare le prestazioni:

  1. Vettorizzazione con NumPy: Processare array di vettori invece di singoli vettori
  2. Preallocazione della memoria: Creare array per i risultati prima del calcolo
  3. Parallelizzazione: Utilizzare librerie come Dask o Numba per calcoli paralleli
  4. Caching: Memorizzare risultati di calcoli ripetuti

Ecco un esempio di implementazione vettorizzata:

import numpy as np

def vectorized_angle_between(vectors1, vectors2):
    """Calcola angoli tra array di vettori"""
    # Prodotti scalari
    dot_products = np.einsum('ij,ij->i', vectors1, vectors2)

    # Magnitudini
    magnitudes1 = np.linalg.norm(vectors1, axis=1)
    magnitudes2 = np.linalg.norm(vectors2, axis=1)

    # Coseni degli angoli
    cos_theta = dot_products / (magnitudes1 * magnitudes2)
    cos_theta = np.clip(cos_theta, -1.0, 1.0)

    # Angoli in gradi
    angles_deg = np.degrees(np.arccos(cos_theta))

    return angles_deg

# Esempio con 1000 coppie di vettori
vectors1 = np.random.rand(1000, 3)
vectors2 = np.random.rand(1000, 3)
angles = vectorized_angle_between(vectors1, vectors2)
        

Visualizzazione dei Risultati

La visualizzazione può aiutare a comprendere meglio i risultati. Ecco come creare un grafico 3D con Matplotlib:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def plot_vectors_with_angle(a, b):
    fig = plt.figure(figsize=(10, 8))
    ax = fig.add_subplot(111, projection='3d')

    # Disegna i vettori
    ax.quiver(0, 0, 0, a[0], a[1], a[2], color='r', label='Vettore A')
    ax.quiver(0, 0, 0, b[0], b[1], b[2], color='b', label='Vettore B')

    # Calcola e disegna l'angolo
    angle = angle_between_vectors(a, b)[0]
    ax.text2D(0.05, 0.95, f"Angolo: {angle:.2f}°", transform=ax.transAxes)

    # Imposta limiti e legenda
    max_val = max(np.max(np.abs(a)), np.max(np.abs(b))) * 1.1
    ax.set_xlim([-max_val, max_val])
    ax.set_ylim([-max_val, max_val])
    ax.set_zlim([-max_val, max_val])
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')
    ax.legend()

    plt.title("Angolo tra due vettori 3D")
    plt.show()

# Esempio
plot_vectors_with_angle(np.array([3, 4, 0]), np.array([1, 0, 5]))
        

Confronto tra Metodi di Calcolo

Esistono diversi approcci per calcolare l’angolo tra vettori. Ecco un confronto delle prestazioni:

Metodo Precisione Velocità (1M operazioni) Memoria Facilità d’Uso
NumPy (vettorizzato) Alta ~0.5s Media Alta
Python puro Media ~12s Bassa Media
Numba (JIT) Alta ~0.2s Media Media
Cython Alta ~0.3s Media Bassa
TensorFlow Alta ~0.8s (include overhead) Alta Media

Per la maggior parte delle applicazioni, NumPy offre il miglior compromesso tra prestazioni e facilità d’uso. Per calcoli estremamente performanti, Numba può offrire significativi miglioramenti.

Errori Comuni e Come Evitarli

Quando si implementa il calcolo dell’angolo tra vettori, è facile incorrere in alcuni errori:

  1. Dimenticare di normalizzare i vettori: Sempre calcolare le magnitudini prima di dividere
  2. Non gestire i vettori nulli: Controllare sempre che le magnitudini non siano zero
  3. Errori di dominio in arccos: Usare np.clip() per assicurarsi che l’input sia in [-1, 1]
  4. Confondere l’ordine dei vettori: L’angolo è lo stesso indipendentemente dall’ordine, ma il prodotto scalare no
  5. Dimenticare la conversione radianti/gradi: Assicurarsi di usare le funzioni corrette (np.degrees, np.radians)
  6. Errori di precisione floating-point: Per applicazioni critiche, considerare l’uso di decimal.Decimal

Estensioni Avanzate

Una volta padronanza del calcolo base, è possibile esplorare estensioni più avanzate:

  1. Angolo tra vettori in spazi n-dimensionali: La formula si generalizza facilmente
  2. Angolo orientato: Usare il prodotto vettoriale per determinare la direzione
  3. Angolo tra rette e piani: Estendere il concetto a geometria 3D
  4. Rotazione di vettori: Usare matrici di rotazione per ruotare un vettore di un angolo specifico
  5. Interpolazione sferica: Animare la transizione tra due vettori

Ecco un esempio di calcolo dell’angolo orientato:

def oriented_angle(a, b, normal=None):
    """Calcola l'angolo orientato tra due vettori"""
    # Angolo base
    angle = angle_between_vectors(a, b)[1]  # in radianti

    if normal is None:
        # Se non specificato, usa la normale standard (prodotto vettoriale)
        normal = np.cross(a, b)

    # Determina la direzione
    cross = np.cross(a, b)
    if np.dot(cross, normal) < 0:
        angle = -angle

    return angle

# Esempio
a = np.array([1, 0, 0])
b = np.array([0, 1, 0])
normal = np.array([0, 0, 1])
print(f"Angolo orientato: {oriented_angle(a, b, normal):.2f} rad")
        

Applicazione Pratica: Calcolo dell'Angolo di Incidenza Solare

Un'applicazione concreta di questo calcolo è la determinazione dell'angolo di incidenza solare su un pannello fotovoltaico:

def solar_incidence_angle(sun_vector, panel_normal):
    """
    Calcola l'angolo di incidenza solare su un pannello
    sun_vector: vettore direzione sole (dovrebbe puntare verso il sole)
    panel_normal: vettore normale al pannello
    """
    # L'angolo di incidenza è l'angolo tra il sole e la normale al pannello
    angle_rad = angle_between_vectors(sun_vector, panel_normal)[1]

    # L'angolo efficace è 90° - angle (perpendicolare = 0°, parallelo = 90°)
    effective_angle = np.pi/2 - angle_rad

    return np.degrees(effective_angle)

# Esempio: sole a 45° di altezza e azimut 0°, pannello inclinato a 30° verso sud
sun_dir = np.array([np.sin(np.radians(45)), 0, np.cos(np.radians(45))])
panel_normal = np.array([np.sin(np.radians(30)), 0, np.cos(np.radians(30))])

incidence_angle = solar_incidence_angle(sun_dir, panel_normal)
print(f"Angolo di incidenza solare: {incidence_angle:.2f}°")
        

Leave a Reply

Your email address will not be published. Required fields are marked *