我有 2 个点 (x1,y1) & (x2,y2) 和一个圆,假设这 2 个点之间有一条线,我需要检查是否与圆发生碰撞
I have 2 points (x1,y1) & (x2,y2) and a circle, suppose there is a line between the 2 points I need to check if there is collision with the circle
正如我在标题中提到的,假设我有一条从点 1 到点 2 的线段,并且有一个圆心和半径我需要检查是否会与圆发生碰撞使用代码。这就是我的进展。
但是,closestX 和 closestY 存在问题,因为我需要检查它们是否在从点 1 到点 2 的线段上,因为如果它们不在线段上,则不会发生碰撞。可悲的是,虽然我被困在这里,但我无法想出一种方法来检查它们是否在线段上。请帮忙谢谢。
import math
p=2
obsHeight=200
DroneHeight=150
cx=3
cy=3
r=1
x1=1
y1=1
x2=1.5
y2=1.5
if DroneHeight<=obsHeight:
distX= x1 - x2
distY= y1 - y2
length=math.sqrt((distX*distX) + (distY*distY ))
dot= (((cx-x1)*(x2-x1)) + ((cy-y1)*(y2-y1)) )/(math.pow(length,p))
closestX=x1+( dot * (x2-x1))
closestY=y1+( dot * (y2-y1))
print(" Closest x: ",closestX)
print(" Closest y: ",closestY)
distX=closestX-cx
distY= closestY-cy
distance= math.sqrt((distX*distX) + (distY*distY ))
print("The distance is: ", distance)
print("The length is: ", length)
if (r==distance):
print("Touching")
elif (distance<r):
print("COLLIDING")
else:
print("Will not collide")
else:
print(" Will not collide, the drone is higher than the obstacle")
可以通过
计算圆心到直线的平方距离
d2 = ((y1-y2)*(cx-x1)+(x2-x1)*(cy-y1))**2/((x2-x1)**2+(y2-y1)**2)
现在只需将该值与平方半径进行比较。如果 d2
编辑:
我认为您已经非常接近正确的解决方案了。在计算点积的行中,您应该除以线段的长度,而不是除以其平方长度。只需在 math.pow 表达式周围放置 (...)**0.5 即可给出正确的值。
注意:
Phython 有一个名为 ** 的内置幂运算符,因此无需使用 math.pow
忽略代码的特殊性,假设您有一条线段、一个中心和一个半径。下面写一个N维的线段是否与N维的超球面相交的通解。这将为我们在 2D 的特殊情况下为您的问题提供正确的解决方案。
您的函数签名如下所示:
def intersects(p1, p2, c, r):
p1
和 p2
是长度为 N 的向量。在您的例子中,p1 = np.array([1, 1])
和 p2 = np.array([1.5, 1.5])
。 c
是等长向量(c = np.array([3, 3])
),r
是标量半径(r = 1
)。我强烈建议您使用 numpy 数组进行数学运算,因为如果您正确使用它会更快,并且您可以在不使用循环的情况下对数组应用逐元素操作(例如 p2 - p1
)。
穿过p1
和p2
的线可以参数化为p = p1 + t * (p2 - p1)
。直线 p
上的每个点对应参数 t
的某个值。具体来说,t == 0
对应p = p1
,t == 1
对应p = p2
。这意味着你可以通过检查一个点的参数是否在 [0, 1]
.
范围内来知道它是否在线段上
然后问题就变成了找到 t
的值,使得 p
最接近 c
。如果 t < 0
或 t > 1
,则您知道线段的极值位于端点。否则,您需要比较两个端点的距离和您找到的 p
。
有几种不同的方法可以提出解决方案。几何方法利用了这样一个事实,即最近的方法发生在从 c
到直线的垂线上。微分方法找到长度的导数为零的位置。我会在这里展示前者。
查看图表,您有以下等式:
(c - p).dot(p2 - p1) == 0
(c - p1 - t * (p2 - p1)).dot(p2 - p1) == 0
(c - p1).dot(p2 - p1) - t * (p2 - p1).dot(p2 - p1) == 0
t == (c - p1).dot(p2 - p1) / (p2 - p1).dot(p2 - p1)
您现在可以像这样编写您的函数:
def intersects(p1, p2, c, r):
c1 = np.subtract(c, p1)
c2 = np.subtract(c, p2)
dist1 = np.linalg.norm(c1)
dist2 = np.linalg.norm(c2)
# If point are on opposite sides of circle, intersects
if (r - dist1) * (r - dist2) < 0:
return True
# If both on inside, does not intersect
if r > dist1:
return False
dp = np.subtract(p2, p1)
t = dp.dot(c1) / dp.dot(dp)
# If closest approach is outside segment, does not intersect
# convince yourself of this (use symmetry about the line c-p)
if t < 0 or t > 1:
return False
cp = np.subtract(p1 + t * dp, c)
distp = np.linalg.norm(cp)
# only other possibility of approach is when closest point is inside radius
return distp <= r
在 Stack Overflow 上和我的应用程序中多次出现查找点和线之间距离的问题,因此我最近将它添加到我维护的实用程序库中,haggis
. You can build a solution using haggis.math.segment_distance
逻辑非常相似。为此,我特地让函数以线段或全线模式运行:
def intersects(p1, p2, c, r):
dist1 = np.linalg.norm(c1 := np.subtract(c, p1))
dist2 = np.linalg.norm(c2 := np.subtract(c, p2))
if (r - dist1) * (r - dist2) < 0: # Opposite sides of circle
return True
if r > dist1: # Both inside circle
return False
d = segment_distance(c, p1, p2)
return d < r
您可以将最后两行改写如下:
d, t = segment_distance(c, p1, p2, segment=False, return_t=True)
return d < r and 0 <= t <= 1
正如我在标题中提到的,假设我有一条从点 1 到点 2 的线段,并且有一个圆心和半径我需要检查是否会与圆发生碰撞使用代码。这就是我的进展。 但是,closestX 和 closestY 存在问题,因为我需要检查它们是否在从点 1 到点 2 的线段上,因为如果它们不在线段上,则不会发生碰撞。可悲的是,虽然我被困在这里,但我无法想出一种方法来检查它们是否在线段上。请帮忙谢谢。
import math
p=2
obsHeight=200
DroneHeight=150
cx=3
cy=3
r=1
x1=1
y1=1
x2=1.5
y2=1.5
if DroneHeight<=obsHeight:
distX= x1 - x2
distY= y1 - y2
length=math.sqrt((distX*distX) + (distY*distY ))
dot= (((cx-x1)*(x2-x1)) + ((cy-y1)*(y2-y1)) )/(math.pow(length,p))
closestX=x1+( dot * (x2-x1))
closestY=y1+( dot * (y2-y1))
print(" Closest x: ",closestX)
print(" Closest y: ",closestY)
distX=closestX-cx
distY= closestY-cy
distance= math.sqrt((distX*distX) + (distY*distY ))
print("The distance is: ", distance)
print("The length is: ", length)
if (r==distance):
print("Touching")
elif (distance<r):
print("COLLIDING")
else:
print("Will not collide")
else:
print(" Will not collide, the drone is higher than the obstacle")
可以通过
计算圆心到直线的平方距离d2 = ((y1-y2)*(cx-x1)+(x2-x1)*(cy-y1))**2/((x2-x1)**2+(y2-y1)**2)
现在只需将该值与平方半径进行比较。如果 d2 编辑:
我认为您已经非常接近正确的解决方案了。在计算点积的行中,您应该除以线段的长度,而不是除以其平方长度。只需在 math.pow 表达式周围放置 (...)**0.5 即可给出正确的值。 注意:
Phython 有一个名为 ** 的内置幂运算符,因此无需使用 math.pow
忽略代码的特殊性,假设您有一条线段、一个中心和一个半径。下面写一个N维的线段是否与N维的超球面相交的通解。这将为我们在 2D 的特殊情况下为您的问题提供正确的解决方案。
您的函数签名如下所示:
def intersects(p1, p2, c, r):
p1
和 p2
是长度为 N 的向量。在您的例子中,p1 = np.array([1, 1])
和 p2 = np.array([1.5, 1.5])
。 c
是等长向量(c = np.array([3, 3])
),r
是标量半径(r = 1
)。我强烈建议您使用 numpy 数组进行数学运算,因为如果您正确使用它会更快,并且您可以在不使用循环的情况下对数组应用逐元素操作(例如 p2 - p1
)。
穿过p1
和p2
的线可以参数化为p = p1 + t * (p2 - p1)
。直线 p
上的每个点对应参数 t
的某个值。具体来说,t == 0
对应p = p1
,t == 1
对应p = p2
。这意味着你可以通过检查一个点的参数是否在 [0, 1]
.
然后问题就变成了找到 t
的值,使得 p
最接近 c
。如果 t < 0
或 t > 1
,则您知道线段的极值位于端点。否则,您需要比较两个端点的距离和您找到的 p
。
有几种不同的方法可以提出解决方案。几何方法利用了这样一个事实,即最近的方法发生在从 c
到直线的垂线上。微分方法找到长度的导数为零的位置。我会在这里展示前者。
查看图表,您有以下等式:
(c - p).dot(p2 - p1) == 0
(c - p1 - t * (p2 - p1)).dot(p2 - p1) == 0
(c - p1).dot(p2 - p1) - t * (p2 - p1).dot(p2 - p1) == 0
t == (c - p1).dot(p2 - p1) / (p2 - p1).dot(p2 - p1)
您现在可以像这样编写您的函数:
def intersects(p1, p2, c, r):
c1 = np.subtract(c, p1)
c2 = np.subtract(c, p2)
dist1 = np.linalg.norm(c1)
dist2 = np.linalg.norm(c2)
# If point are on opposite sides of circle, intersects
if (r - dist1) * (r - dist2) < 0:
return True
# If both on inside, does not intersect
if r > dist1:
return False
dp = np.subtract(p2, p1)
t = dp.dot(c1) / dp.dot(dp)
# If closest approach is outside segment, does not intersect
# convince yourself of this (use symmetry about the line c-p)
if t < 0 or t > 1:
return False
cp = np.subtract(p1 + t * dp, c)
distp = np.linalg.norm(cp)
# only other possibility of approach is when closest point is inside radius
return distp <= r
在 Stack Overflow 上和我的应用程序中多次出现查找点和线之间距离的问题,因此我最近将它添加到我维护的实用程序库中,haggis
. You can build a solution using haggis.math.segment_distance
逻辑非常相似。为此,我特地让函数以线段或全线模式运行:
def intersects(p1, p2, c, r):
dist1 = np.linalg.norm(c1 := np.subtract(c, p1))
dist2 = np.linalg.norm(c2 := np.subtract(c, p2))
if (r - dist1) * (r - dist2) < 0: # Opposite sides of circle
return True
if r > dist1: # Both inside circle
return False
d = segment_distance(c, p1, p2)
return d < r
您可以将最后两行改写如下:
d, t = segment_distance(c, p1, p2, segment=False, return_t=True)
return d < r and 0 <= t <= 1