# 二维碰撞检测

21

• 线段：由4个浮点数表示，指示两个端点，即（x 1，y 1（x 2，y 2。您可以假定端点不相同（因此线段不会退化）。
• 圆盘：即实心圆，以3个浮点表示，两个为中心（x，y），一个为（正）半径r
• ：这些是光盘的补充。也就是说，除了由中心和半径指定的圆形区域之外，空腔会填充所有2D空间。

## 测试用例

``````[0,[0,0],[2,2]], [0,[1,0],[2,4]]        # Crossing line segments
[0,[0.5,0],[-0.5,0]], [1,[0,0],1]       # Line contained in a disc
[0,[0.5,0],[1.5,0]], [1,[0,0],1]        # Line partially within disc
[0,[-1.5,0.5],[1.5,0.5]], [1,[0,0],1]   # Line cutting through disc
[0,[0.5,2],[-0.5,2]], [2,[0,0],1]       # Line outside cavity
[0,[0.5,0],[1.5,0]], [2,[0,0],1]        # Line partially outside cavity
[0,[-1.5,0.5],[1.5,0.5]], [2,[0,0],1]   # Line cutting through cavity
[1,[0,0],1], [1,[0,0],2]                # Disc contained within another
[1,[0,0],1.1], [1,[2,0],1.1]            # Intersecting discs
[1,[3,0],1], [2,[0,0],1]                # Disc outside cavity
[1,[1,0],0.1], [2,[0,0],1]              # Disc partially outside cavity
[1,[0,0],2], [2,[0,0],1]                # Disc encircling cavity
[2,[0,0],1], [2,[0,0],1]                # Any two cavities intersect
[2,[-1,0],1], [2,[1,0],1]               # Any two cavities intersect
``````

``````[0,[0,0],[1,0]], [0,[0,1],[1,1]]        # Parallel lines
[0,[-2,0],[-1,0]], [0,[1,0],[2,0]]      # Collinear non-overlapping lines
[0,[0,0],[2,0]], [0,[1,1],[1,2]]        # Intersection outside one segment
[0,[0,0],[1,0]], [0,[2,1],[2,3]]        # Intersection outside both segments
[0,[-1,2],[1,2]], [1,[0,0],1]           # Line passes outside disc
[0,[2,0],[3,0]], [1,[0,0],1]            # Circle lies outside segment
[0,[-0.5,0.5],[0.5,-0.5]], [2,[0,0],1]  # Line inside cavity
[1,[-1,0],1], [1,[1,1],0.5]             # Non-intersecting circles
[1,[0.5,0],0.1], [2,[0,0],1]            # Circle contained within cavity
``````

Emil

@Emil对不起，但是发布后9个小时，我不得不假设其他人可能已经开始应对挑战，并且更改规范（除了解决重大问题之外）对我来说不是一个好主意。不过，我认为，取决于您的操作方式，平行线段应该是您需要担心的线-线碰撞的唯一边缘情况。

Emil，2014年

TwiNight

@TwiNight如果两行是共线的，但不重叠，则不行。EG`[0,[-2,0],[-1,0]], [0,[1,0],[2,0]]`

Answers:

6

## APL，279 208 206 203

``````s←1 ¯1
f←{x←⊣/¨z←⍺⍵[⍋⊣/¨⍺⍵]
2 2≡x:∧/0∧.=⌊(2⊃-⌿↑z)⌹⍣(≠.×∘⌽/x)⍉↑x←s×-/2⊢/↑z
2≡2⌷x:∨/((2⊃z)∇2,x[1]×(2⌷⊃z)+,∘-⍨⊂y÷.5*⍨+.×⍨y←⌽s×⊃-/y),x[1]=(×⍨3⊃⊃z)>+.×⍨¨y←(s↓⌽↑z)-2⌷⊃z
~x∨.∧x[1]≠(.5*⍨+.×⍨2⊃-⌿↑z)<-/⊢/¨z×s*1⌷x}
``````

`2 2≡x`：细分市场

• 向量的终点不视为向量的一部分（尽管其起点是）。但是，如果仅矢量的尖端在另一个上，则根据规范，输入无效。
• 不论共线性，非退化并行段始终返回false。
• 如果其中一个段退化，则始终返回false。如果两个段均退化，则始终返回true。

`2≡2⌷x`：细分-其他

COTO 2014年

@COTO我未指定Unicode。据我所知，在APL字符集倒是可以为一个字节，并且有包含所有的APL字符的单字节代码页，所以使用该编码，字节数是好的。对于以“正常”语言在多字节字符串中编码内容的人，或者使用Mathematica的Unicode快捷方式的人，按字节计数最重要。
Martin Ender 2014年

@MartinBüttner：所以你说的是，即使没有一个文本编辑器为APL专门设计一个，每个人都无法合理地或实际地表示该字符串的每字节1字节版本，但它算作每字符1字节。因为语言规范中允许的字符数少于256个？
COTO 2014年

@COTO好吧，因为确实存在编码根据该编码可以解释单字节编码的文件。如果人们不得不进行编码，我认为我不愿意走那条路。否则，任何使用少于257个不同字符的程序都可以声明（我认为这几乎是PPCG的任何答案）。我只是认为我们不应该因为APL早于几十年而对APL进行惩罚-那时，将您拥有的字节解释为充当助记符的怪异时髦字符是有意义的。
Martin Ender 2014年

1
@COTO有一个J，它基于APL，仅使用ASCII字符。它们通常得分相似，因此即使使用Unicode得分也可能会打败您。而且我要补充一点，这两种语言都不是专为打高尔夫球而设计的，而AFAIK两者实际上都是专业人士使用的。而且这里打高尔夫球的挑战不仅仅在于获得绿色的勾号，还在于更多地用语言的手段从程序中挤出最后一个小字节并击败相同“体重类别”中的每个人，这通常会使您获得更多的赞誉而不是使用简洁的语言。;）
Martin Ender 2014年

5

# Javascript-393个字节

``````F=(s,a,t,b,e,x)=>(x=e||F(t,b,s,a,1),[A,B]=a,[C,D]=b,r=(p,l)=>([g,h]=l,[f,i]=y(h,g),[j,k]=y(p,g),m=Math.sqrt(f*f+i*i),[(f*j+i*k)/m,(f*k-i*j)/m]),u=(p,c)=>([f,g]=c,[i,j]=y(p,f),i*i+j*j<g*g),y=(p,c)=>[p[0]-c[0],p[1]-c[1]],[n,o]=r(C,a),[q,v]=r(D,a),w=(v*n-o*q)/(v-o),z=r(B,a)[0],Y=u(A,b),Z=u(B,b),[v*o<0&&w*(w-z)<0,Y||Z||o<D&&o>-D&&n*(n-z)<0,!Y||!Z,x,u(A,[C,D+B]),B>D||!u(A,[C,D-B]),x,x,1][s*3+t])
``````

``````F = (s,a,t,b,e,x) => (
x = e || F(t,b,s,a,1),
[A,B] = a,
[C,D] = b,
r = (p,l) => (
[g,h] = l,
[f,i] = y(h,g),
[j,k] = y(p,g),
m = Math.sqrt( f*f + i*i ),
[(f*j + i*k)/m, (f*k - i*j)/m] ),
u = (p,c) => (
[f,g] = c,
[i,j] = y(p,f),
i*i + j*j < g*g ),
y = (p,c) => [p[0] - c[0], p[1] - c[1]],
[n,o] = r(C,a),
[q,v] = r(D,a),
w = (v*n - o*q)/(v - o),
z = r(B,a)[0],
Y = u(A,b), Z = u(B,b),
[   v*o < 0 && w*(w-z) < 0,
Y || Z || o < D && o > -D && n*(n-z) < 0,
!Y || !Z,
x,
u(A,[C,D+B]),
B > D || !u(A,[C,D-B]),
x,
x,
1
][s*3+t]);
``````

• 定义`F`接受所需参数并返回所需值的函数
• 输入格式与OP中的格式相同，不同之处在于每个基元的整数类型代码与元组分开。例如，`F( 0,[[0,0],[2,2]], 0,[[1,0],[2,4]] )``F( 1,[[3,0],1], 2,[[0,0],1] )`
• 在OP中提供的所有测试用例上验证的代码
• 应该处理所有的边角情况，包括零长度线段和零半径圆

4

# Python，284

``````import math,random as r
n=lambda(a,c),(b,d):math.sqrt((a-b)**2+(c-d)**2)
x=lambda(t,a,b),p:max(eval(["n(b,p)-n(a,b)+","-b+","b-"][t]+'n(a,p)'),0)
def F(t,j):
q=0,0;w=1e9
for i in q*9000:
y=x(t,q)+x(j,q)
if y<w:p,w=q,y
q=(r.random()-.5)*w+p[0],(r.random()-.5)*w+p[1]
return w<.0001
``````

``````import math
import random as r
def norm(a, b):
return math.sqrt((a[0] - b[0])**2 + (a[1] - b[1])**2)

def lineWeight(a, b, p):
l1 = norm(a, p)
l2 = norm(b, p)
return min(l1, l2, l1 + l2 - norm(a, b))

def circleWeight(a, r, p):
return max(0, norm(a, p) - r)

def voidWeight(a, r, p):
return max(0, r - norm(a, p))

def weight(f1, f2, s1, s2, p):
return f1(s1[1], s1[2], p) + f2(s2[1], s2[2], p)

def checkCollision(s1, s2):
a = [lineWeight, circleWeight, voidWeight]
f1 = a[s1[0]]
f2 = a[s2[0]]
p = (0.0, 0.0)
w = 0
for i in a*1000:
w = weight(f1, f2, s1, s2, p)
p2 = ((r.random()-.5)*w + p[0], (r.random()-.5)*w + p[1])
if(weight(f1, f2, s1, s2, p2) < w):
p = p2
if w < .0001:
return True
return False
``````

``````import collisiongolfedbak
reload(collisiongolfedbak)

tests = [
[0,[0,0],[2,2]], [0,[1,0],[2,4]],        # Crossing line segments
[0,[0.5,0],[-0.5,0]], [1,[0,0],1],       # Line contained in a disc
[0,[0.5,0],[1.5,0]], [1,[0,0],1],        # Line partially within disc
[0,[-1.5,0.5],[1.5,0.5]], [1,[0,0],1],   # Line cutting through disc
[0,[0.5,2],[-0.5,2]], [2,[0,0],1],       # Line outside cavity
[0,[0.5,0],[1.5,0]], [2,[0,0],1],        # Line partially outside cavity
[0,[-1.5,0.5],[1.5,0.5]], [2,[0,0],1],   # Line cutting through cavity
[1,[0,0],1], [1,[0,0],2],                # Disc contained within another
[1,[0,0],1.1], [1,[2,0],1.1],            # Intersecting discs
[1,[3,0],1], [2,[0,0],1],                # Disc outside cavity
[1,[1,0],0.1], [2,[0,0],1],              # Disc partially outside cavity
[1,[0,0],2], [2,[0,0],1],                # Disc encircling cavity
[2,[0,0],1], [2,[0,0],1] ,               # Any two cavities intersect
[2,[-1,0],1], [2,[1,0],1] ,              # Any two cavities intersect
[0,[0,0],[1,0]], [0,[0,1],[1,1]] ,       # Parallel lines
[0,[-2,0],[-1,0]], [0,[1,0],[2,0]],      # Collinear non-overlapping lines
[0,[0,0],[2,0]], [0,[1,1],[1,2]],        # Intersection outside one segment
[0,[0,0],[1,0]], [0,[2,1],[2,3]],        # Intersection outside both segments
[0,[-1,2],[1,2]], [1,[0,0],1],           # Line passes outside disc
[0,[2,0],[3,0]], [1,[0,0],1],            # Circle lies outside segment
[0,[-0.5,0.5],[0.5,-0.5]], [2,[0,0],1],  # Line inside cavity
[1,[-1,0],1], [1,[1,1],0.5],             # Non-intersecting circles
[1,[0.5,0],0.1], [2,[0,0],1]            # Circle contained within cavity
]

for a, b in zip(tests[0::2], tests[1::2]):
print collisiongolfedbak.F(a,b)
``````
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.