【问题标题】:Problem with finding the closest intersection寻找最近的路口的问题
【发布时间】:2019-05-26 18:23:01
【问题描述】:

光线一直投射到错误的“墙壁”上,但前提是灯更多地位于右下角。如果灯在左上角,一切正常。

我尝试了很多东西,但是上次我写了一个问题,我检查了很多次公式,最后是公式有问题,所以我什至没有尝试

(https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection)

寻找最近墙的功能:

    def draw(self):
        bestdist = 1000000000000000000
        for obs in run.Obs:
            x1, y1 = obs.startp
            x2, y2 = obs.endp
            x3, y3 = run.lamp
            x4, y4 = self.maxendpoint

            d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)
            if d != 0:
                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 u > 0:
                    px = round(x1 + t * (x2 - x1))
                    py = round(y1 + t * (y2 - y1))
                    dist = px**2+py**2
                    if dist < bestdist:
                        bestdist = dist
                        self.endpoint= [px, py]
                    # pygame.draw.circle(run.screen, pygame.Color('green'), (px, py), 3)
        if len(self.endpoint) == 2:
            pygame.draw.line(run.screen, pygame.Color('white'), run.lamp, self.endpoint)

整个代码:

import pygame
import sys
import math
import random as rd
import numpy as np

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))


class rays(object):
    def __init__(self, maxendpoint):
        self.maxendpoint = maxendpoint
        self.endpoint = []

    def draw(self):
        bestdist = 1000000000000000000
        for obs in run.Obs:
            x1, y1 = obs.startp
            x2, y2 = obs.endp
            x3, y3 = run.lamp
            x4, y4 = self.maxendpoint

            d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)
            if d != 0:
                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 u > 0:
                    px = round(x1 + t * (x2 - x1))
                    py = round(y1 + t * (y2 - y1))
                    dist = px**2+py**2
                    if dist < bestdist:
                        bestdist = dist
                        self.endpoint= [px, py]
                    # pygame.draw.circle(run.screen, pygame.Color('green'), (px, py), 3)
        if len(self.endpoint) == 2:
            pygame.draw.line(run.screen, pygame.Color('white'), run.lamp, self.endpoint)


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 = [round(self.winw/2), round(self.winh/2)]
        self.lampr = 13
        self.lines = []
        self.r = 5
        self.Obs = []
        self.angel = 0
        self.fov = 360
        self.scene = np.ones(self.fov)
        self.done = False
        self.makeobs()

    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__()
                elif event.key == pygame.K_LEFT:
                    if self.angel <= 0:
                        self.angel = 360
                    else:
                        self.angel -= 5
                elif event.key == pygame.K_RIGHT:
                    if self.angel >= 360:
                        self.angel = 0
                    else:
                        self.angel += 5
                elif event.key == pygame.K_w:
                    self.lamp[1] -= 10
                elif event.key == pygame.K_a:
                    self.lamp[0] -= 10
                elif event.key == pygame.K_s:
                    self.lamp[1] += 10
                elif event.key == pygame.K_d:
                    self.lamp[0] += 10
                elif event.key == pygame.K_y:
                    pass

        if pygame.mouse.get_pressed() == (1, 0, 0):
            if pygame.mouse.get_pos()[0] > 800:
                self.lamp = [799, pygame.mouse.get_pos()[1]]
            else:
                self.lamp[0] = pygame.mouse.get_pos()[0]
                self.lamp[1] = pygame.mouse.get_pos()[1]

    def draw(self):
        self.screen.fill((pygame.Color('black')))
        pygame.draw.circle(self.screen, pygame.Color('white'), self.lamp, self.lampr)
        for obs in self.Obs:
            obs.drawww()
        for line in self.lines:
            line.draw()

    def makeobs(self):
        for i in range(2):
            self.Obs.append(Obs((rd.randint(0, self.winw), rd.randint(0, self.winh)),
                                (rd.randint(0, self.winw), rd.randint(0, self.winh))))
        # self.Obs.append(Obs((0, 0), (self.winw, 0)))
        # self.Obs.append(Obs((0, 0), (0, self.winh)))
        # self.Obs.append(Obs((self.winw, 0), (self.winw, self.winh)))
        # self.Obs.append(Obs((0, self.winh), (self.winw, self.winh)))

    def createlines(self):
        self.lines.clear()
        for angle in range(self.angel, self.angel+self.fov):
            angle = math.radians(angle)
            self.lines.append(rays([self.lamp[0] + math.cos(angle), self.lamp[1] + 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()

希望无论灯在哪里都能正常工作。

【问题讨论】:

    标签: python pygame line raycasting


    【解决方案1】:

    代码

    px = round(x1 + t * (x2 - x1))
    py = round(y1 + t * (y2 - y1))
    dist = px**2+py**2
    

    没有任何意义,因为(py, py) 是一个点,所以dist = px**2+py**2 是从原点(0, 0)(py, py) 的平方Euclidean distance

    你需要计算(x3, x4)到交点的距离:

    vx = u * (x4 - x3)
    vy = u * (y4 - y3)
    dist = vx**2+vy**2
    

    另外在u的计算中还有一个问题:

    u = ((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / d
    u = ((x1 - x3) * (y1 - y2) - (y1 - y3) * (x1 - x2)) / d

    方法类rays

    class rays(object):
        def __init__(self, maxendpoint):
            self.maxendpoint = maxendpoint
            self.endpoint = []
    
        def draw(self):
            bestdist = 1000000000000000000
            for obs in run.Obs:
                x1, y1 = obs.startp
                x2, y2 = obs.endp
                x3, y3 = run.lamp
                x4, y4 = self.maxendpoint
    
                d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)
                if d != 0:
                    t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / d
                    u = ((x1 - x3) * (y1 - y2) - (y1 - y3) * (x1 - x2)) / d
                    if 0 < t < 1 and u > 0:
                        vx = u * (x4 - x3)
                        vy = u * (y4 - y3)
                        dist = vx**2+vy**2
                        if dist < bestdist:
                            px = round(x3 + u * (x4 - x3))
                            py = round(y3 + u * (y4 - y3))
                            bestdist = dist
                            self.endpoint= [px, py]
                        # pygame.draw.circle(run.screen, pygame.Color('green'), (px, py), 3)
            if len(self.endpoint) == 2:
                pygame.draw.line(run.screen, pygame.Color('white'), run.lamp, self.endpoint)
    

    最小示例: repl.it/@Rabbid76/PyGame-IntersectAndCutLines

    import pygame
    import math
    import random
    
    def intersect(obstacles, P0, P1):
        bestdist = 1000000000000000000
        endpoint = P1
        for Q0, Q1 in obstacles:
            d = (P1[0]-P0[0]) * (Q1[1]-Q0[1]) + (P1[1]-P0[1]) * (Q0[0]-Q1[0]) 
            if d != 0:
                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:
                    vx, vy = (P1[0]-P0[0]) * t, (P1[1]-P0[1]) * t
                    dist = vx*vx + vy*vy
                    if dist < bestdist:
                        px, py = round(Q1[0] * u + Q0[0] * (1-u)), round(Q1[1] * u + Q0[1] * (1-u))
                        bestdist = dist
                        endpoint = (px, py)
        return endpoint
    
    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:
            endpoint = intersect(obstacles, origin, endpoint)
            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)
        pygame.display.flip()
    
    pygame.quit()
    exit()
    

    【讨论】:

      猜你喜欢
      • 2013-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-09
      • 2018-11-18
      • 2011-05-09
      • 2011-03-01
      • 1970-01-01
      相关资源
      最近更新 更多