回答:
無限に線を引き、シェイプを横切る回数(偶数または奇数)をカウントします。クリーチャーが存在するセグメントはカウントしません。次に、クリーチャーがその行の左または右に移動しているかどうかを確認します。
この例では、形状を2回(非常に均等に)交差させて、左に進みます。結果はこの表からすぐに得られます:
# Crosses | even | odd
Direction | |
-------------+-------+------
left | CCW | CW
right | CW | CCW
擬似コードで:
x, y = position of creature
vx, vy = direction of creature movement
crossings = 0
for each x1, y1, x2, y2 in shape segments:
if (x1 < x and x <= x2) or (x2 < x and x <= x1):
if y - y1 > (x - x1) * (y2 - y1) / (x2 - x1):
++crossings
if (crossings & 1) == (vx < 0):
return CW
else
return CCW
シェイプデータ構造から取得できる情報によって異なりますが、シェイプのアウトラインに沿ってCWを移動するクリーチャーは常に右側にシェイプの内側を持ち、CCWを移動するクリーチャーはシェイプの内側に移動しますその左。
多角形がどの方向に定義されているか、頂点がどのようにそれを囲むかを知る必要があります。
これがわからない場合は、ポリゴンの面積を計算することで解決できます。
float Polygon::area() {
float result = 0.0f;
for(int a = 0; a < vertexCount; a ++) {
int b = (a+1) % vertexCount;
result += vertices[a].x * vertices[b].y;
result -= vertices[a].y * vertices[b].x;
}
return result * .5f;
}
看板結果(正または負)は、時計回りか反時計回りかを示します。座標系に依存しているため、これを試して、どの方向に回っているかを確認する必要があります。
形状が時計回りの場合:
形状が反時計回りの場合:
トレバーはすでにこの質問をカバーしているようですが、ここに私の解決策があります:
形状がカバーする面積、つまり
area = 0
foreach (edge in shape)
area += edge.begin.x * edge.end.y - edge.begin.y * edge.end.x
上記のように計算された面積を使用すると、形状自体が時計回りかどうかを簡単に判断できます。面積がゼロ未満の場合にのみ時計回りになります。
オブジェクトが頂点の順序と同じように、または反対方向に移動しているかどうかを確認します。