Gå til indholdet

Tutorial 2: Konvertering mellem Kartesiske og Polære Koordinater i 2D

Ofte er det nødvendigt at kunne skifte mellem det kartesiske koordinatsystem \((x, y)\) og det polære koordinatsystem \((r, \theta)\). Denne tutorial beskriver, hvordan man konverterer koordinater mellem disse to systemer i to dimensioner. Trigonometri spiller en central rolle i disse konverteringer.

Konverteringen fra polære til kartesiske koordinater følger direkte fra definitionerne af sinus og cosinus i en retvinklet trekant:

  • \(x = r \cos \theta\)
  • \(y = r \sin \theta\)

Disse ligninger gælder for alle værdier af \(r\) og \(\theta\), også for "usædvanlige" værdier, hvilket betyder, at aliasing ikke er et problem i denne konvertering.

Konvertering fra kartesiske \((x, y)\) til polære \((r, \theta)\) koordinater er mere kompleks på grund af aliasing, da der er uendeligt mange \((r, \theta)\)-par, der kan beskrive et givent \((x, y)\)-punkt. Normalt ønsker vi at finde de kanoniske polære koordinater.

Radius \(r\) kan nemt beregnes ved hjælp af Pythagoras' læresætning:

  • \(r = \sqrt{x^2 + y^2}\)

Da kvadratrodsfunktionen altid returnerer den positive rod, vil den beregnede værdi af \(r\) altid være ikke-negativ, hvilket er i overensstemmelse med den kanoniske form.

Beregningen af vinklen \(\theta\) er mere udfordrende. Et umiddelbart forsøg kunne være at bruge tangens:

\[ \frac{y}{x} = \frac{r \sin \theta}{r \cos \theta} = \tan \theta \implies \theta = \arctan\left(\frac{y}{x}\right) \]

Dog er der to problemer med denne tilgang:

  1. Hvis \(x = 0\), er divisionen \(y/x\) udefineret.
  2. Arctan-funktionen (\(=\tan^{-1}\)) har kun et værdiområde på \([-90^\circ, +90^\circ]\) (eller \([-\pi/2, +\pi/2]\) radianer), dvs i første og fjerde kvadrant.

Problemet er, at divisionen \(y/x\) mister information om fortegnene på \(x\) og \(y\), hvilket er nødvendigt for at bestemme den korrekte kvadrant for vinklen.

En bedre løsning er at bruge den såkaldte atan2-funktion, som tager både \(y\) og \(x\) som argumenter og korrekt beregner vinklen \(\theta\) i alle fire kvadranter, bortset fra ved origo. Definitionen af atan2-funktionen, som bruges i mange programmeringssprog, er:

\[ \text{atan2}(y, x) = \begin{cases} 0, & x = 0, y = 0 \\ +90^\circ, & x = 0, y > 0 \\ -90^\circ, & x = 0, y < 0 \\ \arctan(y/x), & x > 0 \\ \arctan(y/x) + 180^\circ, & x < 0, y \geq 0 \\ \arctan(y/x) - 180^\circ, & x < 0, y < 0 \end{cases} \]

Ved hjælp af atan2-funktionen kan de kanoniske polære koordinater \((r, \theta)\) beregnes fra de kartesiske koordinater \((x, y)\) som:

  • \(r = \sqrt{x^2 + y^2}\)
  • \(\theta = \text{atan2}(y, x)\)

💻 Konvertering mellem polære og kartesiske koordinater Python

I polar_til_kartesisk()-funktionen skal du huske at konvertere vinklen \(\theta\) fra grader til radianer, hvis du bruger trigonometriske funktioner som math.cos() og math.sin(). Det kan du gøre med math.radians(theta). Husk, du også kan bruge numpy til koden.

import math

def polar_to_cartesian(r, theta):
    """Konverterer polære koordinater til kartesiske."""
    x = r * math.cos(theta)
    y = r * math.sin(theta)
    return x, y

def cartesian_to_polar(x, y):
    """Konverterer kartesiske koordinater til polære."""
    r = math.sqrt(x*x + y*y)
    theta = math.atan2(y, x)
    return r, theta
Her kan du se en animation af atan2-funktionen, som beregner vinklen \(\theta\) i alle kvadranter:

Optimering af beregninger

Når du arbejder med polære koordinater, er det ofte en god idé at overveje disse optimeringstips:

  1. Undgå unødvendige konverteringer mellem polære og kartesiske koordinater
  2. Brug biblioteksfunktioner som atan2() i stedet for selv at implementere dem
  3. Vær opmærksom på præcisionstab ved flydende kommatal
  4. Håndter edge cases korrekt (f.eks. ved nulpunktet eller ved polerne)

💻 Plotte med polære koordinater i Python

Med dette kode kan du plotte punkter givet i polære koordinater \((r, \theta)\) i et kartesisk koordinatsystem. Bemærk, at vinklerne kan angives i grader eller radianer, afhængigt af is_degrees-parameteren.

import numpy as np
import matplotlib.pyplot as plt

# Konverter grader til radianer hvor det er nødvendigt
def to_rad(angle, is_degrees=True):
    return np.radians(angle) if is_degrees else angle

# Konverter polære koordinater (r, theta) til kartesiske (x, y)
def polar_to_cartesian(r, theta, is_degrees=True):
    theta_rad = to_rad(theta, is_degrees)
    x = r * np.cos(theta_rad)
    y = r * np.sin(theta_rad)
    return x, y

# Punkter givet i polære koordinater (r, theta)
# Format: (r, theta, is_degrees)
points = {
    'a': (3, 30, True),
    'b': (2, 295, True),
    'c': (5, -95, True),
    'd': (-3.75, 320, True),  # Negativ r med vinkel 320°
    'e': (2, np.pi/7, False),
    'f': (1.5, np.pi/3, False),
    'g': (-7/2, -np.pi/4, False)  # Negativ r med vinkel -π/2
}

# Opsætning af plot
fig, ax = plt.subplots(figsize=(8, 8))
ax.set_aspect('equal')
ax.grid(True)
ax.axhline(y=0, color='k', linestyle='-', alpha=0.3)
ax.axvline(x=0, color='k', linestyle='-', alpha=0.3)

# Fremhæv den positive x-akse (polær 0-akse) med blå pil
ax.arrow(0, 0, 4.7, 0, head_width=0.2, head_length=0.3, fc='blue', ec='blue', linewidth=2, alpha=0.7)

# Plot punkter
for label, (r, theta, is_degrees) in points.items():
    x, y = polar_to_cartesian(r, theta, is_degrees)

    # Format legend text with rounded display for radians
    if is_degrees:
        legend_text = f'{label}: ({r}, {theta}°)'
    else:
        legend_text = f'{label}: ({r}, {theta:.2f} rad)'

    ax.scatter(x, y, s=100, label=legend_text)
    ax.annotate(label, (x, y), xytext=(5, 5), textcoords='offset points', fontsize=12)

# Tegn cirkler for at hjælpe med visualisering
theta = np.linspace(0, 2*np.pi, 100)
for radius in [1, 2, 3, 4, 5]:
    ax.plot(radius * np.cos(theta), radius * np.sin(theta), 'k--', alpha=0.2)

# Tilføj polære akselinjer med radianer
for i, angle in enumerate(np.arange(0, 2*np.pi, np.pi/6)):
    ax.plot([0, 6*np.cos(angle)], [0, 6*np.sin(angle)], 'k--', alpha=0.2)

    # Vælg label baseret på vinklen
    if angle == 0:
        continue  # Spring over 0, da vi allerede har markeret det med blå
    elif angle == np.pi/6:
        label = "π/6"
    elif angle == np.pi/3:
        label = "π/3"
    elif angle == np.pi/2:
        label = "π/2"
    elif angle == 2*np.pi/3:
        label = "2π/3"
    elif angle == 5*np.pi/6:
        label = "5π/6"
    elif angle == np.pi:
        label = "π"
    elif angle == 7*np.pi/6:
        label = "7π/6"
    elif angle == 4*np.pi/3:
        label = "4π/3"
    elif angle == 3*np.pi/2:
        label = "3π/2"
    elif angle == 5*np.pi/3:
        label = "5π/3"
    elif angle == 11*np.pi/6:
        label = "11π/6"
    else:
        label = f"{i}π/6"

    ax.annotate(label, (6.2*np.cos(angle), 6.2*np.sin(angle)), 
                fontsize=8, ha='center', va='center')

# Indstil grænser og etiketter
ax.set_xlim(-6, 6)
ax.set_ylim(-6, 6)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_title('Punkter i Polære Koordinater')

# Tilføj forklaring
ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left')

plt.tight_layout()
plt.show()