Skip to content

Commit 408097a

Browse files
committed
make use of feature.Clone; streamline reprojection via coordinate transformation
1 parent fd8f537 commit 408097a

File tree

1 file changed

+33
-34
lines changed

1 file changed

+33
-34
lines changed

clipping-service/app/app.py

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -89,41 +89,44 @@ def _clip_vector_to_bounding_box(
8989
Returns:
9090
None
9191
"""
92-
working_file_path = None
93-
print(target_projection_wkt)
94-
if target_projection_wkt:
95-
app.logger.debug("REPROJECTING VECTOR...")
96-
working_file_path = target_vector_path.replace('.fgb', '-projected.fgb')
97-
try:
98-
pygeoprocessing.reproject_vector(source_vector_path,
99-
target_projection_wkt, working_file_path,
100-
driver_name='FlatGeobuf')
101-
source_vector_path = working_file_path
102-
except Exception:
103-
app.logger.exception("Failed to reproject vector; aborting")
104-
os.remove(working_file_path)
105-
raise
92+
shapely_mask = shapely.prepared.prep(
93+
shapely.geometry.box(*target_bounding_box))
10694

107-
shapely_mask = shapely.prepared.prep(shapely.geometry.box(*target_bounding_box))
108-
109-
app.logger.debug("OPENING BASE VECTOR...")
95+
app.logger.debug("Opening base vector...")
11096
base_vector = gdal.OpenEx(source_vector_path, gdal.OF_VECTOR)
11197
base_layer = base_vector.GetLayer()
98+
base_layer.SetSpatialFilterRect(*target_bounding_box)
11299
base_layer_defn = base_layer.GetLayerDefn()
113100
base_geom_type = base_layer.GetGeomType()
101+
base_srs = base_layer.GetSpatialRef()
102+
103+
if target_projection_wkt is not None:
104+
target_srs = osr.SpatialReference()
105+
target_srs.ImportFromWkt(target_projection_wkt)
106+
coord_trans = osr.CreateCoordinateTransformation(base_srs, target_srs)
107+
else:
108+
target_srs = base_srs
114109

115-
app.logger.debug("SETTING UP TARGET...")
110+
app.logger.debug("Setting up target...")
116111
target_driver = gdal.GetDriverByName('FlatGeobuf')
117112
target_vector = target_driver.Create(
118113
target_vector_path, 0, 0, 0, gdal.GDT_Unknown)
119114
target_layer = target_vector.CreateLayer(
120-
base_layer_defn.GetName(), base_layer.GetSpatialRef(), base_geom_type)
115+
base_layer_defn.GetName(), target_srs, base_geom_type)
121116
target_layer.CreateFields(base_layer.schema)
122117

123-
app.logger.debug("CLIPPING VECTOR...")
118+
app.logger.debug("Clipping vector...")
124119
target_layer.StartTransaction()
125120
invalid_feature_count = 0
121+
n_processed = 0
122+
last_log_msg_time = time.time()
126123
for feature in base_layer:
124+
now = time.time()
125+
if now >= last_log_msg_time+2.0:
126+
app.logger.debug(f"Processed {n_processed} features so far")
127+
last_log_msg_time = now
128+
n_processed += 1
129+
127130
invalid = False
128131
geometry = feature.GetGeometryRef()
129132
try:
@@ -137,11 +140,14 @@ def _clip_vector_to_bounding_box(
137140
# Check for intersection rather than use gdal.Layer.Clip()
138141
# to preserve the shape of the polygons
139142
if shapely_mask.intersects(shapely_geom):
140-
new_feature = ogr.Feature(target_layer.GetLayerDefn())
141-
new_feature.SetGeometry(ogr.CreateGeometryFromWkb(
142-
shapely_geom.wkb))
143-
for field_name, field_value in feature.items().items():
144-
new_feature.SetField(field_name, field_value)
143+
# This appears to use the network WAY less
144+
new_feature = ogr.Feature.Clone(feature)
145+
146+
# If we need to, transform the geometry
147+
if target_projection_wkt is not None:
148+
geometry.Transform(coord_trans)
149+
new_feature.SetGeometry(geometry)
150+
145151
target_layer.CreateFeature(new_feature)
146152
else:
147153
invalid = True
@@ -164,9 +170,6 @@ def _clip_vector_to_bounding_box(
164170
target_layer = None
165171
target_vector = None
166172

167-
if working_file_path:
168-
os.remove(working_file_path)
169-
170173

171174
@functools.lru_cache
172175
def cached_file_info(vsi_file_path, file_type):
@@ -179,7 +182,7 @@ def cached_file_info(vsi_file_path, file_type):
179182
raise
180183
elif file_type == VECTOR:
181184
try:
182-
return pygeoprocessing.get_vector_info(f"/vsicurl/{vsi_file_path}")
185+
return pygeoprocessing.get_vector_info(vsi_file_path)
183186
except Exception:
184187
app.logger.error("Failed to read vector info for %s", vsi_file_path)
185188
raise
@@ -302,11 +305,10 @@ def clip():
302305
source_file_path = f'/vsicurl/{parameters["file_url"]}'
303306
if source_file_type == VECTOR:
304307
# Temporarily hard-code path to NOAA shorelines flatgeobuf
305-
source_file_path = "https://storage.googleapis.com/jupyter-app-temp-storage/noaa_us_shorelines.fgb"
308+
source_file_path = "/vsicurl/https://storage.googleapis.com/jupyter-app-temp-storage/noaa_us_shorelines.fgb"
306309
# source_file_path = source_file_path.replace('.mvt', '.shp')
307310

308311
source_file_info = cached_file_info(source_file_path, source_file_type)
309-
app.logger.info(f"\n{source_file_info}\n")
310312

311313
if source_file_type == RASTER:
312314
app.logger.info("CLIPPING RASTER...")
@@ -351,9 +353,6 @@ def clip():
351353
try:
352354
target_projection_wkt = _epsg_to_wkt(
353355
parameters["target_epsg"])
354-
target_bbox = pygeoprocessing.transform_bounding_box(
355-
target_bbox, source_file_info['projection_wkt'],
356-
target_projection_wkt)
357356
except KeyError:
358357
target_projection_wkt = None
359358

0 commit comments

Comments
 (0)