|
6 | 6 | from osgeo import osr
|
7 | 7 | from pyproj import CRS
|
8 | 8 | from pyproj.exceptions import CRSError
|
| 9 | +from shapely.ops import split |
9 | 10 |
|
10 | 11 | import threedigrid_builder
|
11 | 12 | from threedigrid_builder.base import (
|
@@ -881,10 +882,51 @@ def sort(self):
|
881 | 882 | if self.surface_maps is not None:
|
882 | 883 | self.surface_maps.cci[:] = np.take(new_node_ids, self.surface_maps.cci)
|
883 | 884 |
|
884 |
| - def apply_cutlines(self, obstacles): |
885 |
| - """Treat obstacles as cutlines""" |
886 |
| - |
887 |
| - pass |
| 885 | + def apply_cutlines(self, cutlines): |
| 886 | + """Treat obstacles as cutlines for now""" |
| 887 | + # TODO: add unit test for multiline cutting |
| 888 | + |
| 889 | + # Map of node idx to fragment list |
| 890 | + node_fragment = {} |
| 891 | + |
| 892 | + for node_idx in range(len(self.nodes)): |
| 893 | + # create the geometry of the corresponding cell |
| 894 | + node_polygon = shapely.box( |
| 895 | + self.nodes.bounds[node_idx][0], |
| 896 | + self.nodes.bounds[node_idx][1], |
| 897 | + self.nodes.bounds[node_idx][2], |
| 898 | + self.nodes.bounds[node_idx][3], |
| 899 | + ccw=False, |
| 900 | + ) |
| 901 | + assert node_polygon.is_valid |
| 902 | + |
| 903 | + # check for intersection with cutlines |
| 904 | + fragment_collection = [ |
| 905 | + node_polygon |
| 906 | + ] # list of all fragments of the cell (each cutline can cause new fragments), initially the cell itself |
| 907 | + |
| 908 | + for cutline_linestring in cutlines.the_geom: |
| 909 | + new_fragments = [] # List of fragments that have been recut |
| 910 | + # iterate over the fragments |
| 911 | + for fragment in fragment_collection: |
| 912 | + intermediate_fragments = split(fragment, cutline_linestring) |
| 913 | + |
| 914 | + # According to docs: If the splitter does not split the geometry, a collection with a single geometry equal to the input geometry is returned. |
| 915 | + # Note that the original input geometry does not need to be returned, we'll explicitely add that one again. |
| 916 | + if len(intermediate_fragments.geoms) == 1: |
| 917 | + assert intermediate_fragments.geoms[0].equals(fragment) |
| 918 | + new_fragments.append(fragment) |
| 919 | + elif len(intermediate_fragments.geoms) > 1: |
| 920 | + for intermediate_fragment in intermediate_fragments.geoms: |
| 921 | + assert intermediate_fragment.geom_type == "Polygon" |
| 922 | + new_fragments.append(intermediate_fragment) |
| 923 | + else: |
| 924 | + raise RuntimeError("No resulting geometry") |
| 925 | + |
| 926 | + # set new fragment collection and move to the next cutline |
| 927 | + fragment_collection = new_fragments |
| 928 | + |
| 929 | + node_fragment[node_idx] = fragment_collection |
888 | 930 |
|
889 | 931 | def finalize(self):
|
890 | 932 | """Finalize the Grid, computing and setting derived attributes"""
|
|
0 commit comments