Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Regression model from skeleton #10

Merged
merged 85 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
172cf01
update readme for methodology : traitement grand cours d'eau
mdupaysign Jul 18, 2024
8c103b3
refacto config with virtual points
mdupaysign Jul 31, 2024
e67d7be
add fonction KNN
mdupaysign Jul 31, 2024
ef59cd3
add function for lauch virtual points
mdupaysign Jul 31, 2024
4e6c02e
refacto function: delete calculate Z q1
mdupaysign Jul 31, 2024
e6a4ab6
refacto mask buffer with negative buffer
mdupaysign Jul 31, 2024
584f094
add test function las around point
mdupaysign Jul 31, 2024
9db18fa
add function and test for merging skeleton by mask hydro
mdupaysign Jul 31, 2024
352dd47
add function and test for intersect points by line
mdupaysign Jul 31, 2024
23728c2
add function and test for generate 2D grid
mdupaysign Jul 31, 2024
c089b73
add function for applying Z from 2D grid
mdupaysign Jul 31, 2024
d878be7
add fucntion and test for creating model
mdupaysign Jul 31, 2024
263b562
add function and test for convert geodataframe to las: virtual points
mdupaysign Jul 31, 2024
e8894e4
add function for run the script for creating virtual points
mdupaysign Jul 31, 2024
05945fa
add function for little river : flattening
mdupaysign Jul 31, 2024
411e8b8
update config for virtual points
mdupaysign Aug 1, 2024
2b34530
update function main_create_virtual_point.py
mdupaysign Aug 1, 2024
cba333b
update classification (68)
mdupaysign Aug 4, 2024
3cd7f48
update script for flatten : z_first_quartile=0 when no points
mdupaysign Aug 4, 2024
1bdb271
change sjoin-within to sjoin-intersection + overlay : avoid error
mdupaysign Aug 6, 2024
7cab92b
refacto for creating 3D grid with tests: stop error
mdupaysign Aug 7, 2024
c50d917
refacto run create virtual points : save mask hydro are not okay in g…
mdupaysign Aug 7, 2024
2a7b06d
add logging info
mdupaysign Aug 7, 2024
4a9efc5
add logging info, and remove create grid points for flatten rivers (w…
mdupaysign Aug 7, 2024
b11e65f
add function test for linear regression
mdupaysign Aug 7, 2024
c2eeb54
add test for flatten little river
mdupaysign Aug 7, 2024
8db7311
add image for README and update README.md
mdupaysign Aug 8, 2024
958be8c
refacto configs: spacing and definition
mdupaysign Aug 8, 2024
23556bb
refacto README.md and lauch severals scripts .sh
mdupaysign Aug 8, 2024
62a999b
refacto README for test fonctionnels
mdupaysign Aug 8, 2024
aa72a3c
update config
mdupaysign Aug 9, 2024
c530db4
push new version
mdupaysign Aug 9, 2024
7aaf606
refacto test for flattening river
mdupaysign Aug 9, 2024
1115e38
refacto run_create_virtual_points and the test
mdupaysign Aug 9, 2024
0fb15f6
update README
mdupaysign Aug 9, 2024
841ad0b
refacto extract points around skeleton: save result by lidar tile
mdupaysign Aug 12, 2024
14aa14d
lauch function : extract points aloung skeleton with tests
mdupaysign Aug 12, 2024
ebf8fa8
update README
mdupaysign Aug 13, 2024
c0b0eaf
add exemple script for extract points around skeleton
mdupaysign Aug 13, 2024
0ccc864
add exemples scripts for create virtual point
mdupaysign Aug 13, 2024
5d8bbf8
refacto test and function for creating virtual points
mdupaysign Aug 13, 2024
10043cc
add new function for extract points around skeleton by tile : etape 4.A
mdupaysign Aug 13, 2024
62eb89a
update run create virtual points with new version
mdupaysign Aug 13, 2024
b9e832b
refacto linear regression model
mdupaysign Aug 13, 2024
82f230a
refacto test extract points from skeleton
mdupaysign Aug 13, 2024
3a3f117
refacto test intersection points by line
mdupaysign Aug 13, 2024
ab25e9f
refacto test merge skeleton by mask
mdupaysign Aug 13, 2024
dd4f5ea
update submodule
mdupaysign Aug 13, 2024
924eb51
update test config and script for lauch virtuals points
mdupaysign Aug 13, 2024
2949eb2
update input=input_dir_point_skeleton: error name
mdupaysign Aug 14, 2024
c5266db
update test for lauch virtual point
mdupaysign Aug 14, 2024
1c18bc2
update flatten river for avoid error
mdupaysign Aug 14, 2024
ee91796
rectify line 54
mdupaysign Aug 14, 2024
8667304
Update README.md
mdupaysign Aug 14, 2024
3d96fa1
add parameters (point_virtula_classes) for script convert_geodatafram…
mdupaysign Aug 27, 2024
d9a31b9
save the virtual points to LAZ
mdupaysign Aug 27, 2024
fb9deb1
modify defintion's function :calculate_grid_z_with_model
mdupaysign Aug 28, 2024
306ca37
modify spacing for generating grid points: name, default parameters, …
mdupaysign Aug 28, 2024
80f1728
convert json points_knn: refacto
mdupaysign Aug 28, 2024
c3c56d1
refacto function : add drop lines which contain one or more NaN values
mdupaysign Aug 28, 2024
afbaab3
refacto flatten_river.py because modify intersect_points_by_line.py
mdupaysign Aug 29, 2024
b259088
modify commentary function : returns
mdupaysign Aug 29, 2024
70eeb65
remove commented code
mdupaysign Aug 29, 2024
41ef54e
refacto 2 functions :main create virtual point and run create virtual…
mdupaysign Aug 29, 2024
dd54107
udpate test
mdupaysign Aug 29, 2024
f23b766
add parameters river length
mdupaysign Aug 30, 2024
b3f7cfd
modify output for test_main_lidro_input_file
mdupaysign Aug 30, 2024
6866797
refacto README
mdupaysign Aug 30, 2024
5685427
refacto configs and test associates
mdupaysign Sep 4, 2024
d44ceb5
refacto configs v2
mdupaysign Sep 4, 2024
9297179
modify parameters vector.points_grid_spacing to pointcloud.points_gri…
mdupaysign Sep 4, 2024
238a435
update geodatrame_to_las.py to list_points_to_las.py and refacto func…
mdupaysign Sep 5, 2024
ddb4052
refacto test convert list points to las
mdupaysign Sep 5, 2024
8cfa73e
refacto convert_list_points_las.py and test : delete geodataframe
mdupaysign Sep 6, 2024
8f0a50c
delete l66 : isinstance(points_Z, list)
mdupaysign Sep 6, 2024
73b70bf
refacto linear_regression_model.py
mdupaysign Sep 6, 2024
f87e5c4
modify typehint function's parameters
mdupaysign Sep 6, 2024
93f6aa4
add l86 *_ : because without, there is an error (ValueError: too many…
mdupaysign Sep 6, 2024
55a5d8d
delete drop pts_intersect = pts_intersect.dropna(subset=[index_right])
mdupaysign Sep 6, 2024
5a1c181
refacto run_create_virtual_point.py : delete if not points.empty and …
mdupaysign Sep 6, 2024
ce1fb1d
refacto test create grid 2d inside maskhydro : add test
mdupaysign Sep 6, 2024
d7ab20a
update commentarys for function main_create_virtual_point.py
mdupaysign Sep 6, 2024
de6d1e1
delete geometry_skeleton l106
mdupaysign Sep 10, 2024
1d1e9d6
refacto apply z from grid
mdupaysign Sep 10, 2024
9a0a43a
delete commentary round each coordindate to 8 decimal places
mdupaysign Sep 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 65 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,40 +8,64 @@ Pour créer des modèles numériques cohérents avec les modèles hydrologiques,
Cette modélisation des surfaces hydrographiques se décline en 3 grands enjeux :​
* Mise à plat des surfaces d’eau marine​
* Mise à plat des plans d’eau intérieurs (lac, marais, etc.)​
* Mise en plan des grands cours d’eau (>5m large) pour assurer l’écoulement​. A noter que cette étape sera développée en premier.
* Mise en plan des grands cours d’eau (>5m large) pour assurer l’écoulement​. A noter que pour l'instant seulement cette étape est développée.

## Traitement

![Chaine de traitement global de LIDRO](images/chaine_traitement_lidro.jpg)

Les données en entrées :
- dalles LIDAR classées
- données vectorielles représentant le réseau hydrographique issu des différentes bases de données IGN (BDUnis, BDTopo, etc.)
- données vectorielles représentant le réseau hydrographique issu des différentes bases de données IGN (BDUnis, BDTopo, etc.) / ! \ requête SQL fait manuellement pour le moment. Exemple de requête SQL sur le bloc PM du LIDAR HD
```
WITH emprise_PM AS (SELECT st_GeomFromText('POLYGON((875379.222972973 6431750.0,
875379.222972973 6484250.0,
946620.777027027 6484250.0,
946620.777027027 6431750.0,
875379.222972973 6431750.0))') as geom)

SELECT geometrie, nature, fictif, persistance, classe_de_largeur, position_par_rapport_au_sol
FROM troncon_hydrographique
JOIN emprise_PM ON st_intersects(troncon_hydrographique.geometrie,emprise_PM.geom)
WHERE NOT gcms_detruit
AND classe_de_largeur NOT IN ('Entre 0 et 5 m', 'Sans objet')
AND position_par_rapport_au_sol='0'
```

Trois grands axes du processus à mettre en place en distanguant l'échelle de traitmeent associé :
Trois grands axes du processus à mettre en place en distanguant l'échelle de traitement associé :
* 1- Création de masques hydrographiques à l'échelle de la dalle LIDAR
* 2- Création de masques hydrographiques pré-filtrés à l'échelle du chantier, soit :
* la suppression de ces masques dans les zones ZICAD/ZIPVA
* la suppression des aires < 150 m²
* la suppression des aires < 150 m² (paramétrable)
* la suppression des aires < 1000 m² hors BD IGN (grands cours d'eau < 5m de large)
A noter que pour l'instant, la suppresion des masques hydrographiques en dehors des grands cours d'eau et le nettoyage de ces masques s'effectuent manuellement. Ce processus sera développé prochainement en automatique.
* 3- Création de points virtuels le long de deux entités hydrographiques :
* Grands cours d'eau (> 5 m de large dans la BD Unis).
* Surfaces planes (mer, lac, étang, etc.)
* Surfaces planes (mer, lac, étang, etc.) (pas encore développé)

### Traitement des grands cours d'eau (> 5 m de large dans la BD Uns).

### Traitement des grands cours d'eau (> 5 m de large dans la BD Unis).
![Chaine de traitement des points virtuels](images/process_points_virtuels.jpg)

Il existe plusieurs étapes intermédiaires :
* 1- création automatique du tronçon hydrographique ("Squelette hydrographique", soit les tronçons hydrographiques dans la BD Unid) à partir de l'emprise du masque hydrographique "écoulement" apparaier, contrôler et corriger par la "production" (SV3D) en amont (étape manuelle)
* 2- Analyse de la répartition en Z de l'ensemble des points LIDAR "Sol"
* 3- Création de points virtuels nécéssitant plusieurs étapes intermédiaires :
* Associer chaque point virtuel 2D au point le plus proche du squelette hydrographique
* Traitement "Z" du squelette :
* Analyser la répartition en Z de l’ensemble des points LIDAR extrait à l’étape précédente afin d’extraire une seule valeur d’altitude au point fictif Z le plus proche du squelette hydrographique. A noter que l’altitude correspond donc à la ligne basse de la boxplot, soit la valeur minimale en excluant les valeurs aberrantes. Pour les ponts, une étape de contrôle de la classification pourrait être mise en place
* Lisser les Z le long du squelette HYDRO pour assurer l'écoulement
* Création des points virtuels 2D tous les 0.5 mètres le long des bords du masque hydrographique "écoulement" en cohérence en "Z" avec le squelette hydrographique
* 1- création automatique du tronçon hydrographique ("Squelette hydrographique", soit les tronçons hydrographiques dans la BD Unis) à partir de l'emprise du masque hydrographique "écoulement".
/ ! \ EN AMONT : Appariement, contrôle et correction manuels des masques hydrographiques "écoulement" (rivières) et du squelette hydrographique

A l'échelle de l'entité hydrographique :
* 2- Réccupérer tous les points LIDAR considérés comme du "SOL" situés à la limite de berges (masque hydrographique) moins N mètres
Pour les cours d'eau supérieurs à 150 m de long :
* 3- Transformer les coordonnées de ces points (étape précédente) en abscisses curvilignes
* 4- Générer un modèle de régression linéaire afin de générer tous les N mètres une valeur d'altitude le long du squelette de cette rivière. Les différents Z le long des squelettes HYDRO doivent assurer l'écoulement. Il est important de noter que tous les 50 mètres semble une valeur correcte pour appréhender la donnée. Cette valeur s'explique en raison de la précision altimétrique des données LIDAR (20 cm) ET que les rivières françaises correspondent à des cours d’eau naturels dont la pente est inférieure à 1%.
/ ! \ Pour les cours d'eau inférieurs à 150 m de long, le modèle de régression linéaire ne fonctionne pas. La valeur du premier quartile sera calculée sur l'ensemble des points d'altitudes du LIDAR "SOL" (étape 2) et affectée pour ces entités hydrographiques (< 150m de long) : aplanissement.
* 5- Création de points virtuels nécéssitant plusieurs étapes intermédiaires :
* Création des points virtuels 2D espacés selon une grille régulière tous les N mètres (paramétrable) à l'intérieur du masque hydrographique "écoulement"
* Affecter une valeur d'altitude à ces points virtuels en fonction des "Z" calculés à l'étape précédente (interpolation linéaire ou aplanissement)

### Traitement des surfaces planes (mer, lac, étang, etc.)
Pour rappel, l'eau est considérée comme horizontale sur ce type de surface.

/ ! \ EN ATTENTE / ! \
Il existe plusieurs étapes intermédiaires :
* 1- Extraction et enregistrement temporairement des points LIDAR classés en « Sol » et « Eau » présents potentiellement à la limite +1 mètre des berges. Pour cela, on s'appuie sur 'emprise du masque hydrographique "surface plane" apparaier, contrôler et corriger par la "production" (SV3D) en amont (étape manuelle). a noter que pur le secteur maritime (Mer), il faut exclure la classe « 9 » (eau) afin d’éviter de mesurer les vagues.
* 1- Extraction et enregistrement temporairement des points LIDAR classés en « Sol » et « Eau » présents potentiellement à la limite + 1 mètre des berges. Pour cela, on s'appuie sur l'emprise du masque hydrographique "surface plane" apparaier, contrôler et corriger par la "production" (SV3D) en amont (étape manuelle). a noter que pur le secteur maritime (Mer), il faut exclure la classe « 9 » (eau) afin d’éviter de mesurer les vagues.
* 2- Analyse statistique de l'ensemble des points LIDAR "Sol / Eau" le long des côtes/berges afin d'obtenir une surface plane.
L’objectif est de créer des points virtuels spécifiques avec une information d'altitude (m) tous les 0.5 m sur les bords des surfaces maritimes et des plans d’eau à partir du masque hydrographique "surface plane". Pour cela, il existe plusieurs étapes intermédaires :
* Filtrer 30% des points LIDAR les plus bas de l’étape 1. afin de supprimer les altitudes trop élevées
Expand Down Expand Up @@ -93,14 +117,35 @@ Voir les tests fonctionnels en bas du README.

## Tests
### Tests fonctionnels
Tester sur un seul fichier LAS/LAZ
* 1- Créer des masques hydrographiques à l'échelle de la dalle LIDAR
Tester sur un seul fichier LAS/LAZ pour créer un/des masques hydrographiques sur une dalle LIDAR
```
example_create_mask_by_tile.sh
```
Tester sur un dossier contenant plusieurs dalles LIDAR pour créer un/des masques hydrographiques
```
example_create_mask_default.sh
```
* 2- Créer un masque hydrographiques fusionné et nettoyé à l'échelle de l'ensemble de l'ensemble des dalles LIDAR
Tester sur un dossier contenant plusieurs dalles LIDAR pour créer fusionner l'ensemble des masques hydrographiques
```
example_merge_mask_default.sh
```
* 3- Création des tronçons hydrographiques à l'échelle de/des entité(s) hydrographique(s)
```
example_create_skeleton_lines.sh
```

* 4- Création des points virtuels

A. Tester sur un dossier contenant plusieurs dalles LIDAR pour créer des points tous les N mètres le long du squelette hydrographique, et réccupérer les N plus proches voisins points LIDAR "SOL"
```
example_lidro_by_tile.sh
example_extract_points_around_skeleton_default.sh
```

Tester sur un dossier
B. Tester sur un dossier contenant plusieurs dalles LIDAR pour créer des points virtuels 3D à l'intérieurs des masques hydrographiques
```
example_lidro_default.sh
example_create_virtual_point_default.sh
```

### Tests unitaires
Expand Down
37 changes: 24 additions & 13 deletions configs/configs_lidro.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ io:
input_skeleton: null
input_dir: null
output_dir: null
dir_points_skeleton: null # folder to contains files (.GeoJSON) by LIDAR tiles : neighboring points for each point of the skeleton
srid: 2154
extension: .tif
raster_driver: GTiff
Expand All @@ -27,7 +28,7 @@ io:

mask_generation:
raster:
# size for dilatation
# Size for dilatation
dilation_size: 3
filter:
# Classes to be considered as "non-water"
Expand All @@ -41,18 +42,6 @@ mask_generation:
# Tolerance from Douglas-Peucker
tolerance: 1

virtual_point:
filter:
# Keep ground and water pointclouds between Hydro Mask and Hydro Mask buffer
keep_neighbors_classes: [2, 9]
vector:
# distance in meters between 2 consecutive points
distance_meters: 2
# buffer for searching the points classification (default. "2") of the input LAS/LAZ file
buffer: 2
# The number of nearest neighbors to find with KNeighbors
k: 20

skeleton:
max_gap_width: 200 # distance max in meter of any gap between 2 branches we will try to close with a line
max_bridges: 1 # number max of bridges that can be created between 2 branches
Expand All @@ -74,6 +63,28 @@ skeleton:
water_min_size: 500 # min size of a skeleton line to be sure not to be removed (should be at least more than half the max river width)
max_gap_candidates: 3 # max number of candidates to close a gap between 2 branches

virtual_point:
filter:
# Keep ground and water pointclouds between Hydro Mask and Hydro Mask buffer
keep_neighbors_classes: [2, 9]
vector:
# Distance in meters between 2 consecutive points from Skeleton Hydro
distance_meters: 5
# Buffer for searching the points classification (default. "3") of the input LAS/LAZ file
buffer: 3
# The number of nearest neighbors to find with KNeighbors
k: 3
# The minimum length of a river to use the linear regression model
river_length: 150
pointcloud:
# Spacing between the grid points in meters by default "0.5"
gliegard marked this conversation as resolved.
Show resolved Hide resolved
points_grid_spacing: 0.5
# The number of the classe assign those virtual points
virtual_points_classes : 68




hydra:
output_subdir: null
run:
Expand Down
2 changes: 1 addition & 1 deletion data
Submodule data updated from 19f969 to 36a33e
Binary file added images/chaine_traitement_lidro.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/process_points_virtuels.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
""" this function convert GeoDataframe "virtual points" to LIDAR points
"""
import logging
import os
from typing import List

import laspy
import numpy as np
import pandas as pd
from shapely.geometry import Point


def list_points_to_las(virtual_points: List[Point], output_dir: str, crs: str, virtual_points_classes: int):
"""This function convert virtual points (List of virtuals points) to LIDAR points
with classification for virtual points

Args:
virtual_points (List[Point]): A list containing virtuals points by hydrological entity
output_dir (str): folder to output LAS
crs (str): a pyproj CRS object used to create the output GeoJSON file
virtual_points_classes (int): The classification value to assign to those virtual points
"""
# Combine all virtual points into a single GeoDataFrame
grid_with_z = pd.concat(virtual_points, ignore_index=True)

# Create a LAS file with laspy
header = laspy.LasHeader(point_format=6, version="1.4")

# Create a LAS file with laspy and add the VLR for CRS
las = laspy.LasData(header)
las.x = grid_with_z.geometry.x
las.y = grid_with_z.geometry.y
las.z = grid_with_z.geometry.z
las.classification = virtual_points_classes * np.ones(len(grid_with_z.index))

# Add CRS information to the VLR
vlr = laspy.vlrs.known.WktCoordinateSystemVlr(crs.to_wkt())
las.vlrs.append(vlr)

# Save the LAS file
output_laz = os.path.join(output_dir, "virtual_points.laz")
with laspy.open(output_laz, mode="w", header=las.header, do_compress=True) as writer:
writer.write_points(las.points)

logging.info(f"Virtual points LAS file saved to {output_laz}")
1 change: 0 additions & 1 deletion lidro/create_virtual_point/stats/knn_distance.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,5 @@ def find_k_nearest_neighbors(points_skeleton: np.array, points_ground_3d: np.arr
# Retrieve the points corresponding to the indices
# Use indices to retrieve the closest 3D points
k_nearest_points = points_ground_3d[indices[0]]
# = points_3d[indices.flatten()]

return k_nearest_points
48 changes: 48 additions & 0 deletions lidro/create_virtual_point/vectors/apply_Z_from_grid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
""" Apply Z from grid
"""
import geopandas as gpd
from shapely import line_locate_point


def calculate_grid_z_with_model(points: gpd.GeoDataFrame, line: gpd.GeoDataFrame, model) -> gpd.GeoDataFrame:
"""Calculate Z with regression model.
If points are not on the line, these points will be projected on this line

Args:
points (gpd.GeoDataFrame): A GeoDataFrame containing the grid points
line (gpd.GeoDataFrame): A GeoDataFrame containing each line from Hydro's Skeleton
model (dict): A dictionary representing the regression model

Returns:
gpd.GeoDataFrame: A GeoDataFrame of initial points, but with a Z.
"""
# Calculate curvilinear abscises for all points of the grid
mdupaysign marked this conversation as resolved.
Show resolved Hide resolved
curvilinear_abs = line_locate_point(line.loc[0, "geometry"], points["geometry"].array, normalized=False)

# Prediction of Z values using the regression model
# Its possible to use non-linear models for prediction
predicted_z = model(curvilinear_abs)

# Generate a new geodataframe, with 3D points
grid_with_z = calculate_grid_z(points, predicted_z)

return grid_with_z


def calculate_grid_z(points: gpd.GeoDataFrame, predicted_z: float) -> gpd.GeoDataFrame:
"""Calculate Z grid

Args:
points (gpd.GeoDataFrame): A GeoDataFrame containing the grid points
predicted_z (float): predicted Z for river

Returns:
gpd.GeoDataFrame: A GeoDataFrame of initial points, but with a Z.
"""
# Generate a new geodataframe, with 3D points
grid_with_z = gpd.GeoDataFrame(
geometry=gpd.GeoSeries().from_xy(points.geometry.x, points.geometry.y, predicted_z), crs=points.crs
)

return grid_with_z
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
""" Create a regula 2D grid
"""
import geopandas as gpd
import numpy as np
import shapely.vectorized


def generate_grid_from_geojson(mask_hydro: gpd.GeoDataFrame, spacing: float = 0.5, margin: float = 0):
"""
Generates a regular 2D grid of evenly spaced points within a polygon defined
in a GeoJSON file.

Args:
mask_hydro (gpd.GeoDataFrame): A GeoDataFrame containing each mask hydro from Hydro's Skeleton
spacing (float, optional): Spacing between the grid points in meters. The default value is 0.5 meter.
margin (int, optional): Margin around mask for grid creation. The default value is 0 meter.

Returns:
geopandas.GeoDataFrame: A GeoDataFrame containing the grid points within the polygon.
"""
# Extract the polygon
polygon = mask_hydro.geometry.unary_union # Combine all polygons into a single shape if there are multiple

if margin:
polygon = polygon.buffer(margin)

# Get the bounds of the polygon
minx, miny, maxx, maxy = polygon.bounds

# Generate the grid points
x_points = np.arange(minx, maxx, spacing)
y_points = np.arange(miny, maxy, spacing)
grid_points = np.meshgrid(x_points, y_points)

# Filter points that are within the polygon
grid_points_in_polygon = shapely.vectorized.contains(polygon, *grid_points)

filtred_x = grid_points[0][grid_points_in_polygon]
filtred_y = grid_points[1][grid_points_in_polygon]

# Convert to GeoDataFrame
points_gs = gpd.points_from_xy(filtred_x, filtred_y)
grid_gdf = gpd.GeoDataFrame(geometry=points_gs, crs=mask_hydro.crs)

return grid_gdf
Loading