ポリゴンにありますか?

Aug 24 2020

チャレンジ

ポイントとポイントのパスを指定して、そのポイントがパスによって作成されたポリゴン内にあるかどうかを示します。

trueポイントがポリゴンのエッジ上にある場合も戻ります。

入力

整数のペアのリスト。

最初の2つの整数はポイントを表します。

残りのペア(3番目と4番目、5番目と6番目など)は、ポリゴンの頂点を表します。

エッジは入力ペアの順序になっています。

パスは、パスの最初のポイントにループバックすると想定されます。

入力は有効であると見なされます。

パス内の3つのポイントが同一線上にあることはありません。

123 82 84 01 83 42

出力

真実/偽の値。

テストケース

入力->出力

0 0 10 10 10 -1 -5 0 -> true

5 5 10 10 10 50 50 20 -> false

5 5 0 0 0 10 1 20 6 30 10 -40 -> true

これはコードゴルフです。バイト単位の最短の回答が優先されます。

回答

11 Neil Aug 24 2020 at 06:30

木炭、5250バイト

≔⪪A²θF⟦E³§θ⊖ιθ✂θ¹⟧⊞υ↔ΣEι⁻×§κ⁰§§ι⊕λ¹×§κ¹§§ι⊕λ⁰⁼⊟υΣυ

オンラインでお試しください!リンクは、コードの詳細バージョンへのリンクです。説明:

≔⪪A²θ

入力を座標のペアに分割します。

F⟦E³§θ⊖ιθ✂θ¹⟧

3つのポリゴンの面積を計算します。最後、最初、2番目のポイントを取ることによって形成されたポリゴン。すべてのポイント(テストポイントを含む)から形成されたもの。テストポイントを除くすべてのポイントから形成されたもの。

⊞υ↔ΣEι⁻×§κ⁰§§ι⊕λ¹×§κ¹§§ι⊕λ⁰

靴紐の式を使用して、そのポリゴンの面積を計算します。

⁼⊟υΣυ

最後の領域が最初の2つの合計に等しいかどうかを確認します。この場合、ポイントはポリゴン内にあります。

10 J42161217 Aug 24 2020 at 12:26

Wolfram言語(Mathematica)、26バイト

Polygon@#2~RegionMember~#&

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

6 MatthewJensen Aug 24 2020 at 10:11

JavaScript(V8)、123バイト

(x,y,...p)=>p.map((_,i)=>p.concat(p).slice(i,i+4)).reduce((n,[a,b,c,d],i)=>i%2<1&&a<x!=c<x&&y<b+(d-b)*(x-a)/(c-a)?!n:n,!1)

ゴルフなし

(x, y, ...p)=>
  p.map((_, i) => p.concat(p).slice(i, i + 4)) // Group points into edges
  .reduce(
    (n, [a, b, c, d], i)=>                     // for every edge
      i % 2 < 1 &&                             // if it's actually an edge
      a < x != c < x &&                        // and x of point is within bounds
      y < b + (d - b) * (x - a) / (c - a) ?    // and point is below the line
      !n : n,                                  // then invert whether it's inside
    false
  )

TIOは今のところダウンしているようです。可能な場合(または他の誰かが最初に発生した場合)にリンクを追加します。

4 pxeger Aug 25 2020 at 15:42

PostgreSQL 12、91バイト

create function f(a polygon,b point,out o bool)as $$begin return a~b;end$$language plpgsql;

PostgreSQLには、組み込みのポリゴンタイプとポイントタイプ、および包含をテストするための組み込み演算子@>(~バイトを保存するためのスペルト小麦)があります。

...これは退屈すぎますか?

3 KevinCruijssen Aug 24 2020 at 14:32

ジャワ10、142の141バイト

a->{var p=new java.awt.geom.Path2D.Float();p.moveTo(a[2],a[3]);for(int i=3;++i<a.length;)p.lineTo(a[i],a[++i]);return p.contains(a[0],a[1]);}

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

説明:

a->{                         // Method with integer-array parameter and boolean return-type
  var p=new java.awt.geom.Path2D.Float();
                             //  Create a Path2D object
  p.moveTo(a[2],a[3]);       //  Set the starting position to the third and fourth values in the list
  for(int i=3;++i<a.length;) //  Loop `i` in the range (3, length):
    p.lineTo(                //   Draw a line to:
             a[i],           //    x = the `i`'th value in the array
             a[++i]);        //    y = the `i+1`'th value in the array
                             //        (by first increasing `i` by 1 with `++i`)
  return p.contains(a[0],a[1]);}
                             //  Check if the polygon contains the first two values as x,y
2 user Aug 24 2020 at 08:15

Scala、139バイト

入力がaで(Int, Int)あり、List[(Int, Int)]解析する必要がない場合は、少し簡単です。

(x,p)=>(p.last->p.head::p.zip(p.tail)count{q=>(q._1._2<=x._2&x._2<=q._2._2|q._1._2>=x._2&x._2>=q._2._2)&(x._1<=q._1._1|x._1<=q._2._1)})%2>0

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

回転数を使用して、140バイト

x=>y=>_.sliding(2).map{case Seq((a,b),(c,d))=>val(e,f,l)=(b>y,d>y,(a-x)*(d-y)-(c-x)*(b-y))
if(!e&f&l>0)1 else if(e& !f&l<0)-1 else 0}.sum!=0

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

ここで説明するアルゴリズムを使用します

文字列として入力した場合、186バイト

i=>{val x::p=i split " "map(_.toInt)grouped 2 toList;(p.last->p.head::p.zip(p.tail)count{q=>(q._1(1)<=x(1)&x(1)<=q._2(1)|q._1(1)>=x(1)&x(1)>=q._2(1))&(x(0)<=q._1(0)|x(0)<=q._2(0))})%2>0}

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

2 Noodle9 Aug 24 2020 at 20:00

C(gcc)、171 \$\cdots\$ 129126バイト

保存はなんと13 19 35は、おかげバイトceilingcatを!
保存された2 5のおかげでバイトをユーザーに!

W,i,l;f(x,y,V,n)int*V;{for(W=i=0;i<n-2;W+=V[i-2]>y^V[i]>y?(l>0)-(l<0):0)l=(V[i++]-x)*(V[i+2]-y)-(V[i++]-y)*(V[i]-x);return W;}

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

回転数アルゴリズムを使用します。回転数が真の場合、ポイントはポリゴンの内側にあり、そうでない場合は偽です。

2 user Aug 28 2020 at 07:00

Python 3.8(プレリリース)、134バイト

lambda x,y,p:sum((p[i+3]>y)^(p[i+1]>y)and(0<(l:=(p[i+2]-p[i])*(y-p[i+1])-(x-p[i])*(p[i+3]-p[i+1])))-(l<0)for i in range(0,len(p)-2,2))

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

2 Giuseppe Aug 28 2020 at 08:05

R、105バイト

function(P,m=matrix(c(P,P[3:4]),,2,T))!sd(sapply(3:nrow(m)-1,function(k)sign(det(diff(m[c(1,k+0:1),])))))

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

3つの点が同一線上にないことを前提としています。ここで説明されているアルゴリズムを拡張します。

クエリポイントを呼び出すと\$Q\$とポリゴンの順序付けられたポイント\$P_1\dots P_n\$、これはポリゴンのポイントをトラバースし、\によって形成される三角形の符号付き領域を計算することによって(シューレース法を使用して)セグメントのどちら側にあるかを確認します。$Q,P_{i},P_{i+1}\$:正の符号は左を意味し、反時計回りに進む場合は右を意味し、それ以外の場合は逆になります。すべての符号が同じである場合(つまり、符号の標準偏差が0の場合)、ポイントはポリゴン内にあります。

私の計算幾何学の教授は、このポリゴンの点の方法を思い出すのに4日かかったことを少し恥ずかしく思います。教科書/メモが見つかったら、アルゴリズムの説明を投稿します...

1 SE-stopfiringthegoodguys Aug 24 2020 at 19:48

> <>、92バイト

l[l0$21.>&-0=n; {$&:2-&?!v{:{:{:@*{:}@@}@@}@@*-@@+
:0$0(?$-v>]
3pl2-00.>&08
{{{{600.>&-&084p

ニールの靴紐式テクニックを実装します。

1 ojdo Aug 24 2020 at 22:22

Python 3、133バイト

救助する空間パッケージ:

from shapely.geometry import*
def f(s):
 c=list(map(int,s.split()))
 o,*p=zip(c[::2],c[1::2])
 return Point(o).intersects(Polygon(p))

使用する幾何学的操作は小さな落とし穴でした。Polygon.contains(Point)エッジケースはカバーしていません。

1 DominicvanEssen Aug 24 2020 at 18:27

R、139の 127 118 116バイト

編集:ジュゼッペによるgoadingのおかげで靴ひもの計算を改善することによって-23バイト

function(i,S=function(m)abs(sum(m*c(1,-1)*m[2:1,c(2:ncol(m),1)])))S(P<-matrix(i,2))==S(P[,-1])-S(P[,c(1:2,ncol(P))])

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

頂点としてテストポイント+2つの周囲ポイントを持つ三角形によって形成される「ケーキのスライス」が「ケーキ」全体の面積(テストポリゴン)からの面積を引いたものに等しいかどうかをテストするニールズの美しいアプローチを実装します「スライス」が削除された「ケーキ」(テストポイントを含むすべてのポイントを使用するポリゴン)。

inside=
function(i)
    {                                           # S is helper function to calculate 2x the cake area using 
                                                # the 'shoelace' formula:
    S=function(m)abs(sum(m*c(1,-1)*m[2:1,c(2:ncol(m),1)])/2)            
    P=matrix(i,2)                               # 'cake with missing slice' = polygon including test point
    T=P[,c(1:2,ncol(P))]                        # 'slice of cake' = triangle of test point + adjacent polygon vertices
    O=P[,-1]                                    # 'the cake' = outer polygon excluding test point
    S(P)==S(O)-S(T)                             # do the areas add-up?
}
1 Razetime Nov 13 2020 at 23:04

APL(Dyalog Unicode)、63バイト

{⍵∊⍺:1⋄(¯1∊×d)∨1<|+/⍟d←(⊢÷1∘⌽)⍺-⍵}

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

APLcartスニペットから直接取得。何が起こっているのかよくわかりません。誰かがもっと良い説明をしてくれたら嬉しいです。

入力は複雑なポイントとして扱われます。

左側をポリゴン、右側をポイントします。

説明

{⍵∊⍺:1⋄(¯1∊×d)∨1<|+/⍟d←(⊢÷1∘⌽)⍺-⍵}
{⍵∊⍺:1                           } return 1 if point is in list, otherwise:
      ⋄                       ⍺-⍵  subtract the point from each edge
                                   (gives all lines to from vertices to the point)
                       (⊢÷1∘⌽)     divide it by itself rotated by 1
                     d←            save it in d
                    ⍟              take the natural logarithm of each point
                  +/               and sum the vectors
                 |                 take the modulus
                                   (I think this gets the sum of angles)
               1<                  check if 1 is lesser than it
              ∨                    or
       (¯1∊×d)                     any of the points' signums equal (-1,0)