fractopo.branches_and_nodes module

Functions for extracting branches and nodes from trace maps.

branches_and_nodes is the main entrypoint.

fractopo.branches_and_nodes.additional_snapping_func(trace, idx, additional_snapping)

Insert points into LineStrings to make sure trace abutting trace.

E.g.

>>> trace = LineString([(0, 0), (1, 0), (2, 0), (3, 0)])
>>> idx = 0
>>> point = Point(2.25, 0.1)
>>> additional_snapping = [
...     (0, point),
... ]
:rtype: :sphinx_autodoc_typehints_type:`\:py\:class\:\`\~shapely.geometry.linestring.LineString\``
>>> additional_snapping_func(trace, idx, additional_snapping).wkt
'LINESTRING (0 0, 1 0, 2 0, 2.25 0.1, 3 0)'

When idx doesn’t match -> no additional snapping

>>> trace = LineString([(0, 0), (1, 0), (2, 0), (3, 0)])
>>> idx = 1
>>> point = Point(2.25, 0.1)
>>> additional_snapping = [
...     (0, point),
... ]
>>> additional_snapping_func(trace, idx, additional_snapping).wkt
'LINESTRING (0 0, 1 0, 2 0, 3 0)'
fractopo.branches_and_nodes.angle_to_point(point, nearest_point, comparison_point)

Calculate the angle between two vectors.

Vectors are made from the given points: Both vectors have the same first point, nearest_point, and second point is either point or comparison_point.

Returns angle in degrees.

E.g.

>>> point = Point(1, 1)
>>> nearest_point = Point(0, 0)
>>> comparison_point = Point(-1, 1)
:rtype: :sphinx_autodoc_typehints_type:`\:py\:class\:\`float\``
>>> angle_to_point(point, nearest_point, comparison_point)
90.0
>>> point = Point(1, 1)
>>> nearest_point = Point(0, 0)
>>> comparison_point = Point(-1, 2)
>>> angle_to_point(point, nearest_point, comparison_point)
71.56505117707799
fractopo.branches_and_nodes.determine_branch_identity(number_of_i_nodes, number_of_xy_nodes, number_of_e_nodes)

Determine the identity of a branch.

Is based on the amount of I-, XY- and E-nodes and returns it as a string.

E.g.

Return type:

str

>>> determine_branch_identity(2, 0, 0)
'I - I'
>>> determine_branch_identity(1, 1, 0)
'C - I'
>>> determine_branch_identity(1, 0, 1)
'I - E'
fractopo.branches_and_nodes.determine_insert_approach(nearest_point_idx, trace_point_dists, snap_threshold, point, nearest_point)

Determine if to insert or replace point.

fractopo.branches_and_nodes.filter_non_unique_traces(traces, snap_threshold)

Filter out traces that are not unique.

Return type:

GeoSeries

fractopo.branches_and_nodes.get_branch_identities(branches, nodes, node_identities, snap_threshold)

Determine the types of branches for a GeoSeries of branches.

i.e. C-C, C-I or I-I, + (C-E, E-E, I-E)

>>> branches = gpd.GeoSeries(
...     [
...         LineString([(1, 1), (2, 2)]),
...         LineString([(2, 2), (3, 3)]),
...         LineString([(3, 0), (2, 2)]),
...         LineString([(2, 2), (-2, 5)]),
...     ]
... )
>>> nodes = gpd.GeoSeries(
...     [
...         Point(2, 2),
...         Point(1, 1),
...         Point(3, 3),
...         Point(3, 0),
...         Point(-2, 5),
...     ]
... )
>>> node_identities = ["X", "I", "I", "I", "E"]
>>> snap_threshold = 0.001
:rtype: :sphinx_autodoc_typehints_type:`\:py\:class\:\`\~typing.List\`\\ \\\[\:py\:class\:\`str\`\]`
>>> get_branch_identities(branches, nodes, node_identities, snap_threshold)
['C - I', 'C - I', 'C - I', 'C - E']
fractopo.branches_and_nodes.insert_point_to_linestring(trace, point, snap_threshold)

Insert/modify point to trace LineString.

The point location is determined to fit into the LineString without changing the geometrical order of LineString vertices (which only makes sense if LineString is sublinear.)

TODO: Does not work for 2.5D geometries (Z-coordinates). Z-coordinates will be lost.

E.g.

>>> trace = LineString([(0, 0), (1, 0), (2, 0), (3, 0)])
>>> point = Point(1.25, 0.1)
:rtype: :sphinx_autodoc_typehints_type:`\:py\:class\:\`\~shapely.geometry.linestring.LineString\``
>>> insert_point_to_linestring(trace, point, 0.01).wkt
'LINESTRING (0 0, 1 0, 1.25 0.1, 2 0, 3 0)'
>>> trace = LineString([(0, 0), (1, 0), (2, 0), (3, 0)])
>>> point = Point(2.25, 0.1)
>>> insert_point_to_linestring(trace, point, 0.01).wkt
'LINESTRING (0 0, 1 0, 2 0, 2.25 0.1, 3 0)'
fractopo.branches_and_nodes.is_endpoint_close_to_boundary(endpoint, areas, snap_threshold)

Check if endpoint is within snap_threshold of areas boundaries.

Return type:

bool

fractopo.branches_and_nodes.node_identities_from_branches(branches, areas, snap_threshold)

Resolve node identities from branch data.

>>> branches_list = [
...     LineString([(0, 0), (1, 1)]),
...     LineString([(2, 2), (1, 1)]),
...     LineString([(2, 0), (1, 1)]),
... ]
>>> area_polygon = Polygon([(-5, -5), (-5, 5), (5, 5), (5, -5)])
>>> branches = gpd.GeoSeries(branches_list)
>>> areas = gpd.GeoSeries([area_polygon])
>>> snap_threshold = 0.001
>>> nodes, identities = node_identities_from_branches(
...     branches, areas, snap_threshold
... )
>>> [node.wkt for node in nodes]
['POINT (0 0)', 'POINT (1 1)', 'POINT (2 2)', 'POINT (2 0)']
:rtype: :sphinx_autodoc_typehints_type:`\:py\:data\:\`\~typing.Tuple\`\\ \\\[\:py\:class\:\`\~typing.List\`\\ \\\[\:py\:class\:\`\~shapely.geometry.point.Point\`\]\, \:py\:class\:\`\~typing.List\`\\ \\\[\:py\:class\:\`str\`\]\]`
>>> identities
['I', 'Y', 'I', 'I']
fractopo.branches_and_nodes.node_identity(endpoint, idx, areas, endpoints_geoseries, endpoints_spatial_index, snap_threshold)

Determine node identity of endpoint.

Return type:

str

fractopo.branches_and_nodes.report_snapping_loop(loops, allowed_loops)

Report snapping looping.

fractopo.branches_and_nodes.resolve_trace_candidates(trace, idx, traces_spatial_index, traces, snap_threshold)

Resolve spatial index intersection to actual intersection candidates.

Return type:

List[LineString]

fractopo.branches_and_nodes.simple_snap(trace, trace_candidates, snap_threshold)

Modify conditionally trace to snap to any of trace_candidates.

E.g.

>>> trace = LineString([(0, 0), (1, 0), (2, 0), (3, 0)])
>>> trace_candidates = gpd.GeoSeries(
...     [LineString([(3.0001, -3), (3.0001, 0), (3, 3)])]
... )
>>> snap_threshold = 0.001
>>> snapped = simple_snap(trace, trace_candidates, snap_threshold)
:rtype: :sphinx_autodoc_typehints_type:`\:py\:data\:\`\~typing.Tuple\`\\ \\\[\:py\:class\:\`\~shapely.geometry.linestring.LineString\`\, \:py\:class\:\`bool\`\]`
>>> snapped[0].wkt, snapped[1]
('LINESTRING (0 0, 1 0, 2 0, 3.0001 0)', True)

Do not snap overlapping.

>>> trace = LineString([(0, 0), (1, 0), (2, 0), (3.0002, 0)])
>>> trace_candidates = gpd.GeoSeries(
...     [LineString([(3.0001, -3), (3.0001, 0), (3, 3)])]
... )
>>> snap_threshold = 0.001
>>> snapped = simple_snap(trace, trace_candidates, snap_threshold)
>>> snapped[0].wkt, snapped[1]
('LINESTRING (0 0, 1 0, 2 0, 3.0002 0)', False)
fractopo.branches_and_nodes.snap_others_to_trace(idx, trace, snap_threshold, traces, traces_spatial_index, areas, final_allowed_loop=False)

Determine whether and how to snap trace to traces.

E.g.

Trace gets new coordinates to snap other traces to it:

>>> idx = 0
>>> trace = LineString([(0, 0), (1, 0), (2, 0), (3, 0)])
>>> snap_threshold = 0.001
>>> traces = [trace, LineString([(1.5, 3), (1.5, 0.00001)])]
>>> traces_spatial_index = gpd.GeoSeries(traces).sindex
>>> areas = None
>>> snapped = snap_others_to_trace(
...     idx, trace, snap_threshold, traces, traces_spatial_index, areas
... )
:rtype: :sphinx_autodoc_typehints_type:`\:py\:data\:\`\~typing.Tuple\`\\ \\\[\:py\:class\:\`\~shapely.geometry.linestring.LineString\`\, \:py\:class\:\`bool\`\]`
>>> snapped[0].wkt, snapped[1]
('LINESTRING (0 0, 1 0, 1.5 1e-05, 2 0, 3 0)', True)

Trace itself is not snapped by snap_others_to_trace:

>>> idx = 0
>>> trace = LineString([(0, 0), (1, 0), (2, 0), (3, 0)])
>>> snap_threshold = 0.001
>>> traces = [trace, LineString([(3.0001, -3), (3.0001, 0), (3, 3)])]
>>> traces_spatial_index = gpd.GeoSeries(traces).sindex
>>> areas = None
>>> snapped = snap_others_to_trace(
...     idx, trace, snap_threshold, traces, traces_spatial_index, areas
... )
>>> snapped[0].wkt, snapped[1]
('LINESTRING (0 0, 1 0, 2 0, 3 0)', False)
fractopo.branches_and_nodes.snap_trace_simple(idx, trace, snap_threshold, traces, traces_spatial_index, final_allowed_loop=False)

Determine whether and how to perform simple snap.

Return type:

Tuple[LineString, bool]

fractopo.branches_and_nodes.snap_trace_to_another(trace_endpoints, another, snap_threshold)

Add point to another trace to snap trace to end at another trace.

I.e. modifies and returns another

Return type:

Tuple[LineString, bool]

fractopo.branches_and_nodes.snap_traces(traces, snap_threshold, areas=None, final_allowed_loop=False)

Snap traces to end exactly at other traces.

Return type:

Tuple[List[LineString], bool]