Skip to content

Commit 52c839d

Browse files
committed
add shp point z-value buffer
1 parent 3724491 commit 52c839d

File tree

1 file changed

+87
-12
lines changed

1 file changed

+87
-12
lines changed

easyric/io/shp.py

Lines changed: 87 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import pyproj
33
import numpy as np
4+
from shapely.geometry import Polygon, Point
45
from easyric.external import shapefile
56
from easyric.io.geotiff import point_query, mean_values, min_values, get_header
67

@@ -120,16 +121,69 @@ def read_shp2d(shp_path, shp_proj=None, geotiff_proj=None, name_field=None, titl
120121
return shp_dict
121122

122123

123-
def read_shp3d(shp_path, dsm_path, get_z_by='mean', shp_proj=None, geotiff_proj=None, geo_head=None, name_field=None, title_include=False, encoding='utf-8'):
124-
'''
125-
shp_path: full shp_file directory
126-
get_z_by:
127-
"all": using the mean value of whole DSM as the same z-value for all boundary points
128-
-> this will get a 2D plane of ROI
129-
"mean": using the mean value of boundary points closed part.
130-
"local" using the z value of where boundary points located, each point will get different z-values
124+
def read_shp3d(shp_path, dsm_path, get_z_by='mean', get_z_buffer=0, shp_proj=None, geotiff_proj=None, geo_head=None, name_field=None, title_include=False, encoding='utf-8'):
125+
"""[summary]
126+
127+
Parameters
128+
----------
129+
shp_path : str
130+
full shp_file directory
131+
dsm_path : str
132+
full dsm_file directory where want to extract height from
133+
get_z_by : str, optional
134+
["local", "mean", "min", "max", "all"], by default 'mean'
135+
- "local" using the z value of where boundary points located, each point will get different z-values
131136
-> this will get a 3D curved mesh of ROI
132-
'''
137+
- "mean": using the mean value of boundary points closed part.
138+
- "min": 5th percentile mean height (the mean value of all pixels < 5th percentile)
139+
- "max": 95th percentile mean height (the mean value of all pixels > 95th percentile)
140+
- "all": using the mean value of whole DSM as the same z-value for all boundary points
141+
-> this will get a 2D plane of ROI
142+
get_z_buffer : int, optional
143+
the buffer of ROI, by default 0
144+
it is suitable when the given ROI is points rather than polygons. Given this paramter will generate a round buffer
145+
polygon first, then extract the z-value by this region, but the return will only be a single point
146+
The unit of buffer follows the ROI coordinates, either pixel or meter.
147+
shp_proj : str or pyproj.CRS object, optional
148+
The projection coordinate of given shp file, by default None, it will automatic find the proj file
149+
geotiff_proj : pyproj.CRS object, optional
150+
The projection coordinate of given dsm file, by default None, it will automatic find it in geohead
151+
geo_head : dict, optional
152+
returned dict of geotiff.get_header() , by default None
153+
specify this to save the dsm file reading time cost
154+
name_field : int | str | list, optional
155+
The column name of shp file to use as index of ROI, by default None
156+
e.g. shp file with following title:
157+
| id | plot | species |
158+
|----|------|---------|
159+
| 01 | aaa | xxx |
160+
| 02 | bbb | yyy |
161+
162+
- "int": the colume number used as title, start from 0
163+
e.g. name_field = 0
164+
-> {"01": [...], "02": [...], ...}
165+
- "str": the colume title used as title
166+
e.g. name_field = "plot"
167+
-> {"aaa": [...], "bbb": [...]}
168+
- "list": combine multipule title together
169+
e.g.: name_field = ["plot", "species"]
170+
-> {"aaa_xxx": [...], "bbb_yyy":[...], ...}
171+
title_include : bool, optional
172+
where add column title into index, by default False
173+
e.g.: name_field = ["plot", "species"]
174+
title_include = False
175+
-> {"aaa_xxx": [...], "bbb_yyy":[...], ...}
176+
title_include = True
177+
-> {"plot_aaa_species_xxx": [...], "plot_bbb_species_yyy":[...], ...}
178+
encoding : str, optional
179+
by default 'utf-8'
180+
181+
Returns
182+
-------
183+
[type]
184+
[description]
185+
"""
186+
133187
shp_dict = {}
134188
if geo_head is None:
135189
tiff_header = get_header(dsm_path)
@@ -146,6 +200,16 @@ def read_shp3d(shp_path, dsm_path, get_z_by='mean', shp_proj=None, geotiff_proj=
146200
keys = list(shp_dict_2d.keys())
147201
coord_list = [shp_dict_2d[k] for k in keys]
148202

203+
if get_z_buffer != 0:
204+
coord_list_buffer = []
205+
for k in keys:
206+
seed = shp_dict_2d[k]
207+
if seed.shape[0] == 1: # single point
208+
buffered = Point(seed[0,:]).buffer(get_z_buffer)
209+
else: # polygon
210+
buffered = Polygon(seed).buffer(get_z_buffer)
211+
coord_list_buffer.append(np.asarray(buffered.exterior.coords))
212+
149213
print(f"[io][shp][name] Loading Z values from DSM, this may take a while")
150214
# then add z_values on it
151215
if get_z_by == 'local':
@@ -154,17 +218,28 @@ def read_shp3d(shp_path, dsm_path, get_z_by='mean', shp_proj=None, geotiff_proj=
154218
coord_np = np.concatenate([coord_np, coord_z[:, None]], axis=1)
155219
shp_dict[k] = coord_np
156220
elif get_z_by == 'mean':
157-
z_lists = mean_values(dsm_path, polygon=coord_list, geo_head=tiff_header)
221+
if get_z_buffer == 0:
222+
z_lists = mean_values(dsm_path, polygon=coord_list, geo_head=tiff_header)
223+
else:
224+
z_lists = mean_values(dsm_path, polygon=coord_list_buffer, geo_head=tiff_header)
225+
158226
for k, coord_np, coord_z in zip(keys, coord_list, z_lists):
159227
coord_np = np.insert(coord_np, obj=2, values=coord_z, axis=1)
160228
shp_dict[k] = coord_np
161229
elif get_z_by == 'min':
162-
z_lists = min_values(dsm_path, polygon=coord_list, geo_head=tiff_header)
230+
if get_z_buffer == 0:
231+
z_lists = min_values(dsm_path, polygon=coord_list, geo_head=tiff_header)
232+
else:
233+
z_lists = min_values(dsm_path, polygon=coord_list_buffer, geo_head=tiff_header)
234+
163235
for k, coord_np, coord_z in zip(keys, coord_list, z_lists):
164236
coord_np = np.insert(coord_np, obj=2, values=coord_z, axis=1)
165237
shp_dict[k] = coord_np
166238
elif get_z_by == 'max':
167-
z_lists = min_values(dsm_path, polygon=coord_list, geo_head=tiff_header, pctl=95)
239+
if get_z_buffer == 0:
240+
z_lists = min_values(dsm_path, polygon=coord_list, geo_head=tiff_header, pctl=95)
241+
else:
242+
z_lists = min_values(dsm_path, polygon=coord_list_buffer, geo_head=tiff_header, pctl=95)
168243
for k, coord_np, coord_z in zip(keys, coord_list, z_lists):
169244
coord_np = np.insert(coord_np, obj=2, values=coord_z, axis=1)
170245
shp_dict[k] = coord_np

0 commit comments

Comments
 (0)