Elaborar um código em qualquer linguagem de programação que faça a transformação vetorial entre os 3 sistemas de coordenadas (cartesiano, cilíndrico e esférico)

Passo 1

O que o enunciado pede: criar um código (em qualquer linguagem) que faça a transformação vetorial entre os três sistemas de coordenadas — cartesiano, cilíndrico e esférico — isto é, dada a representação das componentes de um vetor em um dos sistemas, devolver as componentes desse mesmo vetor em outro sistema.
Informações e convenções que vou usar (importante para não haver confusão):
  • Coordenadas cartesianas: (x,y,z) com base ortonormal \{\hat{\imath},\hat{\jmath},\hat{k}\}.
  • Coordenadas cilíndricas: (\rho,\varphi,z) com base local \{\hat{\rho},\hat{\varphi},\hat{z}\}, onde \varphi é o ângulo azimutal no plano xy medido a partir do eixo x no sentido anti-horário.
  • Coordenadas esféricas (convenção física): (r,\theta,\varphi) com base local \{\hat{r},\hat{\theta},\hat{\varphi}\}, onde \theta é o ângulo polar (medido a partir do eixo +z) e \varphi é o ângulo azimutal (mesma definição que em cilíndricas).
  • Observação importante: transformação “vetorial” significa transformar as componentes do vetor em relação às bases locais, não apenas transformar as coordenadas do ponto de aplicação. Como as bases dependem da posição (ângulos), é necessário conhecer a posição (ou pelo menos os ângulos) do ponto onde o vetor está definido para realizar a transformação.
  • O código deve tratar casos singulares (por exemplo r=0 ou \rho=0 em que \varphi ou \theta ficam indeterminados) de forma robusta (atribuir um ângulo arbitrário ou retornar aviso).

Passo 2

Transformação entre sistemas — relações fundamentais e como pensar nelas.
  1. Relação entre as bases cartesiana e cilíndrica.
As unidades de base cilíndrica em termos das bases cartesianas valem:
\hat{\rho} = \cos\varphi\\ \hat{\imath} + \sin\varphi\\ \hat{\jmath}, \qquad \hat{\varphi} = -\sin\varphi\\ \hat{\imath} + \cos\varphi\\ \hat{\jmath}, \qquad \hat{z} = \hat{k}.
Isto significa que, se um vetor tem componentes cartesianas (V_x,V_y,V_z) e componentes cilíndricas (V_\rho,V_\varphi,V_z) (note que V_z é o mesmo), então:
\begin{pmatrix} V_\rho \\[4pt] V_\varphi \\[4pt] V_z \end{pmatrix} = \begin{pmatrix} \cos\varphi & \sin\varphi & 0\\[3pt] -\sin\varphi & \cos\varphi & 0\\[3pt] 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} V_x \\[4pt] V_y \\[4pt] V_z \end{pmatrix}.
Como a matriz é ortogonal, a inversa é sua transposta:
\begin{pmatrix} V_x \\[4pt] V_y \\[4pt] V_z \end{pmatrix} = \begin{pmatrix} \cos\varphi & -\sin\varphi & 0\\[3pt] \sin\varphi & \cos\varphi & 0\\[3pt] 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} V_\rho \\[4pt] V_\varphi \\[4pt] V_z \end{pmatrix}.
  1. Relação entre as bases cartesiana e esférica.
As bases esféricas em termos das cartesianas (convenção \theta polar desde +z) são:
\hat{r} = \sin\theta\cos\varphi\\ \hat{\imath} + \sin\theta\sin\varphi\\ \hat{\jmath} + \cos\theta\\ \hat{k},
\hat{\theta} = \cos\theta\cos\varphi\\ \hat{\imath} + \cos\theta\sin\varphi\\ \hat{\jmath} - \sin\theta\\ \hat{k},
\hat{\varphi} = -\sin\varphi\\ \hat{\imath} + \cos\varphi\\ \hat{\jmath}.
Portanto, para componentes cartesianas (V_x,V_y,V_z) e esféricas (V_r,V_\theta,V_\varphi):
\begin{pmatrix} V_r \\[4pt] V_\theta \\[4pt] V_\varphi \end{pmatrix} = \begin{pmatrix} \sin\theta\cos\varphi & \sin\theta\sin\varphi & \cos\theta\\[4pt] \cos\theta\cos\varphi & \cos\theta\sin\varphi & -\sin\theta\\[4pt] -\sin\varphi & \cos\varphi & 0 \end{pmatrix} \begin{pmatrix} V_x \\[4pt] V_y \\[4pt] V_z \end{pmatrix}.
E a inversa (para voltar a cartesianas) é a transposta dessa matriz, porque as bases são mutuamente ortonormais.
  1. Relação entre cilíndricas e esféricas (bases).
As bases esféricas podem ser expressas através das cilíndricas (lembrando que \rho = r\sin\theta e z=r\cos\theta, e que \hat{\varphi} coincide nos dois sistemas):
\hat{r} = \sin\theta\\ \hat{\rho} + \cos\theta\\ \hat{z}, \qquad \hat{\theta} = \cos\theta\\ \hat{\rho} - \sin\theta\\ \hat{z}, \qquad \hat{\varphi} = \hat{\varphi}.
Logo, para componentes:
\begin{pmatrix} V_r \\[4pt] V_\theta \\[4pt] V_\varphi \end{pmatrix} = \begin{pmatrix} \sin\theta & 0 & \cos\theta\\[4pt] \cos\theta & 0 & -\sin\theta\\[4pt] 0 & 1 & 0 \end{pmatrix} \begin{pmatrix} V_\rho \\[4pt] V_\varphi \\[4pt] V_z \end{pmatrix},
e a inversa (spherical → cylindrical) é a transposta:
\begin{pmatrix} V_\rho \\[4pt] V_\varphi \\[4pt] V_z \end{pmatrix} = \begin{pmatrix} \sin\theta & \cos\theta & 0\\[4pt] 0 & 0 & 1\\[4pt] \cos\theta & -\sin\theta & 0 \end{pmatrix} \begin{pmatrix} V_r \\[4pt] V_\theta \\[4pt] V_\varphi \end{pmatrix}.]

Passo 3

Como calcular os ângulos a partir de coordenadas cartesianas (útil no código):
  • \rho = \sqrt{x^2+y^2}.
  • \varphi = \operatorname{atan2}(y,x) — usar a função atan2 para obter o quadrante correto.
  • r = \sqrt{x^2+y^2+z^2}.
  • \theta = \operatorname{atan2}(\rho, z) ou \theta = \operatorname{arccos}\!\left(\dfrac{z}{r}\right) (usar atan2 evita divisão por zero se r=0).
Explicando devagar: a função \operatorname{atan2}(y,x) devolve o ângulo no intervalo (-\pi,\pi] e resolve o sinal de x e y, então é a escolha correta para \varphi. Para \theta, \operatorname{atan2}(\rho,z) dá o ângulo entre o vetor radial e o eixo z.

Passo 4

Casos singulares e cuidados práticos (muito importantes para o código de prova):
  • Se r = 0 (o vetor está na origem), \theta e \varphi são indeterminados: o vetor pode ser representado igualmente em qualquer direção. No código, adotaremos um tratamento consistente (por exemplo fixar \varphi=0, \theta=0 e tratar a transformação com cuidado).
  • Se \rho = 0 (no eixo z), \varphi é indeterminado; novamente fixar \varphi=0 é uma escolha prática.
  • Ao comparar a igualdade de floats, usar tolerância numérica (epsilon) para evitar divisões por zero.
  • Sempre trabalhar com radianos no código.

Passo 5

Um pequeno exemplo numérico (para fixar como aplicar as fórmulas):
Se um vetor tem componentes cartesianas (V_x,V_y,V_z) = (1,1,0) no ponto (x,y,z)=(1,1,0), então:
  • \varphi = \operatorname{atan2}(1,1)=\pi/4.
  • Em cilíndricas:
V_\rho = \cos\varphi\cdot V_x + \sin\varphi\cdot V_y = \tfrac{\sqrt{2}}{2}\cdot 1 + \tfrac{\sqrt{2}}{2}\cdot 1 = \sqrt{2},
V_\varphi = -\sin\varphi\cdot V_x + \cos\varphi\cdot V_y = -\tfrac{\sqrt{2}}{2}\cdot 1 + \tfrac{\sqrt{2}}{2}\cdot 1 = 0,
V_z = 0.
Isso faz sentido: o vetor (1,1,0) aponta radialmente no plano xy, portanto em componentes cilíndricas é puramente radial.

Passo 6

Esboço do algoritmo que o código vai implementar (isto ajuda a escrever o código na prova):
  1. Receber como entrada: componentes do vetor na base de origem e também a posição do ponto (ou os ângulos correspondentes).
  2. Se a posição vier em coordenadas cartesianas, calcular \rho,\varphi,r,\theta usando as fórmulas do Passo 3.
  3. Montar a matriz de transformação apropriada (ver Passo 2) ou aplicar as fórmulas diretas de projeção entre bases.
  4. Aplicar a matriz sobre o vetor de componentes para obter as novas componentes.
  5. Tratar casos singulares com tolerância numérica.
  6. Retornar as componentes no sistema destino e, se desejado, os ângulos usados.

Passo 7

Observações didáticas finais antes do código:
  • As matrizes que apresentei são ortogonais (colunas são vetores unitários ortonormais), então sua inversa é a transposta — isso simplifica muito a implementação: para ir de A→B pode-se construir as componentes de B como o produto das componentes de A pelos produtos escalares entre as bases.
  • No tempo de prova, memorizando as expressões das bases (por exemplo \hat{\rho} e \hat{\varphi} em termos de \hat{\imath},\hat{\jmath}) já se consegue montar rapidamente a pequena matriz 2\times2 do plano xy e as linhas/colunas envolvendo \sin\theta,\cos\theta para esférico.
  • Agora, abaixo está o código final completo que implementa todas as conversões vetoriais entre os três sistemas. Use-o como referência e para testar; ele está comentado e contém funções de utilidade e exemplos de uso.

Resposta

"""
Conversões vetoriais entre sistemas de coordenadas:
- Cartesiano: (x, y, z) com base (i, j, k)
- Cilíndrico: (rho, phi, z) com base (rho_hat, phi_hat, z_hat)
- Esférico : (r, theta, phi) com base (r_hat, theta_hat, phi_hat)

Convenções:
- phi: ângulo azimutal no plano xy, medido a partir do eixo x (atan2(y,x))
- theta: ângulo polar medido a partir do eixo +z (theta = atan2(rho, z))
- Todas as funções esperam/retornam ângulos em radianos.

Funções disponibilizadas:
- cartesian_position_to_spherical(x,y,z) -> (r,theta,phi)
- cartesian_position_to_cylindrical(x,y,z) -> (rho,phi,z)
- cartesian_to_cylindrical_vector(V_cart, x,y,z) -> (V_rho, V_phi, V_z)
- cylindrical_to_cartesian_vector(V_cyl, rho, phi, Vz) -> (Vx, Vy, Vz)
- cartesian_to_spherical_vector(V_cart, x,y,z) -> (V_r, V_theta, V_phi)
- spherical_to_cartesian_vector(V_sph, r, theta, phi) -> (Vx, Vy, Vz)
- cylindrical_to_spherical_vector(V_cyl, rho, phi, z) -> (V_r, V_theta, V_phi)
- spherical_to_cylindrical_vector(V_sph, r, theta, phi) -> (V_rho, V_phi, V_z)

Exemplos de uso no final do arquivo.
"""
from math import sqrt, atan2, sin, cos, isclose

EPS = 1e-12

def cartesian_position_to_cylindrical(x, y, z):
    rho = sqrt(x*x + y*y)
    phi = atan2(y, x) if not (isclose(x, 0.0, abs_tol=EPS) and isclose(y, 0.0, abs_tol=EPS)) else 0.0
    return rho, phi, z

def cartesian_position_to_spherical(x, y, z):
    rho = sqrt(x*x + y*y)
    r = sqrt(rho*rho + z*z)
    if r < EPS:
        # ponto na origem: escolher convenção fixa
        return 0.0, 0.0, 0.0
    phi = atan2(y, x) if not isclose(rho, 0.0, abs_tol=EPS) else 0.0
    theta = atan2(rho, z)  # evita dividir por zero; theta in [0, pi]
    return r, theta, phi

def cartesian_to_cylindrical_vector(V_cart, x, y, z):
    """
    V_cart: tuple/list (Vx, Vy, Vz)
    position: x, y, z (para obter phi)
    retorna: (V_rho, V_phi, V_z)
    """
    Vx, Vy, Vz = V_cart
    rho, phi, _ = cartesian_position_to_cylindrical(x, y, z)
    # phi já está definido mesmo que rho seja zero (convenção = 0)
    c = cos(phi); s = sin(phi)
    V_rho = c*Vx + s*Vy
    V_phi = -s*Vx + c*Vy
    return (V_rho, V_phi, Vz)

def cylindrical_to_cartesian_vector(V_cyl, rho, phi, z=None):
    """
    V_cyl: tuple/list (V_rho, V_phi, V_z)
    rho, phi: posição (phi necessário para orientar as bases)
    z: ignorado para a transformação vetorial (mantido por simetria)
    retorna: (Vx, Vy, Vz)
    """
    V_rho, V_phi, V_z = V_cyl
    c = cos(phi); s = sin(phi)
    Vx = c*V_rho - s*V_phi
    Vy = s*V_rho + c*V_phi
    return (Vx, Vy, V_z)

def cartesian_to_spherical_vector(V_cart, x, y, z):
    """
    V_cart: (Vx, Vy, Vz)
    position: x,y,z (para r,theta,phi)
    retorna: (V_r, V_theta, V_phi)
    """
    Vx, Vy, Vz = V_cart
    r, theta, phi = cartesian_position_to_spherical(x, y, z)
    # Se r == 0, ângulos arbitrários; mas as componentes esféricas ficam indefinidas.
    # Tratamos com convenção: theta=0,phi=0 retornando componentes coerentes.
    cphi = cos(phi); sphi = sin(phi)
    st = sin(theta); ct = cos(theta)
    V_r = st*cphi*Vx + st*sphi*Vy + ct*Vz
    V_theta = ct*cphi*Vx + ct*sphi*Vy - st*Vz
    V_phi = -sphi*Vx + cphi*Vy
    return (V_r, V_theta, V_phi)

def spherical_to_cartesian_vector(V_sph, r, theta, phi):
    """
    V_sph: (V_r, V_theta, V_phi)
    posição esférica r, theta, phi (apenas theta e phi são necessários para as bases)
    retorna: (Vx, Vy, Vz)
    """
    V_r, V_theta, V_phi = V_sph
    cphi = cos(phi); sphi = sin(phi)
    st = sin(theta); ct = cos(theta)
    Vx = st*cphi*V_r + ct*cphi*V_theta - sphi*V_phi
    Vy = st*sphi*V_r + ct*sphi*V_theta + cphi*V_phi
    Vz = ct*V_r - st*V_theta
    return (Vx, Vy, Vz)

def cylindrical_to_spherical_vector(V_cyl, rho, phi, z):
    """
    V_cyl: (V_rho, V_phi, V_z)
    posição: rho, phi, z (para obter theta)
    retorna: (V_r, V_theta, V_phi)
    """
    V_rho, V_phi, V_z = V_cyl
    # calcular theta a partir de rho,z
    if abs(rho) < EPS and abs(z) < EPS:
        theta = 0.0
    else:
        theta = atan2(rho, z)
    st = sin(theta); ct = cos(theta)
    V_r = st*V_rho + ct*V_z
    V_theta = ct*V_rho - st*V_z
    V_ph = V_phi
    return (V_r, V_theta, V_ph)

def spherical_to_cylindrical_vector(V_sph, r, theta, phi):
    """
    V_sph: (V_r, V_theta, V_phi)
    posição: r, theta, phi (theta necessário)
    retorna: (V_rho, V_phi, V_z)
    """
    V_r, V_theta, V_phi = V_sph
    st = sin(theta); ct = cos(theta)
    V_rho = st*V_r + ct*V_theta
    V_z = ct*V_r - st*V_theta
    V_ph = V_phi
    return (V_rho, V_ph, V_z)

# Exemplos de uso e testes simples
if __name__ == "__main__":
    # Exemplo 1: vetor cartesiano no ponto (1,1,0)
    V_cart = (1.0, 1.0, 0.0)
    x, y, z = 1.0, 1.0, 0.0
    V_cyl = cartesian_to_cylindrical_vector(V_cart, x, y, z)
    print("Cart -> Cyl:", V_cyl)  # espera (sqrt(2), ~0, 0)

    # Exemplo 2: voltar para cartesiano
    rho, phi, _ = cartesian_position_to_cylindrical(x, y, z)
    V_cart_back = cylindrical_to_cartesian_vector(V_cyl, rho, phi)
    print("Cyl -> Cart:", V_cart_back)  # deve recuperar (1,1,0)

    # Exemplo 3: cartesiano -> esférico (vetorial)
    V_sph = cartesian_to_spherical_vector(V_cart, x, y, z)
    print("Cart -> Sph:", V_sph)

    # Exemplo 4: esférico -> cartesiano (usar r,theta,phi do ponto)
    r, theta, phi = cartesian_position_to_spherical(x, y, z)
    V_cart_back2 = spherical_to_cartesian_vector(V_sph, r, theta, phi)
    print("Sph -> Cart:", V_cart_back2)  # deve recuperar aproximado (1,1,0)

    # Exemplo 5: cilíndrico <-> esférico
    V_cyl_example = (1.0, 0.5, -0.2)
    rho, phi, z = cartesian_position_to_cylindrical(x, y, z)
    V_sph_from_cyl = cylindrical_to_spherical_vector(V_cyl_example, rho, phi, z)
    print("Cyl -> Sph:", V_sph_from_cyl)
    V_cyl_back = spherical_to_cylindrical_vector(V_sph_from_cyl, *cartesian_position_to_spherical(x,y,z))
    print("Sph -> Cyl:", V_cyl_back)

Exercícios relacionados