web-dev-qa-db-ja.com

三角形を形成する3つの点の中にいくつの整数点がありますか?

実際、これは古典的な問題です。SO user Victor put it(in another SO question 面接中に尋ねるタスク)。

1時間(ため息)でそれを行うことができなかったので、三角形内の整数点の数を計算するアルゴリズムは何ですか?

[〜#〜] edit [〜#〜]:頂点が整数座標にあると仮定します。 (そうしないと、三角形内のすべての点を見つけてから、すべての浮動小数点を減算して整数点だけを残すという問題になります。あまりエレガントではありません)。

29
tzup

頂点が整数座標にあると仮定すると、Kyle Schultzの ピックの定理の調査 で説明されているように、三角形の周りに長方形を作成することで答えを得ることができます。

A j x krectangleの場合、内部点の数は

I = (j – 1)(k – 1).

以下の5x 3の長方形の場合、8つの内部ポイントがあります。

alt text
(出典: ga.ed

垂直脚(j)と水平脚(k)を持つ三角形の場合、内部点の数は次の式で与えられます。

I = ((j – 1)(k – 1) - h) / 2

ここで、hは、(長さではなく)三角形の斜辺と一致する長方形の内部の点の数です。

alt text
(出典: ga.ed

垂直方向または水平方向の三角形の場合、内部点の数(I)は次の式で与えられます。

alt text
(出典: ga.ed

ここで、j、k、h1、h2、およびbは次の図でマークされています

alt text
(出典: ga.ed

最後に、垂直または水平の辺がない三角形の場合は、2つのサブケースに分割できます。1つは三角形の周囲の領域が3つの三角形を形成し、もう1つは周囲の領域が3つの三角形と長方形を形成します(下の図を参照) 。

最初のサブケースの内部点の数(I)は、次の式で与えられます。

alt text
(出典: ga.ed

次の図では、すべての変数がマークされています。

alt text
(出典: ga.ed

2番目のサブケースの内部点の数(I)は、次の式で与えられます。

alt text
(出典: ga.ed

次の図では、すべての変数がマークされています。

alt text
(出典: ga.ed

36
Bill the Lizard

ピックの定理( http://en.wikipedia.org/wiki/Pick%27s_theorem )は、整数点に配置された単純なポリゴンの表面は次の式で与えられると述べています。

A = i + b/2 - 1

ここで、Aは三角形の表面、iは内部点の数、bは境界点の数です。境界点の数bは、各線の傾きの最大公約数を合計することで簡単に計算できます。

b =   gcd(abs(p0x - p1x), abs(p0y - p1y)) 
    + gcd(abs(p1x - p2x), abs(p1y - p2y)) 
    + gcd(abs(p2x - p0x), abs(p2y - p0y))

表面も計算できます。表面を計算する式については、 https://stackoverflow.com/a/14382692/2491535 を参照してください。これらの既知の値を組み合わせると、次のように計算できます。

i = A + 1 - b/2
13
Cst

私のひざまずく反応は、ブルートフォース攻撃です。

  • X方向とy方向の三角形の最大範囲と最小範囲を見つけます。
  • それらの範囲内の整数点のすべての組み合わせをループします。
  • ポイントのセットごとに、標準テストの1つ( 同じ側または重心手法 など)を使用して、ポイントが三角形内にあるかどうかを確認します。この種の計算は、光線/線分と三角形の交点を検出するためのアルゴリズムのコンポーネントであるため、詳細については このリンク を確認することもできます。
11
gnovice

わかりました。1つのアルゴリズムを提案します。それは素晴らしいものではありませんが、機能します。

まず、三角形のテストでポイントが必要になります。この優れた投稿で説明されているように、「重心テクニック」を使用することを提案します。

http://www.blackpawn.com/texts/pointinpoly/default.html

次にアルゴリズムについて説明します。

  1. (x1、y1)(x2、y2)(x3、y3)を三角形の頂点とします

  2. ymin = floor(min(y1、y2、y3))ymax =シーリング(max(y1、y2、y3))xmin = floor(min(x1、x2、x3))ymax =シーリング(max(x1、x2 3))

  3. xminからxmaxおよびyminからymaxまで繰り返すと、三角形を含む長方形領域内のすべての整数点を列挙できます。

  4. 三角形のポイントテストを使用すると、列挙内の各ポイントをテストして、それが三角形上にあるかどうかを確認できます。

簡単です。30分以内にプログラムできると思います。

5
tekBlues

これは「三角形の点」テストと呼ばれます。

これが記事この問題に対するいくつかの解決策です: 三角形テストのポイント

alt text

点が三角形内にあるかどうかを確認する一般的な方法は、ベクトルを見つける点を三角形の3つの頂点のそれぞれに接続し、角度を合計するこれらのベクトルの間です。角度の合計が2 * pi(360度)の場合、ポイントは三角形の内側です。それ以外の場合はそうではありません。

5
Robert Cartaino

別の方法がありますが、必ずしも最良とは限りませんが、インタビュアーに感銘を与えることは間違いありません。

まず、X座標が最も低い点を「L」、X座標が最も高い点を「R」、残りの点を「M」(左、右、中央)と呼びます。

次に、ブレゼンハムのラインアルゴリズムの2つのインスタンスを設定します。 1つのインスタンスをパラメーター化してLからRに描画し、2番目のインスタンスをパラメーター化してLからMに描画します。X= X [L]からX [M]に対して同時にアルゴリズムを実行します。ただし、線を引いたり、ピクセルをオンにしたりする代わりに、線の間のピクセルを数えます。

X [L]からX [M]にステップした後、2番目のブレゼンハムのパラメーターを変更してMからRに描画し、X = X [M]からX [R]に対して同時にアルゴリズムを実行し続けます。

これは、7時間前にErwin Smoutによって提案されたソリューションと非常に似ていますが、直線の傾きの式の代わりにブレゼンハムを使用しています。

ピクセルの列を数えるには、Mが線LRの上にあるか下にあるかを判断する必要があると思います。もちろん、2つの点のX座標またはY座標が同じ場合は特殊なケースが発生します。しかし、これが発生するまでに、インタビュアーは適切に畏敬の念を抱き、次の質問に進むことができます。

1
A. I. Breveleri

非ブルートフォース方式の答えは半分しかありません。頂点が整数の場合、エッジが交差する整数点の数を見つける方法を理解するためにそれを減らすことができます。その数と三角形の面積(ヘロンの公式)を使用して、ピックの定理を使用して内部整数点の数を見つけることができます。

編集:残りの半分については、エッジと交差する整数点を見つけて、それが点間のxとyの差から1を引いたもの、または距離から1を引いたもの(xまたはyの差の1つである場合)の最大公約数であると思われますはゼロです。

1
David

この問題の解決策を明確に説明する非常に便利なリンクを見つけました。私は座標幾何学が苦手なので、このソリューションを使用してJavaでコーディングしました(少なくとも私が試したテストケースでは)。

http://mathforum.org/library/drmath/view/55169.html

public int points(int[][] vertices){
      int interiorPoints = 0;
      double triangleArea = 0;
      int x1 = vertices[0][0], x2 = vertices[1][0], x3 = vertices[2][0];
      int y1 = vertices[0][1], y2 = vertices[1][1], y3 = vertices[2][1];

      triangleArea = Math.abs(((x1-x2)*(y1+y2))                             
                + ((x2-x3)*(y2+y3))
                + ((x3-x1)*(y3+y1)));

      triangleArea /=2;
      triangleArea++;

      interiorPoints = Math.abs(gcd(x1-x2,y1-y2))
                + Math.abs(gcd(x2-x3, y2-y3))
                + Math.abs(gcd(x3-x1, y3-y1));

      interiorPoints /=2;

      return  (int)(triangleArea - interiorPoints);
 }
0
user6241384

これがPython @ Prabhalaのソリューション の実装です:

from collections import namedtuple
from fractions import gcd


def get_points(vertices):
    Point = namedtuple('Point', 'x,y')
    vertices = [Point(x, y) for x, y in vertices]

    a, b, c = vertices

    triangle_area = abs((a.x - b.x) * (a.y + b.y) + (b.x - c.x) * (b.y + c.y) + (c.x - a.x) * (c.y + a.y))
    triangle_area /= 2
    triangle_area += 1

    interior = abs(gcd(a.x - b.x, a.y - b.y)) + abs(gcd(b.x - c.x, b.y - c.y)) + abs(gcd(c.x - a.x, c.y - a.y))
    interior /= 2

    return triangle_area - interior

使用法:

print(get_points([(-1, -1), (1, 0), (0, 1)]))  # 1
print(get_points([[2, 3], [6, 9], [10, 160]]))  # 289
0
alecxe

クイックn 'ダーティ擬似コード:

-- Declare triangle
p1 2DPoint = (x1, y1);
p2 2DPoint = (x2, y2);
p3 2DPoint = (x3, y3);
triangle [2DPoint] := [p1, p2, p3];

-- Bounding box
xmin float = min(triangle[][0]);
xmax float = max(triangle[][0]);
ymin float = min(triangle[][1]);
ymax float = max(triangle[][1]);

result [[float]];

-- Points in bounding box might be inside the triangle
for x in xmin .. xmax {
  for y in ymin .. ymax {
    if a line starting in (x, y) and going in any direction crosses one, and only one, of the lines between the points in the triangle, or hits exactly one of the corners of the triangle {
      result[result.count] = (x, y);
    }
  }
}
0
l0b0

私はこの考えを持っています-

A(x1、y1)、B(x2、y2)、C(x3、y3)を三角形の頂点とします。 'count'を三角形を形成する整数点の数とします。

三角形のエッジに点が必要な場合は、ユークリッド距離の式 http://en.wikipedia.org/wiki/Euclidean_distance を使用して、3辺すべての長さを確認できます。 3辺すべての長さの合計-3は、そのカウントになります。

三角形内のポイントの数を見つけるには、三角形塗りつぶしアルゴリズムを使用する必要があります。実際のレンダリング、つまりdrawpixel(x、y)の実行の代わりに、ループを通過して、ループしながらカウントを更新し続けます。からの三角形塗りつぶしアルゴリズム

ピーター・シャーリー、マイケル・アシクミンによるコンピューターグラフィックスの基礎

役立つはずです。ここで参照 http://www.gidforums.com/t-20838.html

乾杯

0
Arnkrishn

私はこのように行きます:

三角形の最上点(Y座標が最も高い点)を取ります。その時点から始まる2つの「勾配」があります。これは一般的な解決策ではありませんが、視覚化を容易にするために、「左に行く」(x座標を減らす)と「右に行く」の両方を考えてください。

これらの2つの勾配と、最高点よりも小さい任意のY座標から、勾配によって設定された境界内に表示される整数点の数を計算できるはずです。減少するY座標を繰り返し、それらすべてのポイント数を合計します。

減少するY座標が、三角形の2番目に高い点に達したら停止します。

これで、「2番目に高いポイントより上」のすべてのポイントがカウントされ、「いくつかの(はるかに小さい!!!)三角形内のすべてのポイントをカウントする」という問題が残ります。三角形の上側は、 X軸。

同じ手順を繰り返しますが、「最上部」ではなく「左端」を取り、「yを減らす」のではなく「xを増やす」ことを続行します。

その後、もう一度はるかに小さい三角形内のすべての整数点を数えるという問題が残ります。三角形の上側はX軸に平行で、左側はY軸に平行であることがわかります。

残っている三角形のポイントがなくなるまで、繰り返し(繰り返し)続けます。

(私は今あなたのためにあなたの宿題を作りましたか?)

0
Erwin Smout