While vertices can be checked relatively easily for their distances (e.g. scipy kD Tree distance matrix), lines can approach each other very closely as well. This will then result in very small triangles as the near intersection point. This can be dealt with pragmatically by running the mesh generation in two phases: run with original geometries; identify and resolve near nodes; remesh with resolved nodes and the original bounding polygon.
xugrid makes this somewhat straightforward:
import geopandas as gpd
import pandamesh as pm
import pandas as pd
import xugrid as xu
gdf = gpd.read_file("geometry.shp")
mesher = pm.TriangleMesher(gdf)
grid = mesher.generate_ugrid()
_, snapped_x, snapped_y = xu.snap_nodes(x=grid.node_x, y=grid.node_y, max_snap_distance=5.0)
gdf_snapped = gpd.GeoDataFrame(
geometry=gpd.points_from_xy(snapped_x, snapped_y)
)
gdf_polygon = gpd.GeoDataFrame(
geometry=[grid.bounding_polygon]
)
# Maybe remove points that are already polygon vertices so it won't complain?
gdf_new = pd.concat((gdf_snapped, gdf_polygon), ignore_index=True)
gdf_new["cellsize"] = 1000.0 # some large value that won't affect remeshing
mesher = pm.TriangleMesher(gdf_new)
grid_new = mesher.generate_ugrid()
While vertices can be checked relatively easily for their distances (e.g. scipy kD Tree distance matrix), lines can approach each other very closely as well. This will then result in very small triangles as the near intersection point. This can be dealt with pragmatically by running the mesh generation in two phases: run with original geometries; identify and resolve near nodes; remesh with resolved nodes and the original bounding polygon.
xugrid makes this somewhat straightforward: