def certain_timezone_at(self, *, lng: float, lat: float) -> Optional[str]:
        """checks in which timezone polygon the point is certainly included in

        .. note:: this is only meaningful when you use timezone data WITHOUT oceans!
            Otherwise some timezone will always be matched, since ocean timezones span the whole globe.
            -> useless to actually test all polygons.

        .. note:: this is much slower than 'timezone_at'!

        :param lng: longitude of the point in degree
        :param lat: latitude in degree
        :return: the timezone name of the polygon the point is included in or None
        """

        lng, lat = rectify_coordinates(lng, lat)
        shortcut_id_x, shortcut_id_y = coord2shortcut(lng, lat)
        timezone = self._get_unique_zone(shortcut_id_x, shortcut_id_y)
        if timezone is not None:  # found perfect and fast match
            return timezone
        possible_polygons = self.polygon_ids_of_shortcut(
            shortcut_id_x, shortcut_id_y)

        # x = longitude  y = latitude  both converted to 8byte int
        x = coord2int(lng)
        y = coord2int(lat)

        # check if the point is actually included in one of the polygons
        for polygon_nr in possible_polygons:

            # get boundaries
            getattr(self, POLY_MAX_VALUES).seek(4 * NR_BYTES_I * polygon_nr)
            boundaries = self._fromfile(
                getattr(self, POLY_MAX_VALUES),
                dtype=DTYPE_FORMAT_SIGNED_I_NUMPY,
                count=4,
            )
            if not (x > boundaries[0] or x < boundaries[1] or y > boundaries[2]
                    or y < boundaries[3]):

                outside_all_holes = True
                # when the point is within a hole of the polygon this timezone doesn't need to be checked
                for hole_coordinates in self._holes_of_poly(polygon_nr):
                    if inside_polygon(x, y, hole_coordinates):
                        outside_all_holes = False
                        break

                if outside_all_holes:
                    if inside_polygon(x, y,
                                      self.coords_of(polygon_nr=polygon_nr)):
                        return getattr(self,
                                       TIMEZONE_NAMES)[self.id_of(polygon_nr)]
        return None  # no polygon has been matched
    def certain_timezone_at(self, *, lng: float, lat: float) -> Optional[str]:
        """ looks up in which polygon the point certainly is included in

        .. note:: this is much slower than 'timezone_at'!

        :param lng: longitude of the point in degree
        :param lat: latitude in degree
        :return: the timezone name of the polygon the point is included in or None
        """

        lng, lat = rectify_coordinates(lng, lat)
        shortcut_id_x, shortcut_id_y = coord2shortcut(lng, lat)
        possible_polygons = self.polygon_ids_of_shortcut(
            shortcut_id_x, shortcut_id_y)

        # x = longitude  y = latitude  both converted to 8byte int
        x = coord2int(lng)
        y = coord2int(lat)

        # check if the point is actually included in one of the polygons
        for polygon_nr in possible_polygons:

            # get boundaries
            getattr(self, POLY_MAX_VALUES).seek(4 * NR_BYTES_I * polygon_nr)
            boundaries = self._fromfile(getattr(self, POLY_MAX_VALUES),
                                        dtype=DTYPE_FORMAT_SIGNED_I_NUMPY,
                                        count=4)
            if not (x > boundaries[0] or x < boundaries[1] or y > boundaries[2]
                    or y < boundaries[3]):

                outside_all_holes = True
                # when the point is within a hole of the polygon this timezone doesn't need to be checked
                for hole_coordinates in self._holes_of_poly(polygon_nr):
                    if inside_polygon(x, y, hole_coordinates):
                        outside_all_holes = False
                        break

                if outside_all_holes:
                    if inside_polygon(x, y,
                                      self.coords_of(polygon_nr=polygon_nr)):
                        return getattr(self,
                                       TIMEZONE_NAMES)[self.id_of(polygon_nr)]

        return None  # no polygon has been matched
Exemple #3
0
    def certain_timezone_at(self, *, lng, lat):
        """
        this function looks up in which polygon the point certainly is included
        this is much slower than 'timezone_at'!
        :param lng: longitude of the point in degree
        :param lat: latitude in degree
        :return: the timezone name of the polygon the point is included in or None
        """

        lng, lat = rectify_coordinates(lng, lat)
        shortcut_id_x, shortcut_id_y = coord2shortcut(lng, lat)
        possible_polygons = self.polygon_ids_of_shortcut(shortcut_id_x, shortcut_id_y)

        # x = longitude  y = latitude  both converted to 8byte int
        x = coord2int(lng)
        y = coord2int(lat)

        # check if the point is actually included in one of the polygons
        for polygon_nr in possible_polygons:

            # get boundaries
            self.poly_max_values.seek(4 * NR_BYTES_I * polygon_nr)
            boundaries = self.fromfile(self.poly_max_values, dtype=DTYPE_FORMAT_SIGNED_I_NUMPY, count=4)
            if not (x > boundaries[0] or x < boundaries[1] or y > boundaries[2] or y < boundaries[3]):

                outside_all_holes = True
                # when the point is within a hole of the polygon this timezone doesn't need to be checked
                for hole_coordinates in self._holes_of_line(polygon_nr):
                    if inside_polygon(x, y, hole_coordinates):
                        outside_all_holes = False
                        break

                if outside_all_holes:
                    if inside_polygon(x, y, self.coords_of(line=polygon_nr)):
                        return self.timezone_names[self.id_of(polygon_nr)]

        # no polygon has been matched
        return None
    def timezone_at(self, *, lng: float, lat: float) -> Optional[str]:
        """ looks up in which timezone the given coordinate is possibly included in

        to speed things up there are shortcuts being used (stored in a binary file)
        especially for large polygons it is expensive to check if a point is really included,
        so certain simplifications are made and even when you get a hit the point might actually
        not be inside the polygon (for example when there is only one timezone nearby)
        if you want to make sure a point is really inside a timezone use ``certain_timezone_at()``

        :param lng: longitude of the point in degree (-180.0 to 180.0)
        :param lat: latitude in degree (90.0 to -90.0)
        :return: the timezone name of a matching polygon or None
        """
        lng, lat = rectify_coordinates(lng, lat)

        shortcut_id_x, shortcut_id_y = coord2shortcut(lng, lat)
        getattr(self, SHORTCUTS_UNIQUE_ID).seek(
            (NR_LAT_SHORTCUTS * NR_BYTES_H * shortcut_id_x +
             NR_BYTES_H * shortcut_id_y))
        try:
            # if there is just one possible zone in this shortcut instantly return its name
            return getattr(self, TIMEZONE_NAMES)[unpack(
                DTYPE_FORMAT_H,
                getattr(self, SHORTCUTS_UNIQUE_ID).read(NR_BYTES_H))[0]]
        except IndexError:
            possible_polygons = self.polygon_ids_of_shortcut(
                shortcut_id_x, shortcut_id_y)
            nr_possible_polygons = len(possible_polygons)
            if nr_possible_polygons == 0:
                return None
            if nr_possible_polygons == 1:
                # there is only one polygon in that area. return its timezone name without further checks
                return getattr(self, TIMEZONE_NAMES)[self.id_of(
                    possible_polygons[0])]

            # create a list of all the timezone ids of all possible polygons
            ids = self.id_list(possible_polygons, nr_possible_polygons)
            # x = longitude  y = latitude  both converted to 8byte int
            x = coord2int(lng)
            y = coord2int(lat)

            # check until the point is included in one of the possible polygons
            for i in range(nr_possible_polygons):

                # when including the current polygon only polygons from the same zone remain,
                same_element = all_the_same(pointer=i,
                                            length=nr_possible_polygons,
                                            id_list=ids)
                if same_element != -1:
                    # return the name of that zone
                    return getattr(self, TIMEZONE_NAMES)[same_element]

                polygon_nr = possible_polygons[i]

                # get the boundaries of the polygon = (lng_max, lng_min, lat_max, lat_min)
                getattr(self,
                        POLY_MAX_VALUES).seek(4 * NR_BYTES_I * polygon_nr)
                boundaries = self._fromfile(getattr(self, POLY_MAX_VALUES),
                                            dtype=DTYPE_FORMAT_SIGNED_I_NUMPY,
                                            count=4)
                # only run the expensive algorithm if the point is withing the boundaries
                if not (x > boundaries[0] or x < boundaries[1]
                        or y > boundaries[2] or y < boundaries[3]):

                    outside_all_holes = True
                    # when the point is within a hole of the polygon, this timezone must not be returned
                    for hole_coordinates in self._holes_of_poly(polygon_nr):
                        if inside_polygon(x, y, hole_coordinates):
                            outside_all_holes = False
                            break

                    if outside_all_holes:
                        if inside_polygon(
                                x, y, self.coords_of(polygon_nr=polygon_nr)):
                            # the point is included in this polygon. return its timezone name without further checks
                            return getattr(self, TIMEZONE_NAMES)[ids[i]]

            # the timezone name of the last polygon should always be returned
            # if no other polygon has been matched beforehand.
            raise ValueError(
                'BUG: this statement should never be reached. Please open up an issue on Github!'
            )
    def timezone_at(self, *, lng: float, lat: float) -> str:
        """computes in which ocean OR land timezone a point is included in

        Especially for large polygons it is expensive to check if a point is really included.
        To speed things up there are "shortcuts" being used (stored in a binary file),
        which have been precomputed and store which timezone polygons have to be checked.
        In case there is only one possible zone this zone will instantly be returned without actually checking
        if the query point is included in this polygon -> speed up

        Since ocean timezones span the whole globe, some timezone will always be matched!

        :param lng: longitude of the point in degree (-180.0 to 180.0)
        :param lat: latitude in degree (90.0 to -90.0)
        :return: the timezone name of the matched timezone polygon. possibly "Etc/GMT+-XX" in case of an ocean timezone.
        """
        lng, lat = rectify_coordinates(lng, lat)

        shortcut_id_x, shortcut_id_y = coord2shortcut(lng, lat)
        timezone = self._get_unique_zone(shortcut_id_x, shortcut_id_y)
        if timezone is not None:  # found perfect and fast match
            return timezone
        # more thorough testing required:
        possible_polygons = self.polygon_ids_of_shortcut(
            shortcut_id_x, shortcut_id_y)
        nr_possible_polygons = len(possible_polygons)
        if nr_possible_polygons == 0:
            raise ValueError(
                "some timezone polygon should be present (ocean timezones exist everywhere)!"
            )
        if nr_possible_polygons == 1:
            # there is only one polygon in that area. return its timezone name without further checks
            return getattr(self,
                           TIMEZONE_NAMES)[self.id_of(possible_polygons[0])]

        # create a list of all the timezone ids of all possible polygons
        ids = self.id_list(possible_polygons, nr_possible_polygons)
        # x = longitude  y = latitude  both converted to 8byte int
        x = coord2int(lng)
        y = coord2int(lat)

        # check until the point is included in one of the possible polygons
        for i in range(nr_possible_polygons):

            # when including the current polygon only polygons from the same zone remain,
            same_element = all_the_same(pointer=i,
                                        length=nr_possible_polygons,
                                        id_list=ids)
            if same_element != -1:
                # return the name of that zone
                return getattr(self, TIMEZONE_NAMES)[same_element]

            polygon_nr = possible_polygons[i]

            # get the boundaries of the polygon = (lng_max, lng_min, lat_max, lat_min)
            getattr(self, POLY_MAX_VALUES).seek(4 * NR_BYTES_I * polygon_nr)
            boundaries = self._fromfile(
                getattr(self, POLY_MAX_VALUES),
                dtype=DTYPE_FORMAT_SIGNED_I_NUMPY,
                count=4,
            )
            # only run the expensive algorithm if the point is withing the boundaries
            if not (x > boundaries[0] or x < boundaries[1] or y > boundaries[2]
                    or y < boundaries[3]):

                outside_all_holes = True
                # when the point is within a hole of the polygon, this timezone must not be returned
                for hole_coordinates in self._holes_of_poly(polygon_nr):
                    if inside_polygon(x, y, hole_coordinates):
                        outside_all_holes = False
                        break

                if outside_all_holes:
                    if inside_polygon(x, y,
                                      self.coords_of(polygon_nr=polygon_nr)):
                        # the point is included in this polygon. return its timezone name without further checks
                        return getattr(self, TIMEZONE_NAMES)[ids[i]]

        # the timezone name of the last polygon should always be returned
        # if no other polygon has been matched beforehand.
        raise ValueError(
            "BUG: this statement should never be reached. Please open up an issue on Github!"
        )