85613
3次元の三角形です。よろしくお願いします。

(参考)SymPy 1.9 documentation » SymPy Modules Reference » Geometry » Plane

<https://docs.sympy.org/latest/modules/geometry/plane.html>

(参考)2.8.1 クラスの定義＜Pythonのテキスト作りました - Qiita

<https://ktechlabo.xsrv.jp/www_python/python_main.pdf#page=132>

```

    from sympy import *
    def myPtoM(myPoint3D):
        return Matrix([myPoint3D.x,myPoint3D.y,myPoint3D.z])
    def myMtoP(myMatrix):
        return Point3D(myMatrix[0],myMatrix[1],myMatrix[2])
    def myCrosstoP(P1,P2):
        return myMtoP(myPtoM(P1).cross(myPtoM(P2)))
    def myPlane(myA,myB,myC):
        return Plane(myA, normal_vector=myCrosstoP(myB-myA,myC-myA))
    class myPlaneClass:
        def __init__(self,myA,myB,myC):
            Plane(myA, normal_vector=myCrosstoP(myB - myA, myC - myA))
            print(" 私のインスタンス ", self," が作成されました． ")
        def __del__(self):
            print(" 私のインスタンス ", self," が廃棄されました． ")
    O=Point3D(0.0,0.0,0.0)
    A=Point3D(1.0,0.0,0.0)
    B=Point3D(0.0,1.0,0.0)
    C=Point3D(1.0,1.0,1.0)
    myPL=myPlane(O,A,B)
    print("#1",type(myPL),myPL,myPL.projection(C))
    #
    myPLC=myPlaneClass(O,A,B)
    print("#2",type(myPLC),myPLC,myPLC.projection(C))
    myPLC=None
    #
    # Traceback (most recent call last):
    #   File "C:/Users/xxx/PycharmProjects/pythonProject/main.py", line 30, in <module>
    # #1 <class 'sympy.geometry.plane.Plane'> Plane(Point3D(0, 0, 0), (0, 0, 1)) Point3D(1, 1, 0)
    #  私のインスタンス  <__main__.myPlaneClass object at 0x0000014AFA33DE80>  が作成されました．
    #     print("#2",type(myPLC),myPLC,myPLC.projection(C))
    # AttributeError: 'myPlaneClass' object has no attribute 'projection'
    #  私のインスタンス  <__main__.myPlaneClass object at 0x0000014AFA33DE80>  が廃棄されました．
    
```

(2022-01-11)  
ありがとうございます。  
継承、スパークラス？サブクラス？を勉強していく予定です。

```

    from sympy import *
    def myPtoM(myPoint3D):
        return Matrix([myPoint3D.x,myPoint3D.y,myPoint3D.z])
    def myMtoP(myMatrix):
        return Point3D(myMatrix[0],myMatrix[1],myMatrix[2])
    def myCrosstoP(P1,P2):
        return myMtoP(myPtoM(P1).cross(myPtoM(P2)))
    def myPlane(myA,myB,myC):
        return Plane(myA, normal_vector=myCrosstoP(myB-myA,myC-myA))
    class myPlaneClass:
        def __init__(self,myA,myB,myC):
            self.myPLField = Plane(myA, normal_vector=myCrosstoP(myB - myA, myC - myA))
        def projection(self,C):
            return self.myPLField.projection(C)
    myZahyo=((0.0,0.0,0.0),(1.0,0.0,0.0),(0.0,1.0,0.0),(1.0,1.0,1.0))
    O=Point3D(myZahyo[0])
    A=Point3D(myZahyo[1])
    B=Point3D(myZahyo[2])
    C=Point3D(myZahyo[3])
    myPLC=myPlaneClass(O,A,B)
    print("#",myPLC.projection(C),myPLC.projection(C).distance(C))
    # Point3D(1, 1, 0) 1
    
```

(2022-01-12)  
後から値を代入。

```

    from sympy import *
    def myPtoM(myPoint3D):
        return Matrix([myPoint3D.x,myPoint3D.y,myPoint3D.z])
    def myMtoP(myMatrix):
        return Point3D(myMatrix[0],myMatrix[1],myMatrix[2])
    def myCrosstoP(P1,P2):
        return myMtoP(myPtoM(P1).cross(myPtoM(P2)))
    def myPlane(myA,myB,myC):
        return Plane(myA, normal_vector=myCrosstoP(myB-myA,myC-myA))
    class myPlaneClass:
        def __init__(self,myA,myB,myC):
            self.myPLField = Plane(myA, normal_vector=myCrosstoP(myB - myA, myC - myA))
        def projection(self,C):
            return self.myPLField.projection(C)
    # myZahyo=((0.0,0.0,0.0),(1.0,0.0,0.0),(0.0,1.0,0.0),(1.0,1.0,1.0))
    var('Ox Oy Oz Ax Ay Az Bx By Bz Cx Cy Cz')
    myZahyo=((Ox,Oy,Oz),(Ax,Ay,Az),(Bx,By,Bz),(Cx,Cy,Cz))
    O=Point3D(myZahyo[0])
    A=Point3D(myZahyo[1])
    B=Point3D(myZahyo[2])
    C=Point3D(myZahyo[3])
    myPLC=myPlaneClass(O,A,B)
    mySubs={Ox:0.0,Oy:0.0,Oz:0.0,Ax:1.0,Ay:0.0,Az:0.0,Bx:0.0,By:1.0,Bz:0.0,Cx:1.0,Cy:1.0,Cz:1.0}
    print("#",myPLC.projection(C)             ,myPLC.projection(C).distance(C))
    print("#",myPLC.projection(C).subs(mySubs),myPLC.projection(C).distance(C).subs(mySubs))
    # (省略)
    # Point3D(1, 1, 0) 1.00000000000000
    
```
CC BY-SA 4.0
2022-01-11T01:28:25.570
85610
2022-01-11T23:58:54.783
2022-01-11T23:58:54.783
17199
17199
question
python sympy
Pythonのclassの作り方を教えて下さい。「...object has no attribute...」(3Dの三角形)
クラス自体は作成できていますので、ご質問の意図は  
「コード実行時に `AttributeError: 'myPlaneClass' object has no attribute 'projection'`
エラーが発生する問題を解決したい」  
であると仮定して回答します。

`myPlaneClass`には`projection`関数が定義されていないことが直接の原因です。  
ではなぜ`myPL.projection(C)`が実行できているのかと申しますと、`myPL`関数は`projection`関数が定義済みの`Plane`クラス自体を戻り値として`return`しているからです。

なのでサンプルコードのように、コンストラクタで作成した`Plane`クラスのインスタンスをメンバ変数として保持しておき、メンバ変数の`projection`関数を内部的に呼び出すラッパー関数などの仕組みを作成することでエラーを回避できます。

**サンプルコード**

```

    from sympy import *
    def myPtoM(myPoint3D):
        return Matrix([myPoint3D.x,myPoint3D.y,myPoint3D.z])
    def myMtoP(myMatrix):
        return Point3D(myMatrix[0],myMatrix[1],myMatrix[2])
    def myCrosstoP(P1,P2):
        return myMtoP(myPtoM(P1).cross(myPtoM(P2)))
    def myPlane(myA,myB,myC):
        return Plane(myA, normal_vector=myCrosstoP(myB-myA,myC-myA))
    class myPlaneClass:
        def __init__(self,myA,myB,myC):
            # メンバ変数(myPLField)としてPlaneを保持する
            self.myPLField = Plane(myA, normal_vector=myCrosstoP(myB - myA, myC - myA))
            print(" 私のインスタンス ", self," が作成されました． ")
        def __del__(self):
            print(" 私のインスタンス ", self," が廃棄されました． ")
        # メンバ変数(myPLField)のprojection関数を呼び出すラッパー関数
        def projection(self,C):
            return self.myPLField.projection(C)
    O=Point3D(0.0,0.0,0.0)
    A=Point3D(1.0,0.0,0.0)
    B=Point3D(0.0,1.0,0.0)
    C=Point3D(1.0,1.0,1.0)
    myPL=myPlane(O,A,B)
    print("#1",type(myPL),myPL,myPL.projection(C))
    #
    myPLC=myPlaneClass(O,A,B)
    # myPlaneClassで定義したprojection関数を呼び出す
    print("#2",type(myPLC),myPLC,myPLC.projection(C))
    myPLC=None
    
```

**実行結果**

```

    #1 <class 'sympy.geometry.plane.Plane'> Plane(Point3D(0, 0, 0), (0, 0, 1)) Point3D(1, 1, 0) 
     私のインスタンス  <__main__.myPlaneClass object at 0x000001F2265AB0A0>  が作成されました． 
    #2 <class '__main__.myPlaneClass'> <__main__.myPlaneClass object at 0x000001F2265AB0A0> Point3D(1, 1, 0)
     私のインスタンス  <__main__.myPlaneClass object at 0x000001F2265AB0A0>  が廃棄されました．
    
```

以下は余談です。(難しければ読み飛ばしてください)

`myPlaneClass`のコンストラクタで`myA,myB,myC`をそれぞれ独立したメンバ変数として宣言しておき、`projection`関数からそれらの変数を引数として`myPlane`関数を呼び出すコーディングも可能です。  
`myPlane`関数は毎回`Plane`のインスタンス作成を行うので処理コストはかかりますが、処理の途中で`myA,myB,myC`の値が変更されても柔軟に対応できます。

上記の他に`class myPlaneClass(Plane):`の構文で継承を使用できるはずです。(試してはいません)  
`super()`による継承元のコンストラクタ呼び出しや関数のオーバーロードなど、使用に際して理解すべき内容は増えますが、ソースコードを短く記述することができます。
CC BY-SA 4.0
2022-01-11T06:09:35.337
85613
2022-01-11T06:09:35.337
9820
85610
answer