예제 #1
0
    def update(self, update_ctx):
        """Move and turn if min_x or max_x reached. Check for collision."""
        start_pos = self.pos
        super().update(update_ctx)
        if self.pos.x > self.max_x:
            self.facing = Direction.LEFT
            self.set_x(self.max_x - (self.pos.x - self.max_x))
            self.velocity = Vec(-self.speed, 0)
        elif self.pos.x < self.min_x:
            self.facing = Direction.RIGHT
            self.set_x(self.min_x + (self.min_x - self.pos.x))
            self.velocity = Vec(self.speed, 0)

        wall_entities = [
            entity for entity in update_ctx.world.entities
            if entity.blocks_movement and self.is_touching(entity)
        ]
        wall_players = [
            player for player in update_ctx.game.get_players_by_world(
                update_ctx.world.get_world_id()) if self.is_touching(player)
        ]
        walls = wall_entities + wall_players
        if walls:
            walls.sort(key=lambda wall: wall.pos.dist_to(self.pos))
            for wall in walls:
                block_movement(wall.get_bounding_box(), start_pos, self)
예제 #2
0
 async def on_interact(self, event_ctx):
     """Send dialogue when player interacts with Walker."""
     self.velocity = Vec(0, 0)
     if event_ctx.username in self.conv_progress:
         self.conv_progress[event_ctx.username] += 1
         try:
             await Util.send_dialogue(
                 event_ctx.ws, self.uuid,
                 self.dialogue[self.conv_progress[event_ctx.username]])
             event_ctx.player.talking_to = self
         except IndexError:
             del self.conv_progress[event_ctx.username]
             await Util.send_dialogue_end(event_ctx.ws, self.uuid)
             event_ctx.player.talking_to = None
             if not self.conv_progress:
                 if self.facing is Direction.LEFT:
                     self.velocity = Vec(-self.speed, 0)
                 elif self.facing is Direction.RIGHT:
                     self.velocity = Vec(self.speed, 0)
     else:
         self.conv_progress[event_ctx.username] = 0
         await Util.send_dialogue(
             event_ctx.ws, self.uuid,
             self.dialogue[self.conv_progress[event_ctx.username]])
         event_ctx.player.talking_to = self
예제 #3
0
    def test_vec_point_multiplication(self):
        m = Transformation(
            m=[
                [1.0, 2.0, 3.0, 4.0],
                [5.0, 6.0, 7.0, 8.0],
                [9.0, 9.0, 8.0, 7.0],
                [0.0, 0.0, 0.0, 1.0],
            ],
            invm=[
                [-3.75, 2.75, -1, 0],
                [5.75, -4.75, 2.0, 1.0],
                [-2.25, 2.25, -1.0, -2.0],
                [0.0, 0.0, 0.0, 1.0],
            ],
        )
        assert m.is_consistent()

        expected_v = Vec(14.0, 38.0, 51.0)
        assert expected_v.is_close(m * Vec(1.0, 2.0, 3.0))

        expected_p = Point(18.0, 46.0, 58.0)
        assert expected_p.is_close(m * Point(1.0, 2.0, 3.0))

        expected_n = Normal(-8.75, 7.75, -3.0)
        assert expected_n.is_close(m * Normal(3.0, 2.0, 4.0))
예제 #4
0
	def get_path_areas_mode(self, p_depart, p_arrive, area_depart=None):
		p_depart = Vec(p_depart)
		p_arrive = Vec(p_arrive)
		area_depart = self.find_area_for_point(p_depart) if not area_depart else area_depart
		area_arrive = self.find_area_for_point(p_arrive)
		
		# le point d'arrivé est inateignable
		if not area_arrive:
			return [],[],[]
			
		# aucune aire n'a été trouvée pour le point de départ, on va prendre la plus proche
		if not area_depart:
			area_depart = min(self.areas.values(), key=lambda a: (a.middle - p_depart).norm2())

		#application du pathfinding
		areas, raw_path = self.pathfinding_area.compute_path(area_depart, area_arrive)

		# smooth path
		if len(areas) > 1:
			portal_edges = polys_to_portal_edges(areas)
			smooth_path = funnel(p_depart, p_arrive, portal_edges)
		else:
			raw_path = [p_depart, p_arrive]
			smooth_path = [p_depart, p_arrive]
		return areas,raw_path,smooth_path
예제 #5
0
    def test_is_close(self):
        ray1 = Ray(origin=Point(1.0, 2.0, 3.0), dir=Vec(5.0, 4.0, -1.0))
        ray2 = Ray(origin=Point(1.0, 2.0, 3.0), dir=Vec(5.0, 4.0, -1.0))
        ray3 = Ray(origin=Point(5.0, 1.0, 4.0), dir=Vec(3.0, 9.0, 4.0))

        assert ray1.is_close(ray2)
        assert not ray1.is_close(ray3)
예제 #6
0
    def testFlatRenderer(self):
        sphere_color = Color(1.0, 2.0, 3.0)
        sphere = Sphere(transformation=translation(Vec(2, 0, 0)) *
                        scaling(Vec(0.2, 0.2, 0.2)),
                        material=Material(brdf=DiffuseBRDF(
                            pigment=UniformPigment(sphere_color))))
        image = HdrImage(width=3, height=3)
        camera = OrthogonalCamera()
        tracer = ImageTracer(image=image, camera=camera)
        world = World()
        world.add_shape(sphere)
        renderer = FlatRenderer(world=world)
        tracer.fire_all_rays(renderer)

        assert image.get_pixel(0, 0).is_close(BLACK)
        assert image.get_pixel(1, 0).is_close(BLACK)
        assert image.get_pixel(2, 0).is_close(BLACK)

        assert image.get_pixel(0, 1).is_close(BLACK)
        assert image.get_pixel(1, 1).is_close(sphere_color)
        assert image.get_pixel(2, 1).is_close(BLACK)

        assert image.get_pixel(0, 2).is_close(BLACK)
        assert image.get_pixel(1, 2).is_close(BLACK)
        assert image.get_pixel(2, 2).is_close(BLACK)
예제 #7
0
def block_movement(bbox, entity_start_pos, entity):
    """Reposition entity when the entity hits a wall.

    Args:
        bbox: The BoundingBox of the wall.
        entity_start_pos: The position of the entity before the entity
            moved and hit the wall.
        entity: The entity object.
    """
    entity_end_pos = entity.pos
    entity.pos = entity_start_pos
    if entity.get_bounding_box().is_touching(bbox):
        entity.pos = entity_end_pos
    else:
        dp = entity_end_pos - entity_start_pos
        dx = dp.x
        dy = dp.y
        entity_width = entity.get_width()
        entity_height = entity.get_height()

        entity.move(Vec(dx, 0))
        if entity.get_bounding_box().is_touching(bbox):
            if dx > 0:
                entity.set_x(bbox.get_left_b() - entity_width - 1)
            elif dx < 0:
                entity.set_x(bbox.get_right_b() + 1)

        entity.move(Vec(0, dy))
        if entity.get_bounding_box().is_touching(bbox):
            if dy > 0:
                entity.set_y(bbox.get_top_b() - entity_height - 1)
            elif dy < 0:
                entity.set_y(bbox.get_bottom_b() + 1)
예제 #8
0
 def test_point_operations(self):
     p1 = Point(1.0, 2.0, 3.0)
     v = Vec(4.0, 6.0, 8.0)
     p2 = Point(4.0, 6.0, 8.0)
     assert (p1 * 2).is_close(Point(2.0, 4.0, 6.0))
     assert (p1 + v).is_close(Point(5.0, 8.0, 11.0))
     assert (p2 - p1).is_close(Vec(3.0, 4.0, 5.0))
     assert (p1 - v).is_close(Point(-3.0, -4.0, -5.0))
예제 #9
0
    def testNormals(self):
        sphere = Sphere(transformation=scaling(Vec(2.0, 1.0, 1.0)))

        ray = Ray(origin=Point(1.0, 1.0, 0.0), dir=Vec(-1.0, -1.0))
        intersection = sphere.ray_intersection(ray)
        # We normalize "intersection.normal", as we are not interested in its length
        assert intersection.normal.normalize().is_close(
            Normal(1.0, 4.0, 0.0).normalize())
예제 #10
0
    def test_scalings(self):
        tr1 = scaling(Vec(2.0, 5.0, 10.0))
        assert tr1.is_consistent()

        tr2 = scaling(Vec(3.0, 2.0, 4.0))
        assert tr2.is_consistent()

        expected = scaling(Vec(6.0, 10.0, 40.0))
        assert expected.is_close(tr1 * tr2)
예제 #11
0
class VecNormTestCase(unittest.TestCase):
	def setUp(self):
		self.v = Vec((5,5))

	def test_norm2(self):
		self.assertEqual(self.v.norm2(), 50)

	def test_norm(self):
		self.assertEqual(round(self.v.norm()), 7)
예제 #12
0
 def from_json(entity_dict):
     """Convert a dict representing a JSON object into an entity."""
     entity_class = Entity.get_entity_by_id(entity_dict["entity_id"])
     entity_pos = Vec(entity_dict["pos"]["x"], entity_dict["pos"]["y"])
     entity_velocity = Vec(entity_dict["velocity"]["x"],
                           entity_dict["velocity"]["y"])
     entity_facing = Direction.str_to_direction(entity_dict["facing"])
     ent = entity_class(entity_pos, entity_velocity, entity_facing)
     ent.uuid = uuid.UUID(entity_dict["uuid"])
     return ent
예제 #13
0
    def test_translations(self):
        tr1 = translation(Vec(1.0, 2.0, 3.0))
        assert tr1.is_consistent()

        tr2 = translation(Vec(4.0, 6.0, 8.0))
        assert tr1.is_consistent()

        prod = tr1 * tr2
        assert prod.is_consistent()

        expected = translation(Vec(5.0, 8.0, 11.0))
        assert prod.is_close(expected)
예제 #14
0
    def testFurnace(self):
        pcg = PCG()

        # Run the furnace test several times using random values for the emitted radiance and reflectance
        for i in range(5):
            world = World()

            emitted_radiance = pcg.random_float()
            reflectance = pcg.random_float(
            ) * 0.9  # Be sure to pick a reflectance that's not too close to 1
            enclosure_material = Material(
                brdf=DiffuseBRDF(
                    pigment=UniformPigment(Color(1.0, 1.0, 1.0) *
                                           reflectance)),
                emitted_radiance=UniformPigment(
                    Color(1.0, 1.0, 1.0) * emitted_radiance),
            )

            world.add_shape(Sphere(material=enclosure_material))

            path_tracer = PathTracer(pcg=pcg,
                                     num_of_rays=1,
                                     world=world,
                                     max_depth=100,
                                     russian_roulette_limit=101)

            ray = Ray(origin=Point(0, 0, 0), dir=Vec(1, 0, 0))
            color = path_tracer(ray)

            expected = emitted_radiance / (1.0 - reflectance)
            assert pytest.approx(expected, 1e-3) == color.r
            assert pytest.approx(expected, 1e-3) == color.g
            assert pytest.approx(expected, 1e-3) == color.b
예제 #15
0
async def run(ws, path):
    """Run the WebSocket server."""
    del path  # Unused
    username = await ws.recv()
    try:
        player = running_game.get_player(username)
        print("Returning user: "******"New user: "******"starting_world"
        spawn_id = "center_spawn"
        world = World.get_world_by_id(world_id)
        spawn_pos = world.spawn_points[spawn_id].to_spawn_pos()
        player = Player(username, spawn_pos, Vec(0, 0), Direction.DOWN, ws,
                        world_id)
        running_game.add_player(player)
        await Util.send_world(ws, world, spawn_pos)
    try:
        async for message in ws:
            await parseMessage(message, username, ws)
    except ConnectionClosed:
        player.online = False
예제 #16
0
    def testTransformation(self):
        sphere = Sphere(transformation=translation(Vec(10.0, 0.0, 0.0)))

        ray1 = Ray(origin=Point(10, 0, 2), dir=-VEC_Z)
        intersection1 = sphere.ray_intersection(ray1)
        assert intersection1
        assert HitRecord(
            world_point=Point(10.0, 0.0, 1.0),
            normal=Normal(0.0, 0.0, 1.0),
            surface_point=Vec2d(0.0, 0.0),
            t=1.0,
            ray=ray1,
            material=sphere.material,
        ).is_close(intersection1)

        ray2 = Ray(origin=Point(13, 0, 0), dir=-VEC_X)
        intersection2 = sphere.ray_intersection(ray2)
        assert intersection2
        assert HitRecord(
            world_point=Point(11.0, 0.0, 0.0),
            normal=Normal(1.0, 0.0, 0.0),
            surface_point=Vec2d(0.0, 0.5),
            t=2.0,
            ray=ray2,
            material=sphere.material,
        ).is_close(intersection2)

        # Check if the sphere failed to move by trying to hit the untransformed shape
        assert not sphere.ray_intersection(
            Ray(origin=Point(0, 0, 2), dir=-VEC_Z))

        # Check if the *inverse* transformation was wrongly applied
        assert not sphere.ray_intersection(
            Ray(origin=Point(-10, 0, 0), dir=-VEC_Z))
예제 #17
0
 def respawn(self):
     """Reset player's location and other properties."""
     world_id = "starting_world"
     spawn_id = "center_spawn"
     world = World.get_world_by_id(world_id)
     spawn_pos = world.spawn_points[spawn_id].to_spawn_pos()
     Player.__init__(self, self.username, spawn_pos, Vec(0, 0),
                     Direction.DOWN, self.ws, world_id)
예제 #18
0
    def testNormalDirection(self):
        # Scaling a sphere by -1 keeps the sphere the same but reverses its
        # reference frame
        sphere = Sphere(transformation=scaling(Vec(-1.0, -1.0, -1.0)))

        ray = Ray(origin=Point(0.0, 2.0, 0.0), dir=-VEC_Y)
        intersection = sphere.ray_intersection(ray)
        # We normalize "intersection.normal", as we are not interested in its length
        assert intersection.normal.normalize().is_close(
            Normal(0.0, 1.0, 0.0).normalize())
예제 #19
0
def demo(width, height, angle_deg, orthogonal, pfm_output, png_output):
    image = HdrImage(width, height)

    # Create a world and populate it with a few shapes
    world = World()

    for x in [-0.5, 0.5]:
        for y in [-0.5, 0.5]:
            for z in [-0.5, 0.5]:
                world.add(
                    Sphere(transformation=translation(Vec(x, y, z)) *
                           scaling(Vec(0.1, 0.1, 0.1))))

    # Place two other balls in the bottom/left part of the cube, so
    # that we can check if there are issues with the orientation of
    # the image
    world.add(
        Sphere(transformation=translation(Vec(0.0, 0.0, -0.5)) *
               scaling(Vec(0.1, 0.1, 0.1))))
    world.add(
        Sphere(transformation=translation(Vec(0.0, 0.5, 0.0)) *
               scaling(Vec(0.1, 0.1, 0.1))))

    # Initialize a camera
    camera_tr = rotation_z(angle_deg=angle_deg) * translation(
        Vec(-1.0, 0.0, 0.0))
    if orthogonal:
        camera = OrthogonalCamera(aspect_ratio=width / height,
                                  transformation=camera_tr)
    else:
        camera = PerspectiveCamera(aspect_ratio=width / height,
                                   transformation=camera_tr)

    # Run the ray-tracer

    tracer = ImageTracer(image=image, camera=camera)

    def compute_color(ray: Ray) -> Color:
        if world.ray_intersection(ray):
            return WHITE
        else:
            return BLACK

    tracer.fire_all_rays(compute_color)

    # Save the HDR image
    with open(pfm_output, "wb") as outf:
        image.write_pfm(outf)
    print(f"HDR demo image written to {pfm_output}")

    # Apply tone-mapping to the image
    image.normalize_image(factor=1.0)
    image.clamp_image()

    # Save the LDR image
    with open(png_output, "wb") as outf:
        image.write_ldr_image(outf, "PNG")
    print(f"PNG demo image written to {png_output}")
예제 #20
0
def parse_vector(input_file: InputStream, scene: Scene) -> Vec:
    expect_symbol(input_file, "[")
    x = expect_number(input_file, scene)
    expect_symbol(input_file, ",")
    y = expect_number(input_file, scene)
    expect_symbol(input_file, ",")
    z = expect_number(input_file, scene)
    expect_symbol(input_file, "]")

    return Vec(x, y, z)
예제 #21
0
    def testOnbFromNormal(self):
        pcg = PCG()

        expected_zero = pytest.approx(0.0)
        expected_one = pytest.approx(1.0)

        for i in range(100):
            normal = Vec(pcg.random_float(), pcg.random_float(),
                         pcg.random_float())
            normal.normalize()
            e1, e2, e3 = create_onb_from_z(normal)

            assert e3.is_close(normal)

            assert expected_one == e1.squared_norm()
            assert expected_one == e2.squared_norm()
            assert expected_one == e3.squared_norm()

            assert expected_zero == e1.dot(e2)
            assert expected_zero == e2.dot(e3)
            assert expected_zero == e3.dot(e1)
    def set_points(self, points):
        if len(points) < 2:
            raise InvalidStreetException("Street must have atleast 2 points")

        self.points = []
        for (x, y) in points:
            self.points.append(Vec(x, y))

        self.segments = []
        for i in range(len(self.points) - 1):
            a = self.points[i]
            b = self.points[i + 1]
            self.segments.append(Segment(a, b))
예제 #23
0
    def scatter_ray(self, pcg: PCG, incoming_dir: Vec,
                    interaction_point: Point, normal: Normal, depth: int):
        # There is no need to use the PCG here, as the reflected direction is always completely deterministic
        # for a perfect mirror

        ray_dir = Vec(incoming_dir.x, incoming_dir.y,
                      incoming_dir.z).normalize()
        normal = normal.to_vec().normalize()
        dot_prod = normal.dot(ray_dir)

        return Ray(
            origin=interaction_point,
            dir=ray_dir - normal * 2 * dot_prod,
            tmin=1e-5,
            tmax=inf,
            depth=depth,
        )
예제 #24
0
    def __init__(self, pos, velocity, facing):
        """Initialize the Stander with certain default properties.

        Set velocity to 0.
        Set dialogue.
        """
        super().__init__(pos, velocity, facing)
        self.velocity = Vec(0, 0)
        self.dialogue = [
            "Don't get so close, scum! Do you know who my father is?",
            ["Yes", "No"],
            {
                0: "That makes one of us...",
                1: "Me neither..."
            },
        ]
        self.conv_progress = {}
예제 #25
0
    def __init__(self, pos, velocity, facing):
        """Initialize the Walker with certain default properties.

        Set velocity rightward with the norm of the given velocity.
        Set dialogue.
        Set min_x and max_x to three blocks left and three blocks to the right.
        """
        super().__init__(pos, velocity, facing)
        self.speed = velocity.norm()
        self.velocity = Vec(self.speed, 0)
        self.min_x = pos.x - BLOCK_WIDTH * 3
        self.max_x = pos.x + BLOCK_WIDTH * 3
        self.dialogue = [
            "Hi!",
            "This is dialogue.",
            f"And this is {'really '*42}long dialogue.",
        ]
        self.conv_progress = {}
예제 #26
0
    def fire_ray(self, u, v):
        """Shoot a ray through the camera's screen

        The coordinates (u, v) specify the point on the screen where the ray crosses it. Coordinates (0, 0) represent
        the bottom-left corner, (0, 1) the top-left corner, (1, 0) the bottom-right corner, and (1, 1) the top-right
        corner, as in the following diagram::

            (0, 1)                          (1, 1)
               +------------------------------+
               |                              |
               |                              |
               |                              |
               +------------------------------+
            (0, 0)                          (1, 0)
        """
        origin = Point(-self.screen_distance, 0.0, 0.0)
        direction = Vec(self.screen_distance,
                        (1.0 - 2 * u) * self.aspect_ratio, 2 * v - 1)
        return Ray(origin=origin, dir=direction,
                   tmin=1.0).transform(self.transformation)
예제 #27
0
class Ray:
    """A ray of light propagating in space

    The class contains the following members:

    -   `origin` (``Point``): the 3D point where the ray originated
    -   `dir` (``Vec``): the 3D direction along which this ray propagates
    -   `tmin` (float): the minimum distance travelled by the ray is this number times `dir`
    -   `tmax` (float): the maximum distance travelled by the ray is this number times `dir`
    -   `depth` (int): number of times this ray was reflected/refracted"""

    origin: Point = Point()
    dir: Vec = Vec()
    tmin: float = 1e-5
    tmax: float = inf
    depth: int = 0

    def is_close(self, other: Ray, epsilon=1e-5):
        """Check if two rays are similar enough to be considered equal"""
        return (self.origin.is_close(other.origin, epsilon=epsilon)
                and self.dir.is_close(other.dir, epsilon=epsilon))

    def at(self, t):
        """Compute the point along the ray's path at some distance from the origin

        Return a ``Point`` object representing the point in 3D space whose distance from the
        ray's origin is equal to `t`, measured in units of the length of `Vec.dir`."""
        return self.origin + self.dir * t

    def transform(self, transformation: Transformation):
        """Transform a ray

        This method returns a new ray whose origin and direction are the transformation of the original ray"""
        return Ray(origin=transformation * self.origin,
                   dir=transformation * self.dir,
                   tmin=self.tmin,
                   tmax=self.tmax,
                   depth=self.depth)
예제 #28
0
    def __mul__(self, other):
        if isinstance(other, Vec):
            row0, row1, row2, row3 = self.m
            return Vec(
                x=other.x * row0[0] + other.y * row0[1] + other.z * row0[2],
                y=other.x * row1[0] + other.y * row1[1] + other.z * row1[2],
                z=other.x * row2[0] + other.y * row2[1] + other.z * row2[2])
        elif isinstance(other, Point):
            row0, row1, row2, row3 = self.m
            p = Point(x=other.x * row0[0] + other.y * row0[1] +
                      other.z * row0[2] + row0[3],
                      y=other.x * row1[0] + other.y * row1[1] +
                      other.z * row1[2] + row1[3],
                      z=other.x * row2[0] + other.y * row2[1] +
                      other.z * row2[2] + row2[3])
            w = other.x * row3[0] + other.y * row3[1] + other.z * row3[
                2] + row3[3]

            if w == 1.0:
                return p
            else:
                return Point(p.x / w, p.y / w, p.z / w)
        elif isinstance(other, Normal):
            row0, row1, row2, _ = self.invm
            return Normal(
                x=other.x * row0[0] + other.y * row1[0] + other.z * row2[0],
                y=other.x * row0[1] + other.y * row1[1] + other.z * row2[1],
                z=other.x * row0[2] + other.y * row1[2] + other.z * row2[2])
        elif isinstance(other, Transformation):
            result_m = _matr_prod(self.m, other.m)
            result_invm = _matr_prod(
                other.invm, self.invm)  # Reverse order! (A B)^-1 = B^-1 A^-1
            return Transformation(m=result_m, invm=result_invm)
        else:
            raise TypeError(
                f"Invalid type {type(other)} multiplied to a Transformation object"
            )
예제 #29
0
 def to_pos(self):
     """Get the position of the upper-left corner of the tile."""
     return Vec(self.block_x * BLOCK_WIDTH, self.block_y * BLOCK_WIDTH)
예제 #30
0
 def to_spawn_pos(self):
     """Get the position in the tile in which the player spawns."""
     return Vec(
         self.block_x * BLOCK_WIDTH + (BLOCK_WIDTH - PLAYER_WIDTH) / 2,
         self.block_y * BLOCK_WIDTH + (BLOCK_WIDTH - PLAYER_WIDTH) / 2)
예제 #31
0

import
	>>> from geometry import Vec

init
	>>> v = Vec([1,2,3])
	>>> v = Vec((1,2,3))
	>>> v = Vec(range(4))

operators
	>>> v1 = Vec([1,2,3])
	>>> v2 = Vec([4,5,6])

	>>> v1 != (1,2,3)
	False
	
	>>> v1 + v2 == [5,7,9]
	True
	>>> (4,5,6) + v1 == [5,7,9]
	True

	>>> v1 - v2 == [-3,-3,-3]
	True
	>>> [5,7,9] - v1 == (4,5,6)
	True

	>>> v1 += v2
	>>> v1 == [5,7,9]
	True
예제 #32
0
 def test_transform(self):
     ray = Ray(origin=Point(1.0, 2.0, 3.0), dir=Vec(6.0, 5.0, 4.0))
     transformation = translation(Vec(10.0, 11.0, 12.0)) * rotation_x(90.0)
     transformed = ray.transform(transformation)
     assert transformed.origin.is_close(Point(11.0, 8.0, 14.0))
     assert transformed.dir.is_close(Vec(6.0, -4.0, 5.0))
예제 #33
0
	def test_round(self):
		v = Vec([4.2,5.6,6.0])
		self.assertEqual(v.round(), (4,6,6))
예제 #34
0
	def setUp(self):
		self.v = Vec((5,5))
예제 #35
0
파일: navgraph.py 프로젝트: utcoupe/coupe14
	def get_path_vertex_mode(self, p_depart, p_arrive, enable_smooth=True):
		p_depart = Vec(p_depart)
		p_arrive = Vec(p_arrive)
		area_depart = self.find_area_for_point(p_depart)
		area_arrive = self.find_area_for_point(p_arrive)
		remove_arrive_at_end = True
		
		# le point d'arrivé est inateignable
		if not area_arrive:
			return [],[],[]
		
		# le point de départ est déjà dans les vertices (très peut probable)
		if p_depart in self.vertices:
			vertex_depart = self.vertices[p_depart]
		# sinon, on doit le rajouter 'à la main', puis le supprimer après le traitement
		else:
			vertex_depart = Node()
			vertex_depart.init(p_depart.__hash__(),p_depart, [])
			# si le point est dans une zone
			if area_depart:
				for p in area_depart.points:
					vertex_depart.neighbors.append(self.vertices[p])
			# sinon, il est dans une zone interdite, on va chercher le chemin le plus court pour sortir
			else:
				near_vertex = min(self.vertices.values(), key=lambda vertex: (p_depart - vertex.pos).norm2())
				vertex_depart.neighbors.append(self.vertices[near_vertex.pos])
		if p_arrive not in self.vertices:
			vertex_arrive = Node()
			vertex_arrive.init(p_arrive.__hash__(),p_arrive, [])
			for p in area_arrive.points:
				self.vertices[p].neighbors.append(vertex_arrive)
			remove_arrive_at_end = True

		# application du pathfinding
		vertices, raw_path = self.pathfinding_vertices.compute_path(vertex_depart, vertex_arrive)
		if not enable_smooth:
			return [], vertices, raw_path

		
		# remove des vertices ajoutées
		if remove_arrive_at_end:
			for p in area_arrive.points:
				self.vertices[p].neighbors.remove(vertex_arrive)

		# smooth path
		if len(vertices) > 2:
			smooth_path = raw_path
			id_areas = set()
			for vertex in vertices[1:-1]:
				for area in vertex.areas:
					id_areas.add(area.id)
			for area in self.areas.values():
				if area.id not in id_areas:
					area.walkable = False
			if not area_depart: # le départ est en zone interdite
				area_depart = min(vertices[1].areas, key=lambda a: (a.middle - p_arrive).norm2())
			_areas, _raw_path, smooth_path = self.get_path_areas_mode(p_depart, p_arrive, area_depart)
			for area in self.areas.values():
				area.walkable = True
		elif len(vertices) == 2:
			smooth_path = raw_path
		else:
			raw_path = []
			smooth_path = []
		return vertices, raw_path, smooth_path