9

【追記:問題解決!投稿の下部を参照]

Python 開発者がパックされたデータ (この場合は頂点) の配列を API に渡せるようにする必要があります。これは、Python C API を介して手動で公開された一連の C++ インターフェイスです。これに関する私の最初の印象は、ctypes Structure クラスを使用して、次のようなインターフェイスを可能にすることです。

class Vertex(Structure):
_fields_ = [
    ('x', c_float),
    ('y', c_float),
    ('z', c_float),
    ('u', c_float),
    ('v', c_float),
    ('color', c_int)
] 

verts = (Vertex * 3)()
verts[0] = Vertex(0.0, 0.5, 0.0, 0.0, 0.5, 0xFF0000FF)
verts[1] = Vertex(0.5, -0.5, 0.0, 0.5, -0.5, 0x00FF00FF)
verts[2] = Vertex(-0.5, -0.5, 0.0, -0.5, -0.5, 0x0000FFFF)

device.ReadVertices(verts, 3) # This is the interfaces to the C++ object

渡そうとしている関数には、次の署名があります。

void Device::ReadVertices(Vertex* verts, int count);

Python ラッパーは次のようになります。

static PyObject* Device_ReadVertices(Py_Device* self, PyObject* args)
{
    PyObject* py_verts;
    int count;

    if(!PyArg_ParseTuple(args, "Oi", &py_verts, &count)) 
        return NULL;

    // This Doesn't Work!
    Vertex* verts = static_cast<Vertex*>(PyCObject_AsVoidPtr(py_verts));

    self->device->ReadVertices(verts, count);

    Py_RETURN_NONE;
}

もちろん、私が抱えている最大の問題は次のとおりです。構造体の PyObject を取得できますが、それを正しい型にキャストする方法がわかりません。上記のコードは惨めに失敗します。では、ユーザーがこの種のデータを Python から渡してくれるのをどのように許可すればよいのでしょうか?

さて、考慮すべき点がいくつかあります。まず、かなりの量の Python/C++ 層が既に作成されており、それに完全に満足しています (SWIG から離れたので、柔軟性を高めることができました)。再コーディングしたくないので、C API でネイティブに動作するソリューションを希望します。次に、Vertex 構造体を C++ コードで事前に定義するつもりなので、ユーザーが Python で再定義する必要がないようにしたいと思います (その方法でエラーを減らします)。そのような連続した構造を公開する方法がわかりません。第三に、ctypes 構造を試す理由が他にありません。別の方法を知りません。どんな提案でも大歓迎です。最後に、これは (ご想像のとおり) グラフィックス アプリ用であるため、高速な方法が少し手間がかかるとしても、便利な方法よりも高速な方法をお勧めします。

助けてくれてありがとう!Python 拡張機能についてはまだ手探りの状態なので、重要な部分についてコミュニティの意見を聞くことは大きな助けになります。

[解決]

まず最初に、アイデアを提案してくれたすべての人に感謝します。最終的な答えにつながったのは、多くの小さな情報でした。最後に、私が見つけたものは次のとおりです。struct.packを使用するというSamの提案は、最終的にはお金に見合ったものになりました。私は Python 3 を使用しているので、微調整する必要がありましたが、最終的には、画面に三角形が表示されました。

verts = bytes()
verts += struct.pack("fffffI", 0.0, 0.5, 0.0, 0.0, 0.5, 0xFF0000FF)
verts += struct.pack("fffffI", 0.5, -0.5, 0.0, 0.5, -0.5, 0x00FF00FF)
verts += struct.pack("fffffI", -0.5, -0.5, 0.0, -0.5, -0.5, 0x0000FFFF)

device.ReadVertices(verts, 3)

タプルの解析は次のようになります。

static PyObject* Device_ReadVertices(Py_Device* self, PyObject* args)
{
    void* py_verts;
    int len, count;

    if(!PyArg_ParseTuple(args, "y#i", &py_verts, &len, &count)) 
        return NULL;

    // Works now!
    Vertex* verts = static_cast<Vertex*>(py_verts);

    self->device->ReadVertices(verts, count);

    Py_RETURN_NONE;
}

この例では変数を使用していませんがlen(最終製品では使用しますが)、単に 'y' の代わりに 'y#' を使用してタプルを解析する必要があることに注意してください。そうしないと、最初の NULL (ドキュメントによると)。また、考慮すべきこと: このような void* キャストは非常に危険です。そのため、ここで示すよりも多くのエラー チェックを実行してください。

それで、仕事はよくやった、幸せな一日、荷物をまとめて家に帰りますか?

待って!そんなに早くない!もっとあります!

すべてがうまくいったことに満足していたので、気まぐれで、前回の試みがまだうまくいかないかどうかを確認し、この投稿の python の最初のスニペットに戻ったかどうかを確認することにしました。(もちろん、新しい C コードを使用して) そして... うまくいきました! 結果は struct.pack バージョンと同じでした! わお!

したがって、これは、ユーザーがこの種のデータを提供する方法を選択できることを意味し、コードは変更なしでどちらも処理できます。個人的には、読みやすくするために ctype.Structure メソッドをお勧めしますが、実際には、ユーザーが快適に使用できる方法です。(ほら、彼らが望むなら、16 進数でバイトの文字列を手動で入力することができます。それは動作します。私は試しました。)

正直なところ、これが可能な限り最高の結果だと思うので、私は有頂天です。この問題に遭遇した他のすべての人に幸運を祈ります。

4

2 に答える 2

2

テストされていませんが、これを試してみて、ニーズに十分な速さであるかどうかをお知らせください。

Python 側では、頂点をオブジェクトではなく文字列にパックします。

str = "" # byte stream for encoding data
str += struct.pack("5f i", vert1.x, vert1.y, vert1.z, vert1.u, vert1.v, vert1.color) # 5 floats and an int
# same for other vertices

device. ReadVertices( verts, 3) # send vertices to C library

C ライブラリ/python ラッパーで、フォーマット文字列を使用するように PyArgs_ParseTuple を変更します"si"。これにより、Python 文字列が C 文字列 (char*) に変換され、ベクター構造体へのポインターとして型キャストできます。この時点で、C 文字列はバイト/単語/フロートのストリームであり、探しているものになるはずです。

幸運を!

于 2010-02-22T03:51:46.787 に答える
1

私が見ることができる最も簡単な方法は、問題を完全に回避し、x、y、z、u、v、および色を引数として受け取る Device_ReadVertex を公開することです。これには、Python プログラマーが頂点を 1 つずつフィードするようにするなど、明らかな欠点があります。

それが十分でない場合 (そうではない可能性が高い)、ここで説明されているように新しい Python 型を定義してみてください。もう少しコードが長くなりますが、Python 開発者が C コードと同じ型定義を使用していることを確認できるため、これは「よりアーキテクチャ的に健全な」方法だと思います。また、単純な構造体 (実際にはクラスであり、メソッドを追加する可能性があるなど) よりも少し柔軟性があり、実際に必要かどうかはわかりませんが、後で便利になる可能性があります。

于 2010-02-22T04:02:40.827 に答える