예제 #1
0
    def _get_old_and_new_crs(self, ds_path, ds_diff, context=None):
        from kart.crs_util import make_crs

        # If the CRS is changing during the diff, we extract the two CRS from the diff.
        if "meta" in ds_diff:
            meta_diff = ds_diff["meta"]
            old_crs_defs = [
                v.old_value for k, v in meta_diff.items()
                if k.startswith("crs/") and v.old is not None
            ]
            new_crs_defs = [
                v.new_value for k, v in meta_diff.items()
                if k.startswith("crs/") and v.new is not None
            ]
            if len(old_crs_defs) > 1 or len(new_crs_defs) > 1:
                self._raise_multi_crs_error(ds_path, context=context)
            old_crs, new_crs = None, None
            if old_crs_defs:
                old_crs = make_crs(old_crs_defs[0], context=ds_path)
            if new_crs_defs:
                new_crs = make_crs(new_crs_defs[0], context=ds_path)
            if old_crs_defs or new_crs_defs:
                return old_crs, new_crs

        # No diff - old and new CRS are the same.
        ds = self.base_rs.datasets().get(
            ds_path) or self.target_rs.datasets().get(ds_path)
        crs_defs = list(ds.crs_definitions().values())
        if not crs_defs:
            return None, None
        if len(crs_defs) > 1:
            self._raise_multi_crs_error(ds_path, context=context)
        crs = make_crs(crs_defs[0], context=ds_path)
        return crs, crs
예제 #2
0
    def transform_for_schema_and_crs(self, schema, crs, ds_path=None):
        """
        Similar to transform_for_dataset above, but can also be used without a dataset object - for example,
        to apply the spatial filter to a working copy table which might not exactly match any dataset.

        schema - the dataset (or table) schema.
        new_crs - the crs definition of the dataset or table.
            The CRS should be a name eg EPSG:4326, or a full CRS definition, or an osgeo.osr.SpatialReference.
        """
        if self.match_all:
            return SpatialFilter._MATCH_ALL

        geometry_columns = schema.geometry_columns
        if not geometry_columns:
            return SpatialFilter._MATCH_ALL
        new_geom_column_name = geometry_columns[0].name

        from osgeo import osr

        try:
            crs_spec = str(crs)
            if isinstance(crs, str):
                crs = make_crs(crs)
            transform = osr.CoordinateTransformation(self.crs, crs)
            new_filter_ogr = self.filter_ogr.Clone()
            new_filter_ogr.Transform(transform)
            return SpatialFilter(crs, new_filter_ogr, new_geom_column_name)

        except RuntimeError as e:
            crs_desc = f"CRS for {ds_path!r}" if ds_path else f"CRS:\n {crs_spec!r}"
            raise CrsError(
                f"Can't reproject spatial filter into {crs_desc}:\n{e}")
예제 #3
0
파일: index.py 프로젝트: koordinates/kart
 def crs_from_oid(self, crs_oid):
     wkt = normalise_wkt(self.repo[crs_oid].data.decode("utf-8"))
     result = make_crs(wkt)
     for prior_result in self._distinct_crs_list:
         if result.IsSame(prior_result):
             return prior_result
     self._distinct_crs_list.append(result)
     return result
예제 #4
0
파일: index.py 프로젝트: koordinates/kart
 def __init__(self, repo, start_commits=None, stop_commits=None):
     self.repo = repo
     self.ds_to_transforms = {}
     self.target_crs = make_crs("EPSG:4326")
     self._distinct_crs_list = []
     if start_commits is not None:
         self.start_stop_spec = [*start_commits, "--not", *stop_commits]
     else:
         self.start_stop_spec = ["--all"]
예제 #5
0
 def __init__(self, crs_spec, geometry_spec, match_all=False):
     if match_all:
         super().__init__(None, None, match_all=True)
         self.hexhash = None
     else:
         ctx = "spatial filter"
         geometry = geometry_from_string(geometry_spec, context=ctx)
         crs = make_crs(crs_spec, context=ctx)
         super().__init__(crs, geometry.to_ogr())
         self.hexhash = hexhash(crs_spec.strip(), geometry.to_wkb())
예제 #6
0
 def get_geometry_transform(self, target_crs):
     """
     Find the transform to reproject this dataset into the target CRS.
     Returns None if the CRS for this dataset is unknown.
     """
     crs_definition = self.get_crs_definition()
     if crs_definition is None:
         return None
     try:
         src_crs = crs_util.make_crs(crs_definition)
         return osr.CoordinateTransformation(src_crs, target_crs)
     except RuntimeError as e:
         raise InvalidOperation(
             f"Can't reproject dataset {self.path!r} into target CRS: {e}")
예제 #7
0
    def envelope_wgs84(self):
        from osgeo import osr

        try:
            transform = osr.CoordinateTransformation(self.crs,
                                                     make_crs("EPSG:4326"))
            geom_ogr = self.geometry.to_ogr()
            geom_ogr.Transform(transform)
            w, e, s, n = geom_ogr.GetEnvelope()
            return w, s, e, n

        except RuntimeError as e:
            raise CrsError(
                f"Can't reproject spatial filter into EPSG:4326:\n{e}")
예제 #8
0
 def __init__(self, crs_spec, geometry_spec, match_all=False):
     super().__init__()
     self.match_all = match_all
     if not self.match_all:
         self.crs_spec = crs_spec
         self.geometry_spec = geometry_spec
         self.crs = make_crs(crs_spec)
         self.geometry = geometry_from_string(
             geometry_spec,
             allowed_types=(GeometryType.POLYGON,
                            GeometryType.MULTIPOLYGON),
             allow_empty=False,
             context="spatial filter",
         )
예제 #9
0
        for row in r:
            blob_id = row[0].hex()
            envelope = encoder.decode(row[1])
            for i in range(len(score_funcs)):
                score = score_funcs[i](blob_id, envelope)
                if score > winning_scores[i]:
                    winning_scores[i] = score
                    winners[i] = Entry(blob_id, envelope)

        return IndexSummary(features, *winners)


# This transform leaves every point exactly where it is, even points past the antimeridian eg (185, 0)
# We need to test this since its a special case - no other transform will result in longitudes outside
# the range [-180, 180].
EPSG_4326 = make_crs("EPSG:4326")
IDENTITY_TRANSFORM = osr.CoordinateTransformation(EPSG_4326, EPSG_4326)

# This transform tests the general case - like most transforms, the end result will be points with
# longitudes wrapped into the range [-180, 180]. It also is valid over an area that crosses the
# anti-meridian, so we can test that too.
NZTM = make_crs("EPSG:2193")
NZTM_TRANSFORM = osr.CoordinateTransformation(NZTM, EPSG_4326)


@pytest.mark.parametrize(
    "input,transform,expected_result",
    [
        ((1, 2, 3, 4), IDENTITY_TRANSFORM, (1, 2, 3, 4)),
        ((177, -10, 184, 10), IDENTITY_TRANSFORM, (177, -10, -176, 10)),
        ((185, 10, 190, 20), IDENTITY_TRANSFORM, (-175, 10, -170, 20)),