Probleme mit objekten

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Paul_Roder
User
Beiträge: 2
Registriert: Freitag 18. Mai 2018, 12:52

Freitag 18. Mai 2018, 13:15

Hallo,
Ich bin neu sowohl in Python als auch in der Welt der Foren, deshalb bitte ich um Rücksicht.
Als Übung wollte ich einen Code schreiben der Kugel Koordinaten in Kartesische umwandelt und umgekehrt, sowie mir die Möglichkeit geben, zwei Vektoren zu addieren, dazu ist meines Wissens nach zuerst eine Umformung in Kartesische Koordinaten notwendig, sofern die Vektoren nicht schon als solche Vorliegen.
Hier ist mein Versuch:

Code: Alles auswählen

import math

class Vektor_kugel():#Vektor in Kugelkoordinaten
    def __init__(self, r, phi, theta):
        self.r = r
        self.phi = phi
        self.theta = theta

class Vektor_kart():#Vektor in Karthesischen-koordinaten
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z



def umwandeln_Ika(v):# einen Vektor von Kugel in Karthesiche Koordinaten umwandeln
    e = Vektor_kart
    e.x = v.r * math.cos(v.phi) * math.sin(v.theta)
    e.y = v.r * math.sin(v.phi) * math.sin(v.theta)
    e.z = v.r * math.cos(v.theta)
    return e

def umwandeln_Iku(v):# einen Vektor von Karthesischen in Kugelkoordinaten umwandeln
    e = Vektor_kugel
    e.r = math.sqrt((v.x*v.x)+(v.y*v.y)+(v.z*v.z))
    if (e.r == 0):
        e.phi, e.theta = 0, 0
    elif(v.x == 0):
        e.phi = 0
    else:
    e.phi = math.atan(v.y/v.x) 
    e.theta = math.acos(v.z/e.r)
    return e

def V_addition_kart(v1, v2):# Zwei karthesiche Vektoren addieren
    e = Vektor_kart
    e.x = v1.x + v2.x
    e.y = v1.y + v2.y
    e.z = v1.z + v2.z
    return e

def V_addition_kug(v1, v2):# Zwei Vektoren in Kugelkoordinaten addieren
    return umwandeln_Iku(V_addition_kart(umwandeln_Ika(v1), umwandeln_Ika(v2)))

vektor1 = Vektor_kugel(1, 1, 1)
vektor2 = Vektor_kugel(math.pi, math.pi, math.pi)

vektora = umwandeln_Ika(vektor1)
print(vektora.x, vektora.y, vektora.z)#####Die erste ausgabe
vektorb = umwandeln_Ika(vektor2)

print("Vektor a = ", vektora.x, vektora.y, vektora.z)####Die zweite ausgabe(sollte ja eigentlich der ersten entsprechen, tut es aber nicht)
print("Vektor b = ",vektorb.x, vektorb.y, vektorb.z )

v3 = V_addition_kug(vektor1, vektor2)
print(v3.r, v3.phi, v3.theta)

Dabei bekomme ich Folgendes Ergebniss:
0.4546487134128409 0.7080734182735712 0.5403023058681398
Vektor a = -3.8473413874435795e-16 4.7116343153599164e-32 -3.141592653589793
Vektor b = -3.8473413874435795e-16 4.7116343153599164e-32 -3.141592653589793
6.283185307179586 -1.2246467991473532e-16 3.141592653589793

Erstmal verstehe ich nicht, warum sich vektora ändert, obwohl ich eigentlich nur vektorb umforme.
Wenn ihr sonst noch Tipps zur Notation habt, oder ganz anders an das Problem herangegangen wärt, lasst es mich bitte auch Wissen!
Vielen dank im Vorraus :)!
Sirius3
User
Beiträge: 7796
Registriert: Sonntag 21. Oktober 2012, 17:20

Freitag 18. Mai 2018, 13:44

Einbuchstabige Variablennamen sind schlecht, weil sie nichts aussagen. Was hat denn Dein `e` für einen Datentyp? Du erzeugst keine Instanzen, sondern veränderst die Klassendefinition. Die Funktionen sollten eigentlich Methoden der Klassen sein.
TheLüddy
User
Beiträge: 19
Registriert: Freitag 27. April 2018, 10:17

Freitag 18. Mai 2018, 14:28

Ich würde alle Methoden in der Klasse so definieren, dass sie den entsprechenden Zweck erfüllen. So siehst du zum beispiel, dass ich die methode "umwandeln_Ika()" in beiden Klassen verschieden definiert habe. Dies stellt kein Problem dar, da die Definition intern bleibt.

Code: Alles auswählen

import math

class Vektor_kugel():#Vektor in Kugelkoordinaten
    def __init__(self, r, phi, theta):
        self.r = r
        self.phi = phi
        self.theta = theta

    def umwandeln_Ika(self):
        self.r = self.r*math.cos(self.phi)*math.sin(self.theta)
        self.phi = self.r*math.sin(self.phi)*math.sin(self.theta)
        self.theta = self.r*math.cos(self.theta)
        return self.r, self.phi, self.theta

class Vektor_kart():#Vektor in Karthesischen-koordinaten
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

    def umwandeln_Ika(self):
        return self.x, self.y, self.z


vektor1 = Vektor_kugel(1, 1, 1)
vektor2 = Vektor_kart(math.pi, math.pi, math.pi)

print(vektor1.umwandeln_Ika())
print(vektor2.umwandeln_Ika())
Paul_Roder
User
Beiträge: 2
Registriert: Freitag 18. Mai 2018, 12:52

Freitag 18. Mai 2018, 17:16

Vielen dank für die schnellen Antworten!
Ich habe jetzt verstanden, was ich falsch gemacht habe, aber leider noch nicht wie es richtig geht D:
Bei Lüddy´s Lösung kommt leider ein falsches Ergebnis raus, und bei

Code: Alles auswählen

def umwandeln_Ika(self):
        self.r = self.r*math.cos(self.phi)*math.sin(self.theta)
        self.phi = self.r*math.sin(self.phi)*math.sin(self.theta)
        self.theta = self.r*math.cos(self.theta)
        return self.r, self.phi, self.theta
wird doch die variable r verändert, obwohl sie später noch in ihrem vorherigen zustand nochmal gebraucht werden muss oder nicht?

Auserdem soll die Methode/Funktion(was ist der unterschied?) umwandeln_ika() ja nicht werte r phi und theta sondern x, y und z zurück geben.
Ich habe trotzdem mit dieser Version gearbeitet und müsste doch eigentlich dann durch:

Code: Alles auswählen

alpha = Vektor_kart(vektor1.umwandeln_ika())
einen neuen, karthesischen vektor mit dem Namen alpha erzeugen , der vektor1 in Karthesischen Koordinaten abbildet oder nicht?

aber stattdessen schreibt der:

vektor = Vektor_kart(vektor1.umwandeln_Ika())
TypeError: __init__() missing 2 required positional arguments: 'y' and 'z'

obwohl vektor1.umwandeln_ika() doch eigentlich die zum erzeugen erforderlichen 3 Werte zurückgibt.

Nochmals tausend dank für die Hilfe, bitte habt Gedult, ich mache das ja wie gesagt noch nicht lange, deswegen kann es sein, dass irgendwo ein fundamentales Problem vorliegt.
Benutzeravatar
pillmuncher
User
Beiträge: 1097
Registriert: Samstag 21. März 2009, 22:59
Wohnort: München

Freitag 18. Mai 2018, 20:18

Ich würde es gleich so machen:

Code: Alles auswählen

#!/usr/bin/env python3

import math
import collections


Polar3DPoint = collections.namedtuple('Polar3DPoint', 'radial theta phi')
Cartesian3DPoint = collections.namedtuple('Cartesian3DPoint', 'x y z')


def _default(self):
    return self


def _polar_to_cartesian(self):
    return Cartesian3DPoint(
        x=self.radial * math.sin(self.theta) * math.cos(self.phi),
        y=self.radial * math.sin(self.theta) * math.sin(self.phi),
        z=self.radial * math.cos(self.theta),
    )


def _cartesian_to_polar(self):
    radial = math.sqrt(sum(c ** 2 for c in self))
    if radial == 0:  # Vorsicht: solche Vergleiche können bei Fließkommazahlen in die Hose gehen.
        return Polar3DPoint(
            radial=0,
            theta=0,
            phi=0,
        )
    elif self.x == 0:  # Hier ebenso. Siehe http://floating-point-gui.de/
        return Polar3DPoint(
            radial=radial,
            theta=math.acos(self.z/radial),
            phi=0,
        )
    else:
        return Polar3DPoint(
            radial=radial,
            theta=math.acos(self.z/radial),
            phi=math.atan(self.y/self.x),
        )


def _cartesian_add(self, other):
    return Cartesian3DPoint._make(
        a + b for a, b in zip(self, other.to_cartesian())
    )


def _polar_add(self, other):
    return (self.to_cartesian() + other.to_cartesian()).to_polar()


Polar3DPoint.to_polar = _default
Polar3DPoint.to_cartesian = _polar_to_cartesian
Polar3DPoint.__add__ = _polar_add

Cartesian3DPoint.to_polar = _cartesian_to_polar
Cartesian3DPoint.to_cartesian = _default
Cartesian3DPoint.__add__ = _cartesian_add


def main():
    a = Polar3DPoint(radial=1, theta=2, phi=3)
    b = Cartesian3DPoint(x=1, y=2, z=3)
    print(a + a)
    print(a + b)
    print((b + a).to_polar())
    print((b + b).to_polar())
    print((a + a).to_cartesian())
    print((a + b).to_cartesian())
    print(b + a)
    print(b + b)


if __name__ == '__main__':
    main()
Ergebnis:

Code: Alles auswählen

$ python3 coors.py 
Polar3DPoint(radial=2.0, theta=2.0, phi=-0.14159265358979325)
Polar3DPoint(radial=3.3490303017524248, theta=0.6895650900084984, phi=1.5239380951389667)
Polar3DPoint(radial=3.3490303017524248, theta=0.6895650900084984, phi=1.5239380951389667)
Polar3DPoint(radial=7.483314773547883, theta=0.6405223126794245, phi=1.1071487177940904)
Cartesian3DPoint(x=1.8003952594710348, y=-0.2566401204049135, z=-0.8322936730942848)
Cartesian3DPoint(x=0.09980237026448267, y=2.128320060202457, z=2.5838531634528574)
Cartesian3DPoint(x=0.09980237026448258, y=2.128320060202457, z=2.5838531634528574)
Cartesian3DPoint(x=2, y=4, z=6)
In specifications, Murphy's Law supersedes Ohm's.
Sirius3
User
Beiträge: 7796
Registriert: Sonntag 21. Oktober 2012, 17:20

Samstag 19. Mai 2018, 10:27

Paul_Roder hat geschrieben:aber stattdessen schreibt der:

vektor = Vektor_kart(vektor1.umwandeln_Ika())
TypeError: __init__() missing 2 required positional arguments: 'y' and 'z'
›umwandeln_Ika‹ liefert ein Tuple, ›__init__‹ erwartet aber drei Parameter.

Methoden benutzt man immer dann, wenn man was mit dem Objekt machen will, es zum Beispiel umwandeln. Hier ist es sogar noch so, dass es zwei Objekte gibt, die die selben Methoden hat, aber unterschiedlich arbeiten:

Code: Alles auswählen

import math

class VektorKugel():
    # Vektor in Kugelkoordinaten
    def __init__(self, r, phi, theta):
        self.r = r
        self.phi = phi
        self.theta = theta

    def nach_kugel_koordinaten(self):
        return VektorKugel(self.r, self.phi, self.theta)

    def nach_kartesischen_koordinaten(self):
        return VektorKartesisch(
            self.r * math.cos(self.phi) * math.sin(self.theta),
            self.r * math.sin(self.phi) * math.sin(self.theta),
            self.r * math.cos(self.theta),
        )

    def addieren(self, other):
        this = self.nach_kartesischen_koordinaten()
        return this.addieren(other).nach_kugel_koordinaten()

class VektorKartesisch():
    # Vektor in Karthesischen-koordinaten
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

    def nach_kugel_koordinaten(self):
        r = (self.x ** 2 + self.y ** 2 + self.z ** 2) ** 0.5
        phi = math.atan(self.y / self.x) if self.x else 0
        theta = math.acos(self.z / r) if self.z > r else 0
        return VektorKugel(r, phi, theta)

    def nach_kartesischen_koordinaten(self):
        return VektorKartesisch(self.x, self.y, self.z)

    def addieren(self, other):
        other = other.nach_kartesischen_koordinaten()
        return VektorKartesisch(self.x + other.x, self.y + other.y, self.z + other.z)


vektor1 = VektorKugel(1, 1, 1)
vektor2 = VektorKugel(math.pi, math.pi, math.pi)

vektora = vektor1.nach_kartesischen_koordinaten()
vektorb = vektor2.nach_kartesischen_koordinaten()

print("Vektor a = ", vektora.x, vektora.y, vektora.z)
print("Vektor b = ", vektorb.x, vektorb.y, vektorb.z)

v3 = vektor1.addieren(vektor2)
print(v3.r, v3.phi, v3.theta)
fortgeschritten kann man die Instanzen unveränderbar machen, indem man z.b. namedtuple benutzt:

Code: Alles auswählen

import math
from collections import namedtuple

class VektorKugel(namedtuple("VektorKugel", "r, phi, theta")):
    # Vektor in Kugelkoordinaten
    def nach_kugel_koordinaten(self):
        return self

    def nach_kartesischen_koordinaten(self):
        return VektorKartesisch(
            self.r * math.cos(self.phi) * math.sin(self.theta),
            self.r * math.sin(self.phi) * math.sin(self.theta),
            self.r * math.cos(self.theta),
        )

    def __add__(self, other):
        this = self.nach_kartesischen_koordinaten()
        return (this + other).nach_kugel_koordinaten()

class VektorKartesisch(namedtuple("VektorKartesisch", "x,y,z")):
    def nach_kugel_koordinaten(self):
        r = (self.x ** 2 + self.y ** 2 + self.z ** 2) ** 0.5
        phi = math.atan2(self.y, self.x)
        theta = math.acos(self.z / r) if self.z > r else 0
        return VektorKugel(r, phi, theta)

    def nach_kartesischen_koordinaten(self):
        return self

    def __add__(self, other):
        other = other.nach_kartesischen_koordinaten()
        return VektorKartesisch(self.x + other.x, self.y + other.y, self.z + other.z)


vektor1 = VektorKugel(1, 1, 1)
vektor2 = VektorKugel(math.pi, math.pi, math.pi)

v3 = vektor1 + vektor2
print(v3.r, v3.phi, v3.theta)
Antworten