计算线相交的问题 [英] Problem with calculating line intersections
问题描述
我试图显示相交线的点,但是计算出的点在实际相交之间.
(
P ...指向1.行1.线的R ...方向Q ...点在2.行上S ... 2.线的方向Q-P和R之间的alpha ...夹角beta ... R与S之间的夹角伽马= 180°-alpha-betah = |Q-P |* sin(alpha)u = h/sin(β)t = |Q-P |* sin(γ)/sin(beta)t =点(Q-P,(S.y,-S.x))/点(R,(S.y,-S.x))=行列式(mat2(Q-P,S))/行列式(mat2(R,S))u = 点(Q-P,(R.y,-R.x))/点(R,(S.y,-S.x))=行列式(mat2(Q-P,R))/行列式(mat2(R,S))X = P + R * t = Q + S * u
另请参见
import pygame导入数学随机导入def intersect_line_line_vec2(startObs,endObs,起点,终点):P = pygame.Vector2(startObs)R =(endObs-P)Q = pygame.Vector2(来源)S =(端点-Q)d = R.dot((S.y,-S.x))如果d == 0:不返回t =(Q-P).dot((S.y,-S.x))/du =(Q-P).dot((R.y,-R.x))/d如果0< = t< = 1且0< = u< = 1:X = P + R * t返回 (X.x, X.y)不返回def intersect_line_line(P0,P1,Q0,Q1):d = (P1[0]-P0[0]) * (Q1[1]-Q0[1]) + (P1[1]-P0[1]) * (Q0[0]-Q1[0])如果d == 0:不返回t =((Q0 [0] -P0 [0])*(Q1 [1] -Q0 [1])+(Q0 [1] -P0 [1])*(Q0 [0] -Q1 [0]))/天u =((Q0 [0] -P0 [0])*(P1 [1] -P0 [1])+(Q0 [1] -P0 [1])*(P0 [0] -P1 [0]))/天如果0< = t< = 1且0< = u< = 1:返回P1 [0] * t + P0 [0] *(1-t),P1 [1] * t + P0 [1] *(1-t)不返回def createRays(center):返回[(center [0] + 1200 * math.cos(angle),center [1] + 1200 * math.sin(angle))表示范围在(0,360,10)中的角度]def createObstacles(表面):w,h = surface.get_size()返回[((random.randrange(w),random.randrange(h)),(random.randrange(w),random.randrange(h))对于_在range(5)中]窗口= pygame.display.set_mode((800,800))时钟= pygame.time.Clock()原点= window.get_rect().center射线= createRays(来源)障碍= createObstacles(窗口)move_center = True运行=真运行时:时钟滴答(60)对于pygame.event.get()中的事件:如果event.type == pygame.QUIT:运行=错误如果event.type == pygame.MOUSEBUTTONDOWN:障碍= createObstacles(窗口)如果event.type == pygame.KEYDOWN:move_center =不是move_center如果move_center:起源= pygame.mouse.get_pos()射线= createRays(来源)window.fill(0)对于光线中的端点:pygame.draw.line(窗口,(128,128,128),起点,终点)pygame.draw.circle(窗口,(255,255,255),起源,10)首先,在障碍中结束:pygame.draw.line(窗口,(255,0,0),开始,结束)对于光线中的端点:pos = intersect_line_line(起点,终点,原点,终点)如果pos:pygame.draw.circle(窗口,(0,255,0),(round(pos [0]),round(pos [1])),3)pygame.display.flip()pygame.quit()出口()
I am trying to display the points of intersecting lines, but the calculated points are between the actual intersectings.
(https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection)
I have checked the formulars multiple times and used another formula for calculating the intersecting points x, y [x3+u*(x4-x3), y3+u*(y4-y3)]
instead of [x1+t*(x2-x1), y1+t*(y2-y1)]
, but that just made the points somewhere really wrong
("d" is not referenced on the wikipedia page and is just the divisor for the formulars of t and u)
Function for calculating the intersection
def checkcol(self, startObs, endObs):
x1, y1 = startObs
x2, y2 = endObs
x3, y3 = run.lamp
x4, y4 = self.endpoint
d = (x1-x2)*(y3-y4)-(y1-y2)*(x3-x4)
t = ((x1-x3)*(y3-y4)-(y1-y3)*(x3-x4))/d
u = ((x1-x2)*(y1-y3)-(y1-y2)*(x1-x3))/d
if 0 < t < 1 and 1 > u > 0:
pygame.draw.circle(run.screen, pygame.Color('green'), (round(x1+t*(x2-x1)), round(y1+t*(y2-y1))), 3)
The whole code
import pygame
import sys
import math
import random as rd
class Obs(object):
def __init__(self, startp, endp):
self.startp = startp
self.endp = endp
def drawww(self):
pygame.draw.line(run.screen, pygame.Color('red'), (self.startp), (self.endp))
for ray in run.lines:
ray.checkcol(self.startp, self.endp)
class rays(object):
def __init__(self, endpoint):
self.width = 2
self.endpoint = endpoint
def draww(self):
pygame.draw.line(run.screen, pygame.Color('white'), run.lamp, self.endpoint, 2)
def moveEnd(self, xoff, yoff):
self.endpoint[0] += xoff
self.endpoint[1] += yoff
def checkcol(self, startObs, endObs):
x1, y1 = startObs
x2, y2 = endObs
x3, y3 = run.lamp
x4, y4 = self.endpoint
d = (x1-x2)*(y3-y4)-(y1-y2)*(x3-x4)
t = ((x1-x3)*(y3-y4)-(y1-y3)*(x3-x4))/d
u = ((x1-x2)*(y1-y3)-(y1-y2)*(x1-x3))/d
if 0 < t < 1 and 1 > u > 0:
pygame.draw.circle(run.screen, pygame.Color('green'), (round(x1+t*(x2-x1)), round(y1+t*(y2-y1))), 3)
class Control(object):
def __init__(self):
self.winw = 800
self.winh = 800
self.screen = pygame.display.set_mode((self.winw, self.winh))
self.fps = 60
self.clock = pygame.time.Clock()
self.lamp = [400, 400]
self.lampr = 13
self.lines = []
self.r = 10
self.Obs = [Obs((rd.randint(0, self.winw), rd.randint(0, self.winh)),
(rd.randint(0, self.winw), rd.randint(0, self.winh))) for i in range(5)]
self.done = False
def event_loop(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.done = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_F5:
self.__init__()
if pygame.mouse.get_pressed() == (1, 0, 0):
self.lamp = (pygame.mouse.get_pos())
for line in self.lines:
line.moveEnd(pygame.mouse.get_rel()[0], pygame.mouse.get_rel()[1])
def draw(self):
self.screen.fill((pygame.Color('black')))
pygame.draw.circle(self.screen, pygame.Color('white'), self.lamp, self.lampr)
for line in self.lines:
line.draww()
for obs in self.Obs:
obs.drawww()
def createlines(self):
self.lines.clear()
for angle in range(0, 361, 9):
self.lines.append(rays([self.lamp[0] + 1200 * math.cos(angle), self.lamp[1] + 1200 * math.sin(angle)]))
def main_loop(self):
while not self.done:
self.event_loop()
self.createlines()
self.draw()
pygame.display.update()
self.clock.tick(self.fps)
pygame.display.set_caption(f"Draw FPS: {self.clock.get_fps()}")
if __name__ == '__main__':
run = Control()
run.main_loop()
pygame.quit()
sys.exit()
Expected the points of intersecting to be at the actual points of intersection.
To find the intersection points of 2 rays or line segments in two-dimensional space, I use vector arithmetic and the following algorithm:
P ... point on the 1. line
R ... direction of the 1. line
Q ... point on the 2. line
S ... direction of the 2. line
alpha ... angle between Q-P and R
beta ... angle between R and S
gamma = 180° - alpha - beta
h = | Q - P | * sin(alpha)
u = h / sin(beta)
t = | Q - P | * sin(gamma) / sin(beta)
t = dot(Q-P, (S.y, -S.x)) / dot(R, (S.y, -S.x)) = determinant(mat2(Q-P, S)) / determinant(mat2(R, S))
u = dot(Q-P, (R.y, -R.x)) / dot(R, (S.y, -S.x)) = determinant(mat2(Q-P, R)) / determinant(mat2(R, S))
X = P + R * t = Q + S * u
See also Line–line intersection
If t == 1
, then X = P + R
. This can be used to assess whether the intersection is on a line segment.
If a line is defined through the 2 points L1
and L2
, it can be defined that P = L1
and R = L2-L1
. Therefore the point of intersection (X
) lies on the line segment from L1
to L2
if 0 <= t <= 1
.
The same relation applies to u
and S
.
The following function implements the above algorithm using pygame.math.Vector2
objects of the pygame.math
module:
def intersect_line_line_vec2(startObs, endObs, origin, endpoint):
P = pygame.Vector2(startObs)
R = (endObs - P)
Q = pygame.Vector2(origin)
S = (endpoint - Q)
d = R.dot((S.y, -S.x))
if d == 0:
return None
t = (Q-P).dot((S.y, -S.x)) / d
u = (Q-P).dot((R.y, -R.x)) / d
if 0 <= t <= 1 and 0 <= u <= 1:
X = P + R * t
return (X.x, X.y)
return None
The same algorithm without the use of the pygame.math
module, less readable but more or less the same:
def intersect_line_line(P0, P1, Q0, Q1):
d = (P1[0]-P0[0]) * (Q1[1]-Q0[1]) + (P1[1]-P0[1]) * (Q0[0]-Q1[0])
if d == 0:
return None
t = ((Q0[0]-P0[0]) * (Q1[1]-Q0[1]) + (Q0[1]-P0[1]) * (Q0[0]-Q1[0])) / d
u = ((Q0[0]-P0[0]) * (P1[1]-P0[1]) + (Q0[1]-P0[1]) * (P0[0]-P1[0])) / d
if 0 <= t <= 1 and 0 <= u <= 1:
return P1[0] * t + P0[0] * (1-t), P1[1] * t + P0[1] * (1-t)
return None
Applied to your code, this means:
class rays(object):
# [...]
def checkcol(self, startObs, endObs):
P = pygame.Vector2(startObs)
R = (endObs - P).normalize()
Q = pygame.Vector2(run.lamp)
S = (self.endpoint - Q).normalize()
d = R.dot((S.y, -S.x))
if R.dot((S.y, -S.x)) == 0:
return
t = (Q-P).dot((S.y, -S.x)) / d
u = (Q-P).dot((R.y, -R.x)) / d
if 0 <= t <= 1 and 0 <= u <= 1:
X = P + R * t
pygame.draw.circle(run.screen, pygame.Color('green'), (round(X.x), round(X.y)), 3)
Minimal example:
import pygame
import math
import random
def intersect_line_line_vec2(startObs, endObs, origin, endpoint):
P = pygame.Vector2(startObs)
R = (endObs - P)
Q = pygame.Vector2(origin)
S = (endpoint - Q)
d = R.dot((S.y, -S.x))
if d == 0:
return None
t = (Q-P).dot((S.y, -S.x)) / d
u = (Q-P).dot((R.y, -R.x)) / d
if 0 <= t <= 1 and 0 <= u <= 1:
X = P + R * t
return (X.x, X.y)
return None
def intersect_line_line(P0, P1, Q0, Q1):
d = (P1[0]-P0[0]) * (Q1[1]-Q0[1]) + (P1[1]-P0[1]) * (Q0[0]-Q1[0])
if d == 0:
return None
t = ((Q0[0]-P0[0]) * (Q1[1]-Q0[1]) + (Q0[1]-P0[1]) * (Q0[0]-Q1[0])) / d
u = ((Q0[0]-P0[0]) * (P1[1]-P0[1]) + (Q0[1]-P0[1]) * (P0[0]-P1[0])) / d
if 0 <= t <= 1 and 0 <= u <= 1:
return P1[0] * t + P0[0] * (1-t), P1[1] * t + P0[1] * (1-t)
return None
def createRays(center):
return [(center[0] + 1200 * math.cos(angle), center[1] + 1200 * math.sin(angle)) for angle in range(0, 360, 10)]
def createObstacles(surface):
w, h = surface.get_size()
return [((random.randrange(w), random.randrange(h)), (random.randrange(w), random.randrange(h))) for _ in range(5)]
window = pygame.display.set_mode((800, 800))
clock = pygame.time.Clock()
origin = window.get_rect().center
rays = createRays(origin)
obstacles = createObstacles(window)
move_center = True
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
obstacles = createObstacles(window)
if event.type == pygame.KEYDOWN:
move_center = not move_center
if move_center:
origin = pygame.mouse.get_pos()
rays = createRays(origin)
window.fill(0)
for endpoint in rays:
pygame.draw.line(window, (128, 128, 128), origin, endpoint)
pygame.draw.circle(window, (255, 255, 255), origin, 10)
for start, end in obstacles:
pygame.draw.line(window, (255, 0, 0), start, end)
for endpoint in rays:
pos = intersect_line_line(start, end, origin, endpoint)
if pos:
pygame.draw.circle(window, (0, 255, 0), (round(pos[0]), round(pos[1])), 3)
pygame.display.flip()
pygame.quit()
exit()
这篇关于计算线相交的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!