Skip to content

Commit aea017c

Browse files
add ability to convert to build point file
1 parent fbe69ef commit aea017c

File tree

1 file changed

+50
-6
lines changed

1 file changed

+50
-6
lines changed

schimpy/convert_points.py

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import click
55
import geopandas as gpd
66
import pandas as pd
7+
import warnings
78
from shapely.geometry import Point
89
from schimpy.schism_sources_sinks import yaml2df
910
import yaml
@@ -22,27 +23,69 @@ def points_to_shp(fpath, points):
2223
gdf.to_file(fpath, driver="ESRI Shapefile")
2324

2425
def points_to_yaml(fpath, points):
26+
# Ensure columns exist
27+
if "sites" not in points.columns or "stype" not in points.columns:
28+
raise ValueError("Shapefile must contain 'sites' and 'stype' fields.")
2529

2630
dict_file = {}
2731
for _, row in points.iterrows():
2832
dict_file[str(row.sites)] = [round(float(row.x), 2), round(float(row.y), 2)]
2933
with open(fpath, "w") as file:
3034
yaml.dump(dict_file, file, default_flow_style=False, allow_unicode=True)
35+
36+
def points_to_bp(fpath, points):
37+
"""Convert a DataFrame to a SCHISM build points (.bp) file."""
38+
import numpy as np
39+
40+
# Calculate cumulative distance along the transect
41+
points = points.reset_index(drop=True)
42+
coords = points[['x', 'y']].values
43+
44+
# Calculate distances between consecutive points
45+
distances = np.sqrt(np.sum(np.diff(coords, axis=0)**2, axis=1))
46+
47+
# Cumulative distance starting at 0
48+
cumulative_distances = np.concatenate(([0], np.cumsum(distances)))
49+
50+
# Write to file
51+
with open(fpath, 'w') as f:
52+
# Write header
53+
f.write("point x y z distance\n")
54+
f.write(f"{len(points)} ! Number of points\n")
55+
56+
# Write each point
57+
for i, (_, row) in enumerate(points.iterrows(), start=1):
58+
x = float(row['x'])
59+
y = float(row['y'])
60+
z = -10000.0
61+
distance = float(cumulative_distances[i-1])
62+
f.write(f"{i} {x} {y} {z} {distance}\n")
63+
64+
print(f"\nBuild points file written to {fpath}.")
65+
3166

3267
def shp_to_df(fpath):
3368
"""
3469
Read a point shapefile using geopandas and return a DataFrame
3570
with 'sites', 'stype', 'x', and 'y' columns.
3671
"""
3772
gdf = gpd.read_file(fpath)
38-
# Ensure columns exist
39-
if "sites" not in gdf.columns or "stype" not in gdf.columns:
40-
raise ValueError("Shapefile must contain 'sites' and 'stype' fields.")
73+
4174
# Extract coordinates
4275
gdf["x"] = gdf.geometry.x
4376
gdf["y"] = gdf.geometry.y
77+
4478
# Select relevant columns
45-
df = gdf[["sites", "stype", "x", "y"]].copy()
79+
cols = ["x", "y"]
80+
if "sites" in gdf.columns:
81+
cols.insert(0, "sites")
82+
if "stype" in gdf.columns:
83+
cols.insert(1 if "sites" in gdf.columns else 0, "stype")
84+
85+
if "sites" not in gdf.columns or "stype" not in gdf.columns:
86+
warnings.warn("Shapefile must contain 'sites' and 'stype' fields for conversion to yaml")
87+
88+
df = gdf[cols].copy()
4689
return df
4790

4891

@@ -62,14 +105,15 @@ def write_points(fpath, points):
62105
return points_to_shp(fpath, points)
63106
elif fpath.endswith(".yaml"):
64107
return points_to_yaml(fpath, points)
108+
elif fpath.endswith(".bp"):
109+
return points_to_bp(fpath, points)
65110
else:
66111
raise ValueError("Not supported output file type. Only Shapefile (.shp) is supported.")
67112

68113

69114
@click.command(
70115
help="Convert SCHISM points (source and sink) between YAML and Shapefile formats."
71116
)
72-
@click.help_option("-h", "--help")
73117
@click.option(
74118
"--input",
75119
required=True,
@@ -80,7 +124,7 @@ def write_points(fpath, points):
80124
"--output",
81125
required=True,
82126
type=click.Path(),
83-
help="Output file (.yml, .yaml, .in, or .shp).",
127+
help="Output file (.yml, .yaml, .in, .bp, or .shp).",
84128
)
85129
@click.help_option("-h", "--help")
86130
def convert_points_cli(input, output):

0 commit comments

Comments
 (0)