import numpy as np
import matplotlib.pyplot as plt
from shapely.geometry import Polygon, Point
from itertools import groupby
import datetime

INF_TIME = 100000000000


class Grid:
    def __init__(self, width, height, obstacles=None):
        self.grid = None
        self.width = width
        self.height = height
        self.obstacles = obstacles
        self.create_grid()

    def create_grid(self):
        self.grid = np.zeros((self.height, self.width), dtype=np.int8)
        for obstacle in self.obstacles:
            polygon = Polygon(obstacle)
            x, y = np.meshgrid(np.arange(self.width), np.arange(self.height))
            points = np.vstack((x.flatten(), y.flatten())).T
            points_inside = np.array([polygon.contains(Point(point)) or polygon.boundary.contains(Point(point)) for point in points])
            self.grid[points_inside.reshape(self.height, self.width)] = 1
        return

    def has_obstacles(self):
        return self.obstacles is not None

    def plot(self):
        plt.imshow(self.grid, cmap='gray')
        plt.show()


class GridGenerator:
    def __init__(self, objects, width, height):
        self.objects = objects
        self.width = width
        self.height = height
        self.grids = []
        self.generate_grids()

    def is_inside(self, x, y):
        return 0 <= x < self.width and 0 <= y < self.height and all(g[2].grid[y, x] != 1 for g in self.grids)

    def get_grid_at_time(self, time):
        for start_time, end_time, grid in self.grids:
            if start_time <= time <= end_time:
                return grid
        raise ValueError(f"No grid found for time {time}")

    def generate_grids(self):
        st = datetime.datetime.now()
        values = sorted(list(set([tup[0] for tup in self.objects] + [tup[1] for tup in self.objects])))

        if len(values) == 0 or values[0] > 0:
            values.insert(0, 0)

        if values[-1] < INF_TIME:
            values.append(INF_TIME)

        pairs = list(zip(values[:-1], values[1:]))

        grids = []
        objects_sorted = sorted(self.objects, key=lambda obj: obj[0])  # Sort objects by start time
        current_objects = []
        j = 0  # Index of current time range
        for i in range(len(pairs)):
            start_time, end_time = pairs[i]
            polygons = []

            # Add new objects to current_objects as long as their start time is within the current time range
            while j < len(objects_sorted) and objects_sorted[j][0] < end_time:
                if objects_sorted[j][1] > start_time:
                    current_objects.append(objects_sorted[j])
                j += 1

            # Iterate through current_objects and add their polygons to the list for this time range
            for obj in current_objects:
                if obj[1] > start_time:
                    polygons.append(obj[2])

            grids.append((start_time, end_time, polygons))

        return_grids = []
        for grid in grids:
            g = Grid(self.width, self.height, grid[2])
            return_grids.append((grid[0], grid[1], g))

        self.grids = return_grids
        print(f"Grid generation time: {datetime.datetime.now() - st}")


Write the function generate_grids more correctly and efficiently.
Try to improve and optimize the running times, it takes a lot of time!