ポイントが三角形の内側にあるかどうかを確認します


40

あなたの目標は、与えられた2DポイントXが与えられた頂点A、B、Cを持つ三角形の領域内にあるかどうかを判断することです。

テストポイントXと3つの三角形の頂点の座標(合計8座標)を取り、ポイントがその三角形の内側にある場合はTrueを返し、外側にある場合はFalseを返す関数を記述します。

エッジケースを心配しないでください。ポイントが三角形(エッジまたは頂点)の境界上にある場合、または三角形が実際に線分である場合、コードはクラッシュを含む何でもできます。また、数値の安定性や浮動小数点の精度について心配する必要はありません。

コードは名前付き関数でなければなりません。コードスニペットは受け入れられません。

最も少ないキャラクターが勝ちます。

入力:

座標を表す8つの実数。数値は範囲内にあります(-1,1)

正確な入力形式は柔軟です。たとえば、8つの数字、8つの数字のリスト、それぞれタプルで与えられる4つのポイントのリスト、2 * 4マトリックス、4つの複素数、x座標とy座標の2つのリスト、等々。

入力は、追加データなしで、何らかのコンテナ内の数値である必要があります。入力を使用して前処理を行うことはできません。また、ポイントを昇順のy座標で指定する必要があるなど、入力に制約を必要とすることもできません。入力では、任意の8つの座標を許可する必要があります(ただし、前述のエッジケースではコードは任意に動作できます)。

入力形式を明記してください。

出力:

対応するブール値True/ False、対応する数値1/ 0、または使用言語の類似物。

テストケース

入力には[X,A,B,C]、最初にテストポイント、次に3つの三角形の頂点の4つのタプルのリストが与えられます。私は、その出力である必要があり、それらにそれらをグループ化してきましたTrueし、あるべきものFalse

True インスタンス:

[(-0.31961, -0.12646), (0.38478, 0.37419), (-0.30613, -0.59754), (-0.85548, 0.6633)]
[(-0.87427, -0.00831), (0.78829, 0.60409), (-0.90904, -0.13856), (-0.80685, 0.48468)]
[(0.28997, -0.03668), (-0.28362, 0.42831), (0.39332, -0.07474), (-0.48694, -0.10497)]
[(-0.07783, 0.04415), (-0.34355, -0.07161), (0.59105, -0.93145), (0.29402, 0.90334)]
[(0.36107, 0.05389), (0.27103, 0.47754), (-0.00341, -0.79472), (0.82549, -0.29028)]
[(-0.01655, -0.20437), (-0.36194, -0.90281), (-0.26515, -0.4172), (0.36181, 0.51683)]
[(-0.12198, -0.45897), (-0.35128, -0.85405), (0.84566, 0.99364), (0.13767, 0.78618)]
[(-0.03847, -0.81531), (-0.18704, -0.33282), (-0.95717, -0.6337), (0.10976, -0.88374)]
[(0.07904, -0.06245), (0.95181, -0.84223), (-0.75583, -0.34406), (0.16785, 0.87519)]
[(-0.33485, 0.53875), (-0.25173, 0.51317), (-0.62441, -0.90698), (-0.47925, 0.74832)]

False インスタンス:

[(-0.99103, 0.43842), (0.78128, -0.10985), (-0.84714, -0.20558), (-0.08925, -0.78608)]
[(0.15087, -0.56212), (-0.87374, -0.3787), (0.86403, 0.60374), (0.01392, 0.84362)]
[(0.1114, 0.66496), (-0.92633, 0.27408), (0.92439, 0.43692), (0.8298, -0.29647)]
[(0.87786, -0.8594), (-0.42283, -0.97999), (0.58659, -0.327), (-0.22656, 0.80896)]
[(0.43525, -0.8923), (0.86119, 0.78278), (-0.01348, 0.98093), (-0.56244, -0.75129)]
[(-0.73365, 0.28332), (0.63263, 0.17177), (-0.38398, -0.43497), (-0.31123, 0.73168)]
[(-0.57694, -0.87713), (-0.93622, 0.89397), (0.93117, 0.40775), (0.2323, -0.30718)]
[(0.91059, 0.75966), (0.60118, 0.73186), (0.32178, 0.88296), (-0.90087, -0.26367)]
[(0.3463, -0.89397), (0.99108, 0.13557), (0.50122, -0.8724), (0.43385, 0.00167)]
[(0.88121, 0.36469), (-0.29829, 0.21429), (0.31395, 0.2734), (0.43267, -0.78192)]

キャラクターの定義は何ですか?アスキー?7ビットでエンコード可能?バイトで?ユニコード
isaacg 14

何を指示してるんですか?圧縮コードを使用するソリューションはすでにあります。
xnor 14

通常、Ascii以外の文字にはバイトが使用されると考えています。そうでない場合、Utf-32の利点は克服できないからです。
isaacg

さて、今は戻れません。Unicode文字は文字です。必要に応じて圧縮します。
XNOR

回答:


19

Javascript / ECMAScript 6、161 159 158/152

Javascript:

function $(t,r,i,a,n,g,l,e){b=(-g*l+a*(-n+l)+i*(g-e)+n*e)/2;c=b<0?-1:1;d=(a*l-i*e+(e-a)*t+(i-l)*r)*c;f=(i*g-a*n+(a-g)*t+(n-i)*r)*c;return d>0&&f>0&&d+f<2*b*c}

ECMAScript 6バージョン(m.buettnerに感謝、6文字を保存)

$=(t,r,i,a,n,g,l,e)=>{b=(-g*l+a*(-n+l)+i*(g-e)+n*e)/2;c=b<0?-1:1;d=(a*l-i*e+(e-a)*t+(i-l)*r)*c;f=(i*g-a*n+(a-g)*t+(n-i)*r)*c;return d>0&&f>0&&d+f<2*b*c}

そのように呼び出します(戻り値trueまたはfalse):

$(pointX, pointY, v1X, v1Y, v2X, v2Y, v3X, v3Y);

この回答からのコードに基づいて、いくつかの派手な重心座標の数学を使用します。読書を楽しむための無料版は次のとおりです。

function $ (pointX, pointY, v1X, v1Y, v2X, v2Y, v3X, v3Y) {
  var A =  (-v2Y * v3X + v1Y * (-v2X + v3X) + v1X * (v2Y - v3Y) + v2X * v3Y) / 2;
  var sign = A < 0 ? -1 : 1;
  var s = (v1Y * v3X - v1X * v3Y + (v3Y - v1Y) * pointX + (v1X - v3X) * pointY) * sign;
  var t = (v1X * v2Y - v1Y * v2X + (v1Y - v2Y) * pointX + (v2X - v1X) * pointY) * sign;
  return s > 0 && t > 0 && s + t < 2 * A * sign;
}

12
+1、パラメーター名のみの場合!
マット14

なぜ文字カウントのUserScriptを壊す必要があるのですか?
kitcar2000 14

@ kitcar2000どういう意味ですか?
アブラハム14

ルールでは、バイトではなく文字がカウントされると規定されています。:あなたはこの使用できるようにxem.github.io/obfuscatweetを 122個の文字に収まるように
XEM

1
私は間違っていますか、(a*(l-n)+i*(g-e)+n*e-g*l)代わりに使用できました(-g*l+a*(-n+l)+i*(g-e)+n*e)か?
ザカリー

19

Pythonの2.7 128 127 117 110 109 103 99 95 94 91 90

私の最初のコードゴルフの試み!

コード

f=lambda x,y,t:sum(a*y+c*b+d*x<d*a+c*y+b*x for i in(0,1,2)for a,b,c,d in[t[i-1]+t[i]])%3<1

入力として(x、y、t)を取ります。ここで、(x、y)はチェックするポイント、tは三角形t =((x1、y1)、(x2、y2)、(x3、y3))です。

説明

私は行列の行列式を計算しています

| 1 x1 y1 |      | 1 x2 y2 |      | 1 x3 y3 |
| 1 x2 y2 | ,    | 1 x3 y3 | ,    | 1 x1 y1 | .
| 1 x  y  |      | 1 x  y  |      | 1 x  y  |

これらの行列式は、三角形の辺からポイント(x、y)までの符号付き距離を表します。それらがすべて同じ符号を持っている場合、ポイントはすべての線の同じ側にあり、三角形に含まれています。

上記のコードでa*y+c*b+d*x-d*a-c*y-b*xは、はこれらの行列のいずれかの決定要因です。

私は事実使用していますTrue+True+True==3し、False+False+False==0これらの決定はすべて同じ符号を持っているかどうかを判断するために。

t[-1]代わりにを使用して、Pythonのネガティブリストインデックスを使用しますt[(i+1)%3]

sが0または3であるかどうかを確認するs%3<1代わりに使用するアイデアをありがとう、Peterに感謝しますs in(0,3)

Sagemathバージョン

実際には別の解決策ではないので、この回答に80文字を使用したsagemathソリューションを含めます。

f=lambda p,t,o=[1]:sum([det(Matrix([o+t[i-1],o+t[i],o+p]))<0for i in 0,1,2])%3<1

ここp=[x,y]で、t=[[x1,y1],[x2,y2],[x3,y3]]


1
s in (0,3)短縮できますs%3<1か?
ピーターテイラー14

1
負のインデックスを使用すると、より多くのものを保存するために微調整することができます-1,0,1 ... t[i]+t[i+1]と同等です0,1,2 ... t[i-1]+t[i]
ピーター・テイラー

@PeterTaylor絶対に正しい!残念ながら、in -1,0,1これを読む前にスペースを削除しました。実際、あなたの方法はより読みやすいので、とにかくそれを使用します。
アレックスL 14

1
コードゴルフへようこそ!括弧でsum囲む場合は、リスト内包表記の角括弧を取り除くことができます0,1,2。この場合は、スペースを置き換えることで文字を表します。その理由は、Pythonが括弧なしの理解を関数に渡すことを許可しているが、裸のタプル内のコンマは、1,2,3それらを別個の引数として解析しようとするため、混乱させるためです。
xnor

16

Mathematica、67バイト

f=Equal@@({#2,-#}&@@(#-#2).(x-#)>0&@@@Partition[x=#;#2,2,1,{1,1}])&

この関数は、2つの引数、ポイント Xとのリストのます。{A,B,C}これらはそれぞれ#およびと呼ばれ#2ます。それはあなたが電話すれば

f[X,{A,B,C}]

その後、あなたは得るでしょう #Xし、#2として{A,B,C}。(コード内にネストされた他の2つの匿名関数があり、それらの中で異なる意味##2持っていることに注意してください。)

関数自体の説明は次のとおりです。

                                              x=#;#2            & (* Save X into a variable x, but evaluate to {A,B,C}. *)
                                    Partition[x=#;#2,2,1,{1,1}] & (* Get a cyclic list of pairs {{A,B},{B,C},{C,B}}. *)
       (                        &@@@Partition[x=#;#2,2,1,{1,1}])& (* Define an anonymous function and apply it to each 
                                                                     of the above pairs. The two elements are referred 
                                                                     to as # and #2. *)
       (          (#-#2)        &@@@Partition[x=#;#2,2,1,{1,1}])& (* Subtract the two points. For a pair of vertices 
                                                                     this yields a vector corresponding to the edge 
                                                                     between them. *)
        {#2,-#}&                                                  (* An anonymous function that takes two values, 
                                                                     reverses them, inverts the sign of one of them 
                                                                     and puts them into a list. *)
       ({#2,-#}&@@(#-#2)        &@@@Partition[x=#;#2,2,1,{1,1}])& (* Applied to the edge, this yields its normal. *)
       ({#2,-#}&@@(#-#2).(x-#)  &@@@Partition[x=#;#2,2,1,{1,1}])& (* Take the scalar product of that normal with a
                                                                     vector from a vertex to x. This is projection of 
                                                                     this vector onto that normal and hence the SIGNED
                                                                     distance of x from the edge. *)
       ({#2,-#}&@@(#-#2).(x-#)>0&@@@Partition[x=#;#2,2,1,{1,1}])& (* Check the sign of that distance, the exact mapping 
                                                                     between (left, right) and (True, False) is 
                                                                     irrelevant, as long as it's consistent. *)
Equal@@({#2,-#}&@@(#-#2).(x-#)>0&@@@Partition[x=#;#2,2,1,{1,1}])& (* Check if all signs are equal - that is, if point X 
                                                                     lies on the same side of all edges. This is 
                                                                     equivalent to check that the point is inside the 
                                                                     triangle. *)

この関数は実際に、頂点が時計回りまたは反時計回りのいずれかの順序で与えられている限り凸nゴン。


すべての符号が等しい場合よりも、距離の積が正であるかどうかを確認する方が効率的ではないでしょうか?私はMathematicaを使いませんが、それは簡単なはずです。
isaacg 14

@isaacg 3つの用語があるため、それらがすべて否定的である場合、製品は否定的であり、すべて肯定的である場合、製品は肯定的です。2つの数値の符号が等しくなる場合にのみ、アプローチは機能します。
マーティンエンダー14

なぜ使用しないのDetですか?
alephalpha

@alephalphaまあ、私はそれを考えていなかったからだろう。:P ...私はそれを調べます
マーティンエンダー14

@alephalphaうーん、私は今、より少ない文字で3つの必要なマトリックスを構築する方法を見つけることができません。
マーティンエンダー14

7

CJam、66 63 59 52 46 34 32 31 30 28文字

"Ă䒟损崙㩴ァ椟饃꿾藭鑭蘁"2G#b131b:c~

Unicode文字列を変換した後、次のコード(33バイト)が評価されます:

{2*2/\f{f{+~@-@@-}~@@*@@*>})-!}:T

期待する X [A B C]入力としてします。各ポイントはの形式[double double]です。出力は1または0です。

オンラインでお試しください。

に感謝します 6文字(13バイトの非圧縮コード)を保存くれたuser23013に

テストケース

$ cat triangle.cjam
"Ă䒟损崙㩴ァ椟饃꿾藭鑭蘁"2G#b131b:c~

[
  [-0.31961 -0.12646] [ [0.38478 0.37419]   [-0.30613 -0.59754] [-0.85548 0.6633]   ] T
  [-0.87427 -0.00831] [ [0.78829 0.60409]   [-0.90904 -0.13856] [-0.80685 0.48468]  ] T
  [0.28997 -0.03668]  [ [-0.28362 0.42831]  [0.39332 -0.07474]  [-0.48694 -0.10497] ] T
  [-0.07783 0.04415]  [ [-0.34355 -0.07161] [0.59105 -0.93145]  [0.29402 0.90334]   ] T
  [0.36107 0.05389]   [ [0.27103 0.47754]   [-0.00341 -0.79472] [0.82549 -0.29028]  ] T
  [-0.01655 -0.20437] [ [-0.36194 -0.90281] [-0.26515 -0.4172]  [0.36181 0.51683]   ] T
  [-0.12198 -0.45897] [ [-0.35128 -0.85405] [0.84566 0.99364]   [0.13767 0.78618]   ] T
  [-0.03847 -0.81531] [ [-0.18704 -0.33282] [-0.95717 -0.6337]  [0.10976 -0.88374]  ] T
  [0.07904 -0.06245]  [ [0.95181 -0.84223]  [-0.75583 -0.34406] [0.16785 0.87519]   ] T
  [-0.33485 0.53875]  [ [-0.25173 0.51317]  [-0.62441 -0.90698] [-0.47925 0.74832]  ] T
  [-0.99103 0.43842]  [ [0.78128 -0.10985]  [-0.84714 -0.20558] [-0.08925 -0.78608] ] T
  [0.15087 -0.56212]  [ [-0.87374 -0.3787]  [0.86403 0.60374]   [0.01392 0.84362]   ] T
  [0.1114 0.66496]    [ [-0.92633 0.27408]  [0.92439 0.43692]   [0.8298 -0.29647]   ] T
  [0.87786 -0.8594]   [ [-0.42283 -0.97999] [0.58659 -0.327]    [-0.22656 0.80896]  ] T
  [0.43525 -0.8923]   [ [0.86119 0.78278]   [-0.01348 0.98093]  [-0.56244 -0.75129] ] T
  [-0.73365 0.28332]  [ [0.63263 0.17177]   [-0.38398 -0.43497] [-0.31123 0.73168]  ] T
  [-0.57694 -0.87713] [ [-0.93622 0.89397]  [0.93117 0.40775]   [0.2323 -0.30718]   ] T
  [0.91059 0.75966]   [ [0.60118 0.73186]   [0.32178 0.88296]   [-0.90087 -0.26367] ] T
  [0.3463 -0.89397]   [ [0.99108 0.13557]   [0.50122 -0.8724]   [0.43385 0.00167]   ] T
  [0.88121 0.36469]   [ [-0.29829 0.21429]  [0.31395 0.2734]    [0.43267 -0.78192]  ] T
]p;

$ cjam triangle.cjam
[1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0]

それは名前付き関数ですか?
マーティンエンダー14

@ m.buettner:並べ替え。公式Wikiは、次の言葉:ブロック-プログラムセクションで区切られた{}し、単一のユニットとして扱わ。C / javaのコードブロックに似ていますが、ブロックはファーストクラスのオブジェクトであり、変数に割り当てることができます(つまり、関数を定義します)。
デニス14

1
@xnor 1m<@m*は、3組のXとi+1三角形の次の(th)頂点を準備します。@-@@-現在の(ith)頂点を原点に移動します(そうでない場合はミラーリングされますが@-\@-、重要ではありません)。@@*@@*>クロス積(行列式)のz軸を計算し、1負の場合に戻ります。:+3%!それらがすべて同じであるかどうか、つまり、3つすべてが負または非負であるかどうかを返します。つまり、エッジの場合を除いて正を意味します。ゴルフよりもCJamを読む方が難しいと思います。
jimmy23013 14

1
37バイト:{[_1m<\]z\f{f{+~@-@@-}~@@*@@*>})-!}:T2m>またはWm<Unicodeの安全性のために使用します。
jimmy23013 14

1
33バイト:{2*2/\f{f{+~@-@@-}~@@*@@*>})-!}:T
jimmy23013 14

5

C – 156バイト

入力は、Xに3つのフロート、Yに3つのフロートの配列で、テストポイントのxとyを分離します。ボーナス:すべてのエッジケースを処理します!

int f(float*X,float*Y,float x,float y){int i,j,c=0;for(i=0,j=2;i<3;j=i++)if(((Y[i]>y)!=(Y[j]>y))&&(x<(X[j]-X[i])*(y-Y[i])/(Y[j]-Y[i])+X[i]))c=!c;return c;}

PNPOLYから適応。


i;j;c;f(float*X,float*Y,float x,float y){for(c=i=0,j=2;i<3;)c^=(Y[i]>y)-(Y[j]>y)&(x<(X[j]-X[i])*(y-Y[i])/(Y[j]-Y[i])+X[j=i++]);return c;}137 - JavaScriptでテスト
ベベ

@bebe-構文エラーが発生します。
デレク朕會功夫14

それはしない構文エラーの原因となります。
ベベ14

4

Pyth 1.0.557 54 51

DgYb=Z0J'bWbK;bDiHNR*-'H'K-@N1@K1~Z>iYJiJY=JK)R!%Z3

関数gを定義します。関数gは、テストポイントと、三角形の頂点のリストの2つの入力を受け取ります。出力TrueおよびFalse。注:入力、具体的にはb、三角形の頂点のリストを破棄します。

ここで試してみてください。最後の数文字はgvwvw、次の2行でテストケースを指定して関数を呼び出します。

このアルゴリズムに基づいて

説明:

DgYb                  Define g(Y,b):
=Z0                     Z=0
J'b                     J=b[0]              (No = is needed because j is special).
Wb                      While len(b)>0:     (While b:)
K;b                       K=b.pop()
DiHN                      Define i(H,N):    
R*-'H'K-@N1@K1              Return half of the linked equation.
~ZiYJiJY                  Z+=i(Y,J)>i(J,Y)
=JK                       J=K
)                       Wend
R!%Z3                   return not Z%3==0   (True iff Z == 0 or 3)

CJam-ピス戦争が激化!


これは名前付き関数でなければなりません。されたwSTDIN入力を取りますか?
xnor 14

@xnorおっと、説明の一部を見逃しました。編集します。
isaacg

@xnor答えを出力する関数は許可されますか、それとも答えを返す必要がありますか?現在、これは答えを出力しますが、もう1文字を返してもらうことができます。
isaacg 14

答えを返します。
xnor 14

あなたは、おそらくカウンターを置き換えることにより、文字を保存することができZ、あなたがして蓄積すること空のセットでZ|=のみかどうかを確認するためにその長さをテストし、0のかが1見られましたか?この戦略はPythonでより長く判明しましたが、おそらくPythプリミティブを使用する価値があります。
xnor 14

4

J 64 45(割り当てなしの42)

c=:*./@(>:&0)@({.(,(1-+/))@%.|:@}.)@(}:-"1{:)

代入は事物が関数であるために必要ではないので、それを数えるべきかどうか確信が持てません。柔軟な入力を活用する:(1 +頂点の数)x(空間の次元)の配列が必要です。

ここでいくつかの余分なポイントを獲得したいと考えています...:このことは、平面の三角形だけでなく、3D空間の3角錐など、シンプレックスのあらゆる次元で機能します。また、シンプレックスの頂点の数が(n + 1)より小さい場合にも機能し、シンプレックスへの点の投影が内側かどうかを計算します。

重心座標に変換し、負の座標をチェックして、ポイントが外側にあることを示します。Jは_を負に使用します

NB. example in triangle
D =: 4 2 $ 1 1 0 0 3 0 0 2 NB. 4 rows , x first, then the vertices of the triangle

NB. subtract last vertex coordinates from the rest and drop reference node
n=: (}:-"1{:)

NB. preprocessed to barycentric coordinates
bar=: {. (, 1 - +/)@%. |:@}.

NB. all positive
ap =: *./@(>:&0)

insided =: ap@bar@n

inside D
1

与えられた例の実行:

   true =: 0 : 0
[(-0.31961, -0.12646), (0.38478, 0.37419), (-0.30613, -0.59754), (-0.85548, 0.6633)]
[(-0.87427, -0.00831), (0.78829, 0.60409), (-0.90904, -0.13856), (-0.80685, 0.48468)]
[(0.28997, -0.03668), (-0.28362, 0.42831), (0.39332, -0.07474), (-0.48694, -0.10497)]
[(-0.07783, 0.04415), (-0.34355, -0.07161), (0.59105, -0.93145), (0.29402, 0.90334)]
[(0.36107, 0.05389), (0.27103, 0.47754), (-0.00341, -0.79472), (0.82549, -0.29028)]
[(-0.01655, -0.20437), (-0.36194, -0.90281), (-0.26515, -0.4172), (0.36181, 0.51683)]
[(-0.12198, -0.45897), (-0.35128, -0.85405), (0.84566, 0.99364), (0.13767, 0.78618)]
[(-0.03847, -0.81531), (-0.18704, -0.33282), (-0.95717, -0.6337), (0.10976, -0.88374)]
[(0.07904, -0.06245), (0.95181, -0.84223), (-0.75583, -0.34406), (0.16785, 0.87519)]
[(-0.33485, 0.53875), (-0.25173, 0.51317), (-0.62441, -0.90698), (-0.47925, 0.74832)]
)

   false =: 0 : 0
[(-0.99103, 0.43842), (0.78128, -0.10985), (-0.84714, -0.20558), (-0.08925, -0.78608)]
[(0.15087, -0.56212), (-0.87374, -0.3787), (0.86403, 0.60374), (0.01392, 0.84362)]
[(0.1114, 0.66496), (-0.92633, 0.27408), (0.92439, 0.43692), (0.8298, -0.29647)]
[(0.87786, -0.8594), (-0.42283, -0.97999), (0.58659, -0.327), (-0.22656, 0.80896)]
[(0.43525, -0.8923), (0.86119, 0.78278), (-0.01348, 0.98093), (-0.56244, -0.75129)]
[(-0.73365, 0.28332), (0.63263, 0.17177), (-0.38398, -0.43497), (-0.31123, 0.73168)]
[(-0.57694, -0.87713), (-0.93622, 0.89397), (0.93117, 0.40775), (0.2323, -0.30718)]
[(0.91059, 0.75966), (0.60118, 0.73186), (0.32178, 0.88296), (-0.90087, -0.26367)]
[(0.3463, -0.89397), (0.99108, 0.13557), (0.50122, -0.8724), (0.43385, 0.00167)]
[(0.88121, 0.36469), (-0.29829, 0.21429), (0.31395, 0.2734), (0.43267, -0.78192)]
)
   NB. replace - by _ to avoid problems
   NB. cut up per row, drop the [ ] and convert to numbers
   $dat_t =: ((4 2 $ ".)@}:@}.;._2) (true='-')} true ,: '_'
10 4 2
   $dat_f =: ((4 2 $ ".)@}:@}.;._2) (false='-')}false,: '_'
10 4 2
   NB. this results in arrays with shape 10 4 2

   NB. for each 4 x 2 array (rank 2), do c for all true instances
   c=:*./@(>:&0)@({.(,(1-+/))@%.|:@}.)@(}:-"1{:)
   c"2 dat_t
1 1 1 1 1 1 1 1 1 1
   NB. the same for the false ones, demonstrating anonymous usage
   NB. still a function though (or verb in J parlance)
   *./@(>:&0)@({.(,(1-+/))@%.|:@}.)@(}:-"1{:)"2 dat_f
0 0 0 0 0 0 0 0 0 0

名前付き関数を要求したので、割り当て文字がカウントされます。ポリゴンに一般化するためのいくつかのポイントがあります!·····
xnor 14

まあ、実際には、ポリゴンに一般化するのではなく、N+1頂点が最大のN次元シンプレックスに一般化します。たとえば、3次元空間の4頂点ピラミッド、または4次元空間の5頂点シンプレックス。頂点の数はより小さいN+1場合があります。この場合、アルゴリズムは、シンプレックスが存在する超平面への正射影がシンプレックス内にあるかどうかを調べます(たとえば、2次元の2ポイントシンプレックスがラインに投影され、チェックされます)この投影がエンドポイント間にあるかどうか)
jpjacobs 14

4

HTML5 + JS、13b + 146b / 141b / 114文字

HTML:

<canvas id=C>

JS(146b):

// @params: t1x, t1y, t2x, t2y, t3x, t3y, pointx, pointy
function T(a,b,c,d,e,f,g,h){with(C.getContext("2d"))return beginPath(),moveTo(a,b),lineTo(c,d),lineTo(e,f),fill(),!!getImageData(g,h,1,1).data[3]}

またはES6(141b):

T=(a,b,c,d,e,f,g,h)=>{with(C.getContext("2d"))return beginPath(),moveTo(a,b),lineTo(c,d),lineTo(e,f),fill(),!!getImageData(g,h,1,1).data[3]}

またはES6 unicode-obfuscated(114文字):

eval(unescape(escape('𥀽𚁡𛁢𛁣𛁤𛁥𛁦𛁧𛁨𚐽🡻𭱩𭁨𚁃𛡧𩑴𠱯𫡴𩑸𭀨𘠲𩀢𚐩𬡥𭁵𬡮𘁢𩑧𪑮𤁡𭁨𚀩𛁭𫱶𩑔𫰨𨐬𨠩𛁬𪑮𩑔𫰨𨰬𩀩𛁬𪑮𩑔𫰨𩐬𩠩𛁦𪑬𫀨𚐬𘐡𩱥𭁉𫑡𩱥𡁡𭁡𚁧𛁨𛀱𛀱𚐮𩁡𭁡𦰳𧑽').replace(/uD./g,'')))

デモ:http : //jsfiddle.net/xH8mV/

Unicode難読化:http : //xem.github.io/obfuscatweet/


ポイントが側に近い場合、正しい結果が得られないようです:jsfiddle.net/L2B2Aこれは、すべての入力が(-1,1)の間であり、コードが周りの4ピクセルのみをテストしているためだと思います起源。
デレク朕會功夫14

そうです、例に合わせて、キャンバスの原点とスケールを変更して、[-1,1]内の三角形を処理する必要があります。しかし、なぜこれらの三角形はとても小さいのですか?
xem 14

問題は、すべてのxyが-1から1の間であると言います。本当に理由はわかりませんが、すべての入力に1e7を掛けると(精度を維持するため)正しい結果が得られると思います:D
Derek朕會功夫

グラフィカルなソリューション、非常に賢い!
xnor 14

3

パイソン(65)

人々は投稿を終えたようですので、質問に対する独自の解決策を投稿します。

f=lambda X,L:sum(((L[i-1]-X)/(L[i]-X)).imag>0for i in(0,1,2))%3<1

Xはテストポイントを表す複素数でありL、それぞれが複素数である3つのポイントのリストです。

最初に、あまりゴルフされていないバージョンのコードについて説明します。

def f(X,A,B,C):A-=X;B-=X;C-=X;return((A/B).imag>0)==((B/C).imag>0)==((C/A).imag>0)

Pythonの組み込みの複雑な算術演算を利用して、原点にあるA,B,C,XようにポイントをシフトしXます。原点がの凸包に含まれているかどうかを確認する必要がありA,B,Cます。これは、線分AB、BC、およびACの同じ側(左または右)に常にある原点に相当します。

セグメント ABの原点は、AからBに到達するために180度未満で反時計回りに移動した場合は左側に、それ以外の場合は右側にあります。我々は、角度を考慮した場合ab及びc、これらの点に対応し、この手段は、b-a < 180 degrees(360度の範囲0に角度をとっ)。複素数としてangle(B/A)=angle(B)/angle(A)。また、angle(x) < 180 degrees上半平面のポイントについても、を介してチェックしimag(x)>0ます。

したがって、原点がABの左側にあるかどうかはとして表され(A/B).imag>0ます。これらがすべての巡回ペアですべて等しいかどうかを確認すると、A,B,C三角形ABCに原点が含まれているかどうかがわかります。

それでは、完全にゴルフされたコードに戻りましょう

f=lambda X,L:sum(((L[i-1]-X)/(L[i]-X)).imag>0for i in(0,1,2))%3<1

(A-X,B-X,C-X)=(L[0]-X,L[1]-X,L[2]-X)L[-1]= L[2])を囲む負のPythonリストインデックスを利用して、の各循環ペアを生成します。BoolsがすべてTrue1)またはすべてであることを確認するにはFalse0)であることを確認するには、それらを追加し、多くのソリューションが行ったように、3性を確認します。


2

Fortran- 232 218 195 174

血まみれのひどい。この関数は、データが渡され、前処理できないという要件のために恐ろしいです。

logical function L(x);real::x(8);p=x(1)-x(3);q=x(2)-x(4);r=x(5)-x(3);s=x(6)-x(4);t=x(7)-x(3);u=x(8)-x(4);L=ALL([p*(s-u)+q*(t-r)+r*u-t*s,p*u-q*t,q*r-p*s]>=r*u-t*s);endfunction

14文字の減少は、テスト実行から関数名をゴルフするのを忘れたためです。さらに減少するのは、暗黙的な入力と関数名の変更の忘れによるものです。ポイントを単一の配列として読み取るため、次の20文字が外れました。完全なプログラムは

program inTriagle
   real, dimension(2) :: a,b,c,x
   do 
      print*,"Enter coordinates as x,a,b,c"
      read*,x,a,b,c
      if(all(x==0.0).and.all(a==0.0).and.all(b==0.0).and.all(c==0.0)) exit
      print*,"Is point in triangle: ",T(x,a,b,c)
   enddo
 contains!                       
   logical function L(x)
     real::x(8)
     p=x(1)-x(3);q=x(2)-x(4);r=x(5)-x(3)
     s=x(6)-x(4);t=x(7)-x(3);u=x(8)-x(4)
     L=ALL([p*(s-u)+q*(t-r)+r*u-t*s,p*u-q*t,q*r-p*s]>=r*u-t*s)
   endfunction
end program inTriagle

1
Fortranの暗黙的な型付けに依存し、8つの数字すべてを含む単一の入力配列を使用することで、これを少し短くすることができlogical function T(x);real x(8);p=x(1)-x(3);q=x(2)-x(4);r=x(5)-x(3);s=x(6)-x(4);u=x(7)-x(3);v=x(8)-x(4);o=r*v-u*s;T=ALL([p*(s-v)+q*(u-r)+o,p*v-q*u,q*r-p*s]>=o);endます。
Ventero

1
より一般的な部分式を削除することでさらに短くなりlogical function T(x);real x(8);p=x(1)-x(3);q=x(2)-x(4);r=x(5)-x(3);s=x(6)-x(4);u=x(7)-x(3);v=x(8)-x(4);a=r*v-u*s;b=p*v-q*u;d=q*r-p*s;T=ALL([a-b-d,b,d]>=a);endます。変換で間違いを犯さなかったと思います。元のコードがすべてのテストケースに合格するとは限りません。
ヴェンテロ14

@Ventero:私は暗黙の型を乱用するのを忘れて信じることができません:(あなたの助けをありがとう。!
カイルKanos

@Ventero:また、私の答えは三角形の向きに依存しているようです。TrueOP の最初の例は、元の方向を指定しながら、値と値Falseを交換Bした場合に表示されCますTrue
カイルカノス14

ああ、確かに、問題は(前のコメントの表記を再利用する)ときに発生しa < 0ます。これは、テストする必要がある条件を効果的に反転させます。残念ながら、すべてをでラップすることでこれを修正することはできません。そのためabs、暗黙の条件bd同じ符号を持つことaは失われます。これは次のようなものを使用することで修正できます(再び、前回のコメントの表記法と事前定義された変数を再利用します)e=a-b-d;T=ALL([a*a-b*b,a*a-d*d,a*a-e*e,a*b,a*d,a*e]>=0)
Ventero

2

MATLAB:9!

ここに書くのは大したことじゃない

inpolygon

次のように呼び出すことができます:

inpolygon(2/3, 2/3, [0 1 1], [0 0 1])

出力は次の名前の変数に割り当てられます ans


私が実際に関数を書かなければならなかった場合、それはそのようなものかもしれません、おそらく最適化できます:

function y=f(a,b,c,d)
inpolygon(a,b,c,d)

2
関数ハンドルを使用して短くすることができます:f=@(a,b,c,d)inpolygon(a,b,c,d)
jpjacobs 14

2

C#218(149?)

using P=System.Drawing.PointF;
bool F(P[]p){for(int i=0;i<4;i++){p[i].X*=1e7f;p[i].Y*=1e7f;}P[]a=new P[3];Array.Copy(p,1,a,0,3);var g=new System.Drawing.Drawing2D.GraphicsPath();g.AddLines(a);return g.IsVisible(p[0]);}

おそらく、数学的な方法ほど文字効率は良くありませんが、ライブラリの楽しい使い方です。ちなみに、やはり遅いです。

また、「数値の安定性や浮動小数点の精度についても心配しないでください」を活用します。-残念ながら、内部的にsをGraphicsPath使用しているintため、-1 <f <1の範囲の値は3つの値しか持つことができません。floatの精度は7桁しかないため、1e7を掛けて整数に変換します。うーん、それは本当に精度を失っていないと思います。また、別の方法で悪用される可能性があります。おそらく、精度を無視して「間違った」答えを与えることを利用できたでしょう。

場合は、私は、ライブラリをインポートする文字コストを無視することができよ149(、非常に少なくとも、System.LinqおよびSystem.Drawing最もWinFormsのプロジェクトにかなり標準ですが、System.Drawing.Drawing2Dストレッチのビットかもしれません):

bool G(PointF[]p){for(int i=0;i<4;i++){p[i].X*=1e7f;p[i].Y*=1e7f;}var g=new GraphicsPath();g.AddLines(p.Skip(1).ToArray());return g.IsVisible(p[0]);}

テストプログラム(ええ、いです):

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using P=System.Drawing.PointF;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        Program prog = new Program();
        foreach (string test in
@"[(-0.31961, -0.12646), (0.38478, 0.37419), (-0.30613, -0.59754), (-0.85548, 0.6633)]
[(-0.87427, -0.00831), (0.78829, 0.60409), (-0.90904, -0.13856), (-0.80685, 0.48468)]
[(0.28997, -0.03668), (-0.28362, 0.42831), (0.39332, -0.07474), (-0.48694, -0.10497)]
[(-0.07783, 0.04415), (-0.34355, -0.07161), (0.59105, -0.93145), (0.29402, 0.90334)]
[(0.36107, 0.05389), (0.27103, 0.47754), (-0.00341, -0.79472), (0.82549, -0.29028)]
[(-0.01655, -0.20437), (-0.36194, -0.90281), (-0.26515, -0.4172), (0.36181, 0.51683)]
[(-0.12198, -0.45897), (-0.35128, -0.85405), (0.84566, 0.99364), (0.13767, 0.78618)]
[(-0.03847, -0.81531), (-0.18704, -0.33282), (-0.95717, -0.6337), (0.10976, -0.88374)]
[(0.07904, -0.06245), (0.95181, -0.84223), (-0.75583, -0.34406), (0.16785, 0.87519)]
[(-0.33485, 0.53875), (-0.25173, 0.51317), (-0.62441, -0.90698), (-0.47925, 0.74832)]
[(-0.99103, 0.43842), (0.78128, -0.10985), (-0.84714, -0.20558), (-0.08925, -0.78608)]
[(0.15087, -0.56212), (-0.87374, -0.3787), (0.86403, 0.60374), (0.01392, 0.84362)]
[(0.1114, 0.66496), (-0.92633, 0.27408), (0.92439, 0.43692), (0.8298, -0.29647)]
[(0.87786, -0.8594), (-0.42283, -0.97999), (0.58659, -0.327), (-0.22656, 0.80896)]
[(0.43525, -0.8923), (0.86119, 0.78278), (-0.01348, 0.98093), (-0.56244, -0.75129)]
[(-0.73365, 0.28332), (0.63263, 0.17177), (-0.38398, -0.43497), (-0.31123, 0.73168)]
[(-0.57694, -0.87713), (-0.93622, 0.89397), (0.93117, 0.40775), (0.2323, -0.30718)]
[(0.91059, 0.75966), (0.60118, 0.73186), (0.32178, 0.88296), (-0.90087, -0.26367)]
[(0.3463, -0.89397), (0.99108, 0.13557), (0.50122, -0.8724), (0.43385, 0.00167)]
[(0.88121, 0.36469), (-0.29829, 0.21429), (0.31395, 0.2734), (0.43267, -0.78192)]".Split('\n'))
        {
            string t = test.Replace("[(", "").Replace(")]", "");
            string[] points = t.Split(new string[] { "), (" }, StringSplitOptions.None);

            string[] p = points[0].Split(',');
            P[] xabc = new P[4];

            for (int i = 0; i < 4; i++)
            {
                p = points[i].Split(',');
                xabc[i] = new F(float.Parse(p[0]), float.Parse(p[1]));
            }

            Console.WriteLine(test + "=>" + prog.F(xabc));
        }

        Console.ReadKey();
    }

    bool G(PointF[]p)
    {
        for(int i=0;i<4;i++){p[i].X*=1e7f;p[i].Y*=1e7f;}
        var g=new GraphicsPath();
        g.AddLines(p.Skip(1).ToArray());
        return g.IsVisible(p[0]);
    }

    bool F(P[]p)
    {
        for(int i=0;i<4;i++){p[i].X*=1e7f;p[i].Y*=1e7f;}
        var g=new System.Drawing.Drawing2D.GraphicsPath();
        g.AddLines(p.Skip(1).ToArray());
        return g.IsVisible(p[0]);
    }
}

かわいい、描画エンジンに仕事をさせる。
XNOR

2

ハスケル— 233 127

ここで説明されているように、クロス積を使用します

h(a,b)(p,q)(r,s)(t,u)=z a b p q r s==z a b r s t u&&z a b r s t u==z a b t u p q where z j k l m n o =(o-m)*(j-l)+(l-n)*(k-m)>0

このStack Exchangeの回答で説明されている重心座標と式を使用して実装された以前のソリューション:

g(p,q)(r,s)(t,u)(v,w)=
 let (j,k)=(p+(-r),q+(-s))
     (l,m)=(t+(-r),u+(-s))
     (n,o)=(v+(-r),w+(-s))
     d=l*o-n*m
     a=(j*(m-o)+k*(n-l)+l*o-n*m)/d
     b=(j*o-k*n)/d
     c=(k*l-j*m)/d
 in (0<=a&&a<1)&&(0<=b&&b<1)&&(0<=c&&c<1)

両方の関数は4つのペアgh取ります。最初のペアは包含をテストするポイントで、残りは三角形の頂点の座標です。

サンプル入力でテストするには:

let trueTestCases =
  [((-0.31961, -0.12646), (0.38478, 0.37419), (-0.30613, -0.59754), (-0.85548, 0.6633)),
   ((-0.87427, -0.00831), (0.78829, 0.60409), (-0.90904, -0.13856), (-0.80685, 0.48468)),
   ((0.28997, -0.03668), (-0.28362, 0.42831), (0.39332, -0.07474), (-0.48694, -0.10497)),
   ((-0.07783, 0.04415), (-0.34355, -0.07161), (0.59105, -0.93145), (0.29402, 0.90334)),
   ((0.36107, 0.05389), (0.27103, 0.47754), (-0.00341, -0.79472), (0.82549, -0.29028)),
   ((-0.01655, -0.20437), (-0.36194, -0.90281), (-0.26515, -0.4172), (0.36181, 0.51683)),
   ((-0.12198, -0.45897), (-0.35128, -0.85405), (0.84566, 0.99364), (0.13767, 0.78618)),
   ((-0.03847, -0.81531), (-0.18704, -0.33282), (-0.95717, -0.6337), (0.10976, -0.88374)),
   ((0.07904, -0.06245), (0.95181, -0.84223), (-0.75583, -0.34406), (0.16785, 0.87519)),
   ((-0.33485, 0.53875), (-0.25173, 0.51317), (-0.62441, -0.90698), (-0.47925, 0.74832))]

let falseTestCases =
  [((-0.99103, 0.43842), (0.78128, -0.10985), (-0.84714, -0.20558), (-0.08925, -0.78608)),
   ((0.15087, -0.56212), (-0.87374, -0.3787), (0.86403, 0.60374), (0.01392, 0.84362)),
   ((0.1114, 0.66496), (-0.92633, 0.27408), (0.92439, 0.43692), (0.8298, -0.29647)),
   ((0.87786, -0.8594), (-0.42283, -0.97999), (0.58659, -0.327), (-0.22656, 0.80896)),
   ((0.43525, -0.8923), (0.86119, 0.78278), (-0.01348, 0.98093), (-0.56244, -0.75129)),
   ((-0.73365, 0.28332), (0.63263, 0.17177), (-0.38398, -0.43497), (-0.31123, 0.73168)),
   ((-0.57694, -0.87713), (-0.93622, 0.89397), (0.93117, 0.40775), (0.2323, -0.30718)),
   ((0.91059, 0.75966), (0.60118, 0.73186), (0.32178, 0.88296), (-0.90087, -0.26367)),
   ((0.3463, -0.89397), (0.99108, 0.13557), (0.50122, -0.8724), (0.43385, 0.00167)),
   ((0.88121, 0.36469), (-0.29829, 0.21429), (0.31395, 0.2734), (0.43267, -0.78192))]

type Point = (Double, Double)

test :: [(Point, Point, Point, Point)] -> [Bool]
test testCases =
  map (\((px,py),(ax,ay),(bx,by),(cx,cy)) -> h (px,py) (ax,ay) (bx,by) (cx,cy)) testCases

test trueTestCases --> [True,True,True,True,True,True,True,True,True,True]
test falseTestCases --> [False,False,False,False,False,False,False,False,False,False]

ゴルフのないソリューション:

type Point = (Double, Double)

-- using cross products

triangulate' (a, b) (p, q) (r, s) (t, u) =
  (side a b p q r s == side a b r s t u) && (side a b r s t u == side a b t u p q)
  where side j k l m n o = (o - m) * (j - l) + (-n + l) * (k - m) >= 0

-- using barycentric coordinates

triangulate :: (Point, Point, Point, Point) -> Bool
triangulate ((px, py), (ax, ay), (bx, by), (cx, cy)) = 
  let (p'x, p'y) = (px + (-ax), py + (-ay))
      (b'x, b'y) = (bx + (-ax), by + (-ay))
      (c'x, c'y) = (cx + (-ax), cy + (-ay))
      d = b'x * c'y - c'x * b'y
      a = (p'x * (b'y - c'y) + p'y * (c'x - b'x) + b'x * c'y - c'x * b'y) / d
      b = (p'x * c'y - p'y * c'x) / d
      c = (p'y * b'x - p'x * b'y) / d
  in
      (0 <= a && a < 1) && (0 <= b && b < 1) && (0 <= c && c < 1)

2

JavaScript(ES6)120

C=(p,q,i,j,k,l,m,n,
 z=j*(m-k)+i*(l-n)+k*n-l*m,
 s=(j*m-i*n+(n-j)*p+(i-m)*q)/z,
 t=(i*l-j*k+(j-l)*p+(k-i)*q)/z
)=>s>0&t>0&s+t<1

この他の質問への私の回答から直接コピー

FireFox / FireBugコンソールでテストする

すべて1を出力

;[
C(-0.31961, -0.12646, 0.38478, 0.37419, -0.30613, -0.59754, -0.85548, 0.6633),
C(-0.87427, -0.00831, 0.78829, 0.60409, -0.90904, -0.13856, -0.80685, 0.48468),
C(0.28997, -0.03668, -0.28362, 0.42831, 0.39332, -0.07474, -0.48694, -0.10497),
C(-0.07783, 0.04415, -0.34355, -0.07161, 0.59105, -0.93145, 0.29402, 0.90334),
C(0.36107, 0.05389, 0.27103, 0.47754, -0.00341, -0.79472, 0.82549, -0.29028),
C(-0.01655, -0.20437, -0.36194, -0.90281, -0.26515, -0.4172, 0.36181, 0.51683),
C(-0.12198, -0.45897, -0.35128, -0.85405, 0.84566, 0.99364, 0.13767, 0.78618),
C(-0.03847, -0.81531, -0.18704, -0.33282, -0.95717, -0.6337, 0.10976, -0.88374),
C(0.07904, -0.06245, 0.95181, -0.84223, -0.75583, -0.34406, 0.16785, 0.87519),
C(-0.33485, 0.53875, -0.25173, 0.51317, -0.62441, -0.90698, -0.47925, 0.74832)
]

すべて0を出力

;[
C(-0.99103, 0.43842,0.78128, -0.10985,-0.84714, -0.20558,-0.08925, -0.78608),
C(0.15087, -0.56212,-0.87374, -0.3787,0.86403, 0.60374,0.01392, 0.84362),
C(0.1114, 0.66496,-0.92633, 0.27408,0.92439, 0.43692,0.8298, -0.29647),
C(0.87786, -0.8594,-0.42283, -0.97999,0.58659, -0.327,-0.22656, 0.80896),
C(0.43525, -0.8923,0.86119, 0.78278,-0.01348, 0.98093,-0.56244, -0.75129),
C(-0.73365, 0.28332,0.63263, 0.17177,-0.38398, -0.43497,-0.31123, 0.73168),
C(-0.57694, -0.87713,-0.93622, 0.89397,0.93117, 0.40775,0.2323, -0.30718),
C(0.91059, 0.75966,0.60118, 0.73186,0.32178, 0.88296,-0.90087, -0.26367),
C(0.3463, -0.89397,0.99108, 0.13557,0.50122, -0.8724,0.43385, 0.00167),
C(0.88121, 0.36469,-0.29829, 0.21429,0.31395, 0.2734,0.43267, -0.78192)
]

2

SmileBASIC、111 100文字

DEF T X,Y,A,B,C,D,E,F
Q=9e5GCLS
GTRI(A-X)*Q,Q*(B-Y),Q*(C-X),Q*(D-Y),Q*(E-X),Q*(F-Y)?!!GSPOIT(0,0)END

三角形を描画し、ポイントのピクセルの色を確認します。三角形は、99999xに拡大され、チェックされる点が描画前に(0,0)になるようにシフトされ、精度の損失を最小限に抑えます。


2

Intel 8087 FPUアセンブリ、 222 220バイト

8087 FPUハードウェアのみを使用して計算します。MACROとしての未組み立て(この場合も未使用)バージョンは次のとおりです(220の16進バイトコードは不要です)。

; calculate the area of of a triangle ABC using determinate
; input: coordinates (float), Ax,Ay,Bx,By,Cx,Cy
; output: area in ST
TAREA   MACRO   A1,A2,B1,B2,C1,C2
    FLD  A1
    FLD  B2
    FLD  C2
    FSUB        ; ST = By - Cy
    FMUL        ; ST = Ax * ( By - Cy )
    FLD  B1 
    FLD  C2
    FLD  A2
    FSUB        ; ST = Cy - Ay
    FMUL        ; ST = Bx * ( Cy - Ay )
    FLD  C1
    FLD  A2
    FLD  B2
    FSUB        ; Ay - By
    FMUL        ; Cx * ( Ay - By )
    FADD        ; Cx * ( Ay - By ) + Bx * ( Cy - Ay )
    FADD        ; Cx * ( Ay - By ) + Bx * ( Cy - Ay ) + Ax * ( By - Cy )
    FLD1        ; make a value of 2
    FADD ST,ST  ; ST = 2
    FDIV        ; divide by 2
    FABS        ; take abs value
        ENDM

; determine if point X is in triangle ABC
; input: points X, A, B, C
; output: ZF=1 if X in triangle, ZF=0 if X not in triangle
TXINABC     MACRO X1,X2,A1,A2,B1,B2,C1,C2

    TAREA  A1,A2,B1,B2,C1,C2    ; ST(3) = area of triangle ABC
    TAREA  X1,X2,B1,B2,C1,C2    ; ST(2) = area of triangle XBC
    TAREA  A1,A2,X1,X2,C1,C2    ; ST(1) = area of triangle AXC
    TAREA  A1,A2,B1,B2,X1,X2    ; ST(0) = area of triangle ABX

    FADD        ; add areas of triangles with point
    FADD        ; ST = ST + ST(1) + ST(2)
    FCOMPP      ; compare ST to ST(1) and pop results
    FWAIT       ; sync CPU/FPU
    FSTSW R     ; store result flags to R
    MOV  AX, R  ; move result to AX
    SAHF        ; store result into CPU flags for conditional check
        ENDM

説明

確定行列を使用してABC三角形の面積を計算し、次にX点とABC三角形の2つの他の点で形成された三角形を計算します。三角形ABCの​​面積が三角形XBC + AXC + ABXの面積の合計に等しい場合、ポイントは三角形内にあります。結果はZFとして返されます。

これのすてきなところ

すべての数学および浮動小数点演算は、80ビット拡張精度のハードウェアで実行されます。最終的な浮動小数点比較もハードウェアで行われるため、非常に正確です。

また、これは8087の8つのスタックレジスタすべてを一度に使用します。

これほどきれいではないもの

三角形のポイントは計算中に数式に何度も差し戻す必要があるため、メモリ内の各変数を正しい順序で1つずつFPUのスタックレジスタにロードする必要があります。これはMACROとしての関数のようにかなり簡単にモデル化できますが、それはコードがアセンブリのたびに展開され、冗長コードが作成されることを意味します。同じ繰り返しコードセグメントの一部をPROCに移動することで、41バイトが節約されました。ただし、コードが読みにくくなるため、上記のリストにはコードが含まれていません(そのため、「ungolfed」とラベル付けされています)。

テスト

IBM DOSを使用した出力を示すテストプログラムを次に示します。

TTEST   MACRO T
        LOCAL IS_IN_TRI

    TXINABC T,T+4*1,T+4*2,T+4*3,T+4*4,T+4*5,T+4*6,T+4*7
    MOV  DX, OFFSET TEQ     ; load true string by default 
    JZ   IS_IN_TRI          ; if ZF=1, it is in triangle, skip to display
    MOV  DX, OFFSET FEQ     ; otherwise ZF=0 means not in triangle, so load false string
IS_IN_TRI:
    MOV  AH, 9              ; DOS write string function
    INT  21H 
        ENDM

START:
    FINIT                   ; reset 8087

    TTEST   T0              ; true tests
    TTEST   T1
    TTEST   T2
    TTEST   T3
    TTEST   T4
    TTEST   T5
    TTEST   T6
    TTEST   T7
    TTEST   T8
    TTEST   T9

    TTEST   F0              ; false tests
    TTEST   F1
    TTEST   F2
    TTEST   F3
    TTEST   F4
    TTEST   F5
    TTEST   F6  
    TTEST   F7
    TTEST   F8  
    TTEST   F9

    RET         ; return to DOS

T0  DD  -0.31961, -0.12646, 0.38478, 0.37419, -0.30613, -0.59754, -0.85548, 0.6633
T1  DD  -0.87427, -0.00831, 0.78829, 0.60409, -0.90904, -0.13856, -0.80685, 0.48468
T2  DD  0.28997, -0.03668, -0.28362, 0.42831, 0.39332, -0.07474, -0.48694, -0.10497
T3  DD  -0.07783, 0.04415, -0.34355, -0.07161, 0.59105, -0.93145, 0.29402, 0.90334
T4  DD  0.36107, 0.05389, 0.27103, 0.47754, -0.00341, -0.79472, 0.82549, -0.29028
T5  DD  -0.01655, -0.20437, -0.36194, -0.90281, -0.26515, -0.4172, 0.36181, 0.51683
T6  DD  -0.12198, -0.45897, -0.35128, -0.85405, 0.84566, 0.99364, 0.13767, 0.78618
T7  DD  -0.03847, -0.81531, -0.18704, -0.33282, -0.95717, -0.6337, 0.10976, -0.88374
T8  DD  0.07904, -0.06245, 0.95181, -0.84223, -0.75583, -0.34406, 0.16785, 0.87519
T9  DD  -0.33485, 0.53875, -0.25173, 0.51317, -0.62441, -0.90698, -0.47925, 0.74832

F0  DD  -0.99103, 0.43842, 0.78128, -0.10985, -0.84714, -0.20558, -0.08925, -0.78608
F1  DD  0.15087, -0.56212, -0.87374, -0.3787, 0.86403, 0.60374, 0.01392, 0.84362
F2  DD  0.1114, 0.66496, -0.92633, 0.27408, 0.92439, 0.43692, 0.8298, -0.29647
F3  DD  0.87786, -0.8594, -0.42283, -0.97999, 0.58659, -0.327, -0.22656, 0.80896
F4  DD  0.43525, -0.8923, 0.86119, 0.78278, -0.01348, 0.98093, -0.56244, -0.75129
F5  DD  -0.73365, 0.28332, 0.63263, 0.17177, -0.38398, -0.43497, -0.31123, 0.73168
F6  DD  -0.57694, -0.87713, -0.93622, 0.89397, 0.93117, 0.40775, 0.2323, -0.30718
F7  DD  0.91059, 0.75966, 0.60118, 0.73186, 0.32178, 0.88296, -0.90087, -0.26367
F8  DD  0.3463, -0.89397, 0.99108, 0.13557, 0.50122, -0.8724, 0.43385, 0.00167
F9  DD  0.88121, 0.36469, -0.29829, 0.21429, 0.31395, 0.2734, 0.43267, -0.78192

TEQ DB 'In Triangle',0DH,0AH,'$'
FEQ DB 'Not In Triangle',0DH,0AH,'$'

出力

In Triangle
In Triangle
In Triangle
In Triangle
In Triangle
In Triangle
In Triangle
In Triangle
In Triangle
In Triangle
Not In Triangle
Not In Triangle
Not In Triangle
Not In Triangle
Not In Triangle
Not In Triangle
Not In Triangle
Not In Triangle
Not In Triangle
Not In Triangle

1

C 414(465だった)

ゴルフ

#define D double 
int F(D ax,D ay,D bx,D by,D cx,D cy,D px,D py){int y=0;double J,K;D m=(ax-bx<0.001)?(by-ay)/(ax-bx):1000;D b=m*ax+ay;J=m*cx-cy+b;K=m*px-py+b;if(J*K>=0)y=1;return y;}D T[8],k;int i,n;void G(){while(i<8){scanf("%lf",&k);T[i++]=k;}n+=F(T[2],T[3],T[4],T[5],T[6],T[7],T[0],T[1]);n+=F(T[4],T[5],T[6],T[7],T[2],T[3],T[0],T[1]);n+=F(T[2],T[3],T[6],T[7],T[4],T[5],T[0],T[1]);printf(n==3?"True":"False");}

説明のために追加された元の関数宣言

/**
* determine if points C & P are on same side of line AB
* return 1 if true, 0 otherwise
*/
int PointsSameSide(D ax,D ay,D bx,D by,D cx, D cy, D px, D py);

名前付き関数として書き直されました:stdinを介して1行ごとに入力するか、スペースで区切って1行に入力します。

#define D double
int F(D ax,D ay,D bx,D by,D cx, D cy, D px, D py)
{
int y=0;
double J,K;
D m = (ax-bx<0.001)?(by-ay)/(ax-bx):1000;
D b = m*ax+ay;
J=m*cx-cy+b;
K=m*px-py+b;
if(J*K>=0)y=1;
return y;
}
double T[8],k;
int i,n;
void G()
{
while(i<8){scanf("%lf",&k);T[i++]=k;}
n+=F(T[2],T[3],T[4],T[5],T[6],T[7],T[0],T[1]);
n+=F(T[4],T[5],T[6],T[7],T[2],T[3],T[0],T[1]);
n+=F(T[2],T[3],T[6],T[7],T[4],T[5],T[0],T[1]);
printf(n==3?"True":"False");
}

3
改行と不要なスペースを取り除くことで、いくつかのバイトを節約できます。また、doubleas を再定義しましたDが、それでもdoubleコードで使用しています。
グロノスタジ14

1

Java、149文字

g=Math.atan2(100*(d-y),(a-x));h=Math.atan2(100*(e-y),(b-x));i=Math.atan2(100*(f-y),(c-x));k=Math.round(Math.abs(g-h)+Math.abs(h-i)+Math.abs(i-g))==6;

「数学」を書かなければならないと考えると恐ろしい。毎回。これは実際のプログラムです:

package mathPackage;
public class InTriangle {
public static void main(String[] args) {
    boolean k;
    double a=-1,b=0,c=1,d=0,e=1,f=0,x=0,y=0.4;
    double g,h,i;
    g=Math.atan2(100*(d-y),(a-x));
    h=Math.atan2(100*(e-y),(b-x));
    i=Math.atan2(100*(f-y),(c-x));
    k=Math.round(Math.abs(g-h)+Math.abs(h-i)+Math.abs(i-g))==6;
    System.out.println(k);
    System.out.println(g);
    System.out.println(h);
    System.out.println(i);
    System.out.print(Math.abs(g-h)+Math.abs(h-i)+Math.abs(i-g));
}
}

ここで、aはポイントaのx、bはポイントbのx、cはxのc、dはaのy、eはbのy、fはcのy、xとyはxおよびポイントのy。ブール値kは、真かどうかを決定します。


1
何の100*ためですか?
XNOR

1

JavaScript 125/198

8つの引数でポイントが提供される場合:

function d(x,y,a,b,c,d,e,f){function z(a,b,c,d){return(y-b)*(c-a)-(x-a)*(d-b)>0}return(z(a,b,c,d)+z(c,d,e,f)+z(e,f,a,b))%3<1}

ポイントが2次元配列で提供される場合:

function c(s){return (z(s[1][0],s[1][1],s[2][0],s[2][1])+z(s[2][0],s[2][1],s[3][0],s[3][1])+z(s[3][0],s[3][1],s[1][0],s[1][1]))%3<1;function z(a,b,c,d){return (s[0][1]-b)*(c-a)-(s[0][0]-a)*(d-b)>0}}

このコードでは、これらの派手なベクトル演算は使用していません。代わりに、単純な代数トリックを使用して、ポイントが三角形の内側にあるかどうかを判断します。式:

(y-b)(c-a) - (x-a)(d-b)

これは、ポイントが線のどちら側にあるかを示すもので、勾配の定義を再配置することで得られます。

            m = (y2-y1)/(x2-x1)
      (y2-y1) = m(x2-x1)
       (y-y1) = m(x-x1)     ,substituting point we are testing (x,y) to be the 2nd point
       (y-y1) = (x-x1)(y2-y1)/(x2-x1)  ,substitute back the original definition of m
(y-y1)(x2-x1) = (x-x1)(y2-y1)    <-- left side will be greater than the right side, if
                                     the point is on the left; otherwise, it's on the right
            0 = (y-b)(c-a)-(x-a)(d-b) ,where (a,b)=(x1,y1), (c,d)=(x2,y2)

3辺すべてをテストする場合、三角形の周囲でテストするため、ポイントが三角形の内側にある場合にのみ、3辺すべてで同じ符号の数字が得られます。ポイントが側面にある場合、テストの1つは0を返します。

jsFiddleテストコード:http ://jsfiddle.net/DerekL/zEzZU/

var l = [[-0.31961, -0.12646, 0.38478, 0.37419, -0.30613, -0.59754, -0.85548, 0.6633],[-0.87427, -0.00831, 0.78829, 0.60409, -0.90904, -0.13856, -0.80685, 0.48468],[0.28997, -0.03668, -0.28362, 0.42831, 0.39332, -0.07474, -0.48694, -0.10497],[-0.07783, 0.04415, -0.34355, -0.07161, 0.59105, -0.93145, 0.29402, 0.90334],[0.36107, 0.05389, 0.27103, 0.47754, -0.00341, -0.79472, 0.82549, -0.29028],[-0.01655, -0.20437, -0.36194, -0.90281, -0.26515, -0.4172, 0.36181, 0.51683],[-0.12198, -0.45897, -0.35128, -0.85405, 0.84566, 0.99364, 0.13767, 0.78618],[-0.03847, -0.81531, -0.18704, -0.33282, -0.95717, -0.6337, 0.10976, -0.88374],[0.07904, -0.06245, 0.95181, -0.84223, -0.75583, -0.34406, 0.16785, 0.87519],[-0.33485, 0.53875, -0.25173, 0.51317, -0.62441, -0.90698, -0.47925, 0.74832],
         [-0.99103, 0.43842, 0.78128, -0.10985, -0.84714, -0.20558, -0.08925, -0.78608],[0.15087, -0.56212, -0.87374, -0.3787, 0.86403, 0.60374, 0.01392, 0.84362],[0.1114, 0.66496, -0.92633, 0.27408, 0.92439, 0.43692, 0.8298, -0.29647],[0.87786, -0.8594, -0.42283, -0.97999, 0.58659, -0.327, -0.22656, 0.80896],[0.43525, -0.8923, 0.86119, 0.78278, -0.01348, 0.98093, -0.56244, -0.75129],[-0.73365, 0.28332, 0.63263, 0.17177, -0.38398, -0.43497, -0.31123, 0.73168],[-0.57694, -0.87713, -0.93622, 0.89397, 0.93117, 0.40775, 0.2323, -0.30718],[0.91059, 0.75966, 0.60118, 0.73186, 0.32178, 0.88296, -0.90087, -0.26367],[0.3463, -0.89397, 0.99108, 0.13557, 0.50122, -0.8724, 0.43385, 0.00167],[0.88121, 0.36469, -0.29829, 0.21429, 0.31395, 0.2734, 0.43267, -0.78192]];

function d(x,y,a,b,c,d,e,f){function z(a,b,c,d){return(y-b)*(c-a)-(x-a)*(d-b)>0}return(z(a,b,c,d)+z(c,d,e,f)+z(e,f,a,b))%3<1}

for(var i = 0; i < l.length; i++){
    console.log(d.apply(undefined,l[i]));    //10 true, 10 false
}

CoffeeScriptに変換された場合、97文字(スペースまたはタブはカウントされません)がカウントされます。

d=(x,y,a,b,c,d,e,f)->
    z=(a,b,c,d)->
        (y-b)*(c-a)-(x-a)*(d-b)>0
    (z(a,b,c,d)+z(c,d,e,f)+z(e,f,a,b))%3<1

ES6に変換された場合、115文字

d=(x,y,a,b,c,d,e,f)=>{z=(a,b,c,d)=>{return (y-b)*(c-a)-(x-a)*(d-b)>0};return(z(a,b,c,d)+z(c,d,e,f)+z(e,f,a,b))%3<1}

これ、私が:Dを使用している「派手なベクトル演算」です(ただし、他の人が採用した派手な重心座標アプローチではありません)。トップ投票の回答のように、ES6を使用してのような関数を定義することにより、数バイトを節約できますd=(x,y,...)=>{...}。あなたの場合、CoffeeScriptを使用してさらに保存できます。CoffeeScriptは必要ありません。pastebin.comreturn / RVFk1D5k ...いずれにしても、の<1代わりにを使用して1バイトを保存できます==0
マーティンエンダー14

@ m.buettner:o使用した方程式はベクトル(単純な代数から導出された)とは関係がないと思いましたが、どちらも同じ方程式を生成するようです。数学は素晴らしい。
デレク朕會功夫14

1

R、23

MATLABに触発され、

SDMTools::pnt.in.poly()

は、長さ2のベクトルであり、頂点の3x2行列であるようSDMTools::pnt.in.poly(point,triangle)に呼ばれます。SDMToolsはCRANで入手できます。pointtriangle


1

Mathematica、38文字

RegionMember[Polygon[#[[1]]],#[[2]]] &

例:

d = {{{0, 0}, {1, 0}, {.5, .7}}, {.5, .6}};

RegionMember[Polygon[#[[1]]], #[[2]]] & @ d

(* True *)


スペースを文字として数えるのが標準ですが、おそらくここでは何も壊さずにスペースを削除できます。
xnor

1
また、事前定義変数を使用するのではなく、入力を取得して出力を生成する必要があります。Mathematicaの回答を検索して、その方法を確認できます。
xnor

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.