def rasterize_space_with_obstacles(
    scene,
    a: Union[str, list[str]],
    b: Union[str, list[str]],
    start_location,
    end_location,
    cell_size=1.0,
    visualize=False,
):
    """
    Rasterize the union of multiple space polygons while considering obstacle polygons,
    then find and visualize the shortest path from start to end.

    Parameters:
    - space_polygons: list of shapely.geometry.polygon.Polygon objects representing the main spaces
    - obstacle_polygons: list of shapely.geometry.polygon.Polygon objects representing obstacles
    - start_location: tuple (x, y) representing the start location
    - end_location: tuple (x, y) representing the end location
    - cell_size: size of each cell in the grid
    - visualize: boolean, if True, visualize the union of spaces, obstacles, and the shortest path

    Returns:
    - graph: A networkx.Graph object representing the rasterized union of spaces minus the obstacles
    - path: list of nodes representing the shortest path from start to end
    """

    def is_close_to_any_node(neighbor, graph, threshold=1e-6):
        for node in graph.nodes():
            distance = np.linalg.norm(np.array(neighbor) - np.array(node))
            if distance < threshold:
                return node
        return None

    if isinstance(a, str):
        a = [a]
    if isinstance(b, str):
        b = [b]

    a_meshes = iu.meshes_from_names(scene, a)
    b_meshes = iu.meshes_from_names(scene, b)

    space_polygons = [iu.project_to_xy_poly(mesh) for mesh in a_meshes]
    obstacle_polygons = [iu.project_to_xy_poly(mesh) for mesh in b_meshes]

    # Get the union of all space polygons
    union_space = unary_union(space_polygons)

    # Get bounding box of the union space
    minx, miny, maxx, maxy = union_space.bounds

    # Create a grid over the bounding box
    x_coords = np.arange(minx, maxx, cell_size)
    y_coords = np.arange(miny, maxy, cell_size)

    graph = nx.Graph()

    # For visualization
    if visualize:
        fig, ax = plt.subplots()
        for space in space_polygons:
            if isinstance(space, Polygon):
                x, y = space.exterior.xy
                ax.fill(x, y, alpha=0.5)  # Fill the space
                ax.plot(x, y, color="black")  # Plot the space boundary
            elif isinstance(space, MultiPolygon):
                for sub_space in space.geoms:
                    x, y = sub_space.exterior.xy
                    ax.fill(x, y, alpha=0.5)
                    ax.plot(x, y, color="black")

        for obstacle in obstacle_polygons:
            if isinstance(obstacle, Polygon):
                x, y = obstacle.exterior.xy
                ax.fill(x, y, color="grey")  # Fill the obstacles
                ax.plot(x, y, color="black")  # Plot the obstacle boundary
            elif isinstance(obstacle, MultiPolygon):
                for sub_obstacle in obstacle.geoms:
                    x, y = sub_obstacle.exterior.xy
                    ax.fill(x, y, color="grey")
                    ax.plot(x, y, color="black")

    # For each cell in the grid, check if its center is inside the union space and outside all obstacle polygons
    for x in x_coords:
        for y in y_coords:
            cell_center = Point(x + cell_size / 2, y + cell_size / 2)
            if cell_center.within(union_space) and all(
                not cell_center.within(obstacle) for obstacle in obstacle_polygons
            ):
                graph.add_node((x + cell_size / 2, y + cell_size / 2))

                # For visualization
                if visualize:
                    ax.plot(
                        cell_center.x, cell_center.y, "bo", markersize=3
                    )  # Plot the point inside the union space and outside obstacles

    # Connect each node to its neighboring nodes
    for node in graph.nodes():
        x, y = node
        neighbors = [
            (x + cell_size, y),
            (x - cell_size, y),
            (x, y + cell_size),
            (x, y - cell_size),
        ]
        for neighbor in neighbors:
            closest_node = is_close_to_any_node(neighbor, graph)
            if closest_node is not None:
                graph.add_edge(node, closest_node)

    # Find the closest nodes to the start and end locations
    start_node = min(
        graph.nodes(),
        key=lambda node: np.linalg.norm(np.array(node) - np.array(start_location)),
    )
    end_node = min(
        graph.nodes(),
        key=lambda node: np.linalg.norm(np.array(node) - np.array(end_location)),
    )

    # Calculate the shortest path using Dijkstra's algorithm
    path = nx.shortest_path(graph, source=start_node, target=end_node, weight="weight")

    # Visualize the path
    if visualize:
        path_x = [x for x, y in path]
        path_y = [y for x, y in path]
        ax.plot(path_x, path_y, c="red", linewidth=2, label="Shortest Path")
        ax.scatter(
            [start_node[0], end_node[0]],
            [start_node[1], end_node[1]],
            c="green",
            s=100,
            label="Start & End",
        )
        plt.legend()
        plt.title("Shortest Path from Start to End")
        plt.show()

    return graph, path

    Rasterize the union of multiple space polygons while considering obstacle polygons,
    then find and visualize the shortest path from start to end.

    Parameters:
    - space_polygons: list of shapely.geometry.polygon.Polygon objects representing the main spaces
    - obstacle_polygons: list of shapely.geometry.polygon.Polygon objects representing obstacles
    - start_location: tuple (x, y) representing the start location
    - end_location: tuple (x, y) representing the end location
    - cell_size: size of each cell in the grid
    - visualize: boolean, if True, visualize the union of spaces, obstacles, and the shortest path

    Returns:
    - graph: A networkx.Graph object representing the rasterized union of spaces minus the obstacles
    - path: list of nodes representing the shortest path from start to end
    
infinigen/core/constraints/evaluator/node_impl/trimesh_geometry.py