2016-08-17 4 views
2

私は、hereの次の擬似コードに基づいて、Pythonの表面法線ベクトルを計算するためのNewellのメソッドを実装しようとしています。その時点でn[0.0, 0.0, 0.0]あるので、Newellのメソッドを使用してPythonの表面法線を計算する

Point3D = collections.namedtuple('Point3D', 'x y z') 

def surface_normal(poly): 
    n = [0.0, 0.0, 0.0] 

    for i, v_curr in enumerate(poly): 
     v_next = poly[(i+1) % len(poly)] 
     n[0] += (v_curr.y - v_next.y) * (v_curr.z - v_next.z) 
     n[1] += (v_curr.z - v_next.z) * (v_curr.x - v_next.x) 
     n[2] += (v_curr.x - v_next.x) * (v_curr.y - v_next.y) 

    normalised = [i/sum(n) for i in n] 

    return normalised 

def test_surface_normal(): 
    poly = [Point3D(0.0, 0.0, 0.0), 
      Point3D(0.0, 1.0, 0.0), 
      Point3D(1.0, 1.0, 0.0), 
      Point3D(1.0, 0.0, 0.0)] 

    assert surface_normal(poly) == [0.0, 0.0, 1.0] 

これは、正規化ステップで失敗:

Begin Function CalculateSurfaceNormal (Input Polygon) Returns Vector 

    Set Vertex Normal to (0, 0, 0) 

    Begin Cycle for Index in [0, Polygon.vertexNumber) 

     Set Vertex Current to Polygon.verts[Index] 
     Set Vertex Next to Polygon.verts[(Index plus 1) mod Polygon.vertexNumber] 

     Set Normal.x to Sum of Normal.x and (multiply (Current.y minus Next.y) by (Current.z plus Next.z)) 
     Set Normal.y to Sum of Normal.y and (multiply (Current.z minus Next.z) by (Current.x plus Next.x)) 
     Set Normal.z to Sum of Normal.z and (multiply (Current.x minus Next.x) by (Current.y plus Next.y)) 

    End Cycle 

    Returning Normalize(Normal) 

End Function 

は、ここに私のコードです。正しく理解している場合は、[0.0, 0.0, 1.0](Wolfram Alphaのconfirmed)にする必要があります。

私はここで間違っていますか?そして、Pythonで表面法線を計算する良い方法はありますか?私のポリゴンは常に平面であるため、別の方法がある場合は、Newellのメソッドは絶対に必要なわけではありません。

答えて

0

問題は実際には愚かなものでした。等

行:

n[0] += (v_curr.y - v_next.y) * (v_curr.z - v_next.z) 

にすべきである:

n[0] += (v_curr.y - v_next.y) * (v_curr.z + v_next.z) 

ブラケットの第二のセットの値が減算されない、添加されるべきです。

1

Newellの方法に代わるアプローチをしたい場合は、2つの非平行ベクトルのクロス積を使用することができます。それはあなたがそれを提供するほぼすべての平面形状で機能するはずです。私は理論が凸多面体のためのものだと知っていますが、Wolfram Alphaで見た例では、凹面のポリゴンについても適切なサーフェス法線が返されます(例えば、bowtieポリゴン)。

+0

はい、有効なベクトルではない '[0,0,0]'を正規化しようとしているので、ゼロで割ります。それはコードのその時点の値であってはなりません。そして、平面で、私は最初のものを意味します。 3D空間内の2Dポリゴン。 –

+0

さて、私もそれを持っていました(これを使って避けました - 'normalised = [i/sum(n)ならsum(n)!= 0.0 else in 0 for i]' - 。あなたのポリゴンは常に凸であるか、そうでないポリゴンを持つことは可能でしょうか? – dblclik

+0

これらは、自己交差していなくても、どのような形状であってもかまいません。そして、あなたの回避策は失敗します。たとえば、 '[-0.5、0.0、0.5] 'というベクトルで失敗するかもしれません。 'try:except:'ブロックを使っていましたが、アルゴリズムが正しく動作していれば必要ではありません。 –

関連する問題