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

fix split overlap error #85

Merged
merged 2 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
43 changes: 26 additions & 17 deletions fractopo/general.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Contains general calculation and plotting tools.
"""

import json
import logging
import math
Expand Down Expand Up @@ -30,6 +31,7 @@
from shapely import prepared, wkb
from shapely.affinity import scale
from shapely.geometry import (
GeometryCollection,
LineString,
MultiLineString,
MultiPoint,
Expand Down Expand Up @@ -99,18 +101,20 @@
DEFAULT_FRACTOPO_CACHE_PATH = Path(".cache/fractopo")

JOBLIB_CACHE = Memory(
os.environ.get("FRACTOPO_CACHE_PATH", DEFAULT_FRACTOPO_CACHE_PATH)
# Disk caching is disabled in pytest execution by setting an environment
# variable FRACTOPO_DISABLE_CACHE to a non-zero string (i.e. "1") However,
# it can be enabled even in tests by setting FRACTOPO_DISABLE_CACHE to 0
if os.environ.get("FRACTOPO_DISABLE_CACHE") in (None, "0") else None,
(
os.environ.get("FRACTOPO_CACHE_PATH", DEFAULT_FRACTOPO_CACHE_PATH)
# Disk caching is disabled in pytest execution by setting an environment
# variable FRACTOPO_DISABLE_CACHE to a non-zero string (i.e. "1") However,
# it can be enabled even in tests by setting FRACTOPO_DISABLE_CACHE to 0
if os.environ.get("FRACTOPO_DISABLE_CACHE") in (None, "0")
else None
),
verbose=int(os.environ.get("FRACTOPO_JOBLIB_CACHE_VERBOSITY", 0)),
)


@dataclass
class ProcessResult:

"""
Dataclass for multiprocessing result parsing.
"""
Expand All @@ -122,7 +126,6 @@ class ProcessResult:

@unique
class Col(Enum):

"""
GeoDataFrame column names for attributes.
"""
Expand Down Expand Up @@ -162,7 +165,6 @@ def fallback_aggregation(values) -> str:

@unique
class Aggregator(Enum):

"""
Define how to aggregate during subsample aggragation.
"""
Expand All @@ -173,7 +175,6 @@ class Aggregator(Enum):

@dataclass
class ParamInfo:

"""
Parameter with name and metadata.
"""
Expand All @@ -188,7 +189,6 @@ class ParamInfo:

@unique
class Param(Enum):

"""
Column names for geometric and topological parameters.

Expand Down Expand Up @@ -719,7 +719,7 @@ def point_to_xy(point: Point) -> Tuple[float, float]:

@JOBLIB_CACHE.cache
def determine_general_nodes(
traces: Union[gpd.GeoSeries, gpd.GeoDataFrame]
traces: Union[gpd.GeoSeries, gpd.GeoDataFrame],
) -> Tuple[List[Tuple[Point, ...]], List[Tuple[Point, ...]]]:
"""
Determine points of intersection and endpoints of given trace LineStrings.
Expand Down Expand Up @@ -876,6 +876,15 @@ def determine_valid_intersection_points(
log.error(f"Expected geom ({geom.wkt}) not to be of type LineString.")
elif isinstance(geom, MultiLineString):
log.error(f"Expected geom ({geom.wkt}) not to be of type MultiLineString.")
elif isinstance(geom, GeometryCollection):
for collection_geom in geom.geoms:
if isinstance(collection_geom, Point):
valid_interaction_points.append(collection_geom)
else:
log.warning(
f"Expected collection_geom ({collection_geom.wkt}) to be of type Point"
)

else:
raise TypeError(
"Expected (Multi)Point or (Multi)LineString geometries"
Expand Down Expand Up @@ -905,7 +914,7 @@ def line_intersection_to_points(first: LineString, second: LineString) -> List[P


def flatten_tuples(
list_of_tuples: List[Tuple[Any, ...]]
list_of_tuples: List[Tuple[Any, ...]],
) -> Tuple[List[int], List[Any]]:
"""
Flatten collection of tuples and return index references.
Expand Down Expand Up @@ -1353,7 +1362,7 @@ def dissolve_multi_part_traces(traces: gpd.GeoSeries) -> gpd.GeoSeries:


def dissolve_multi_part_traces(
traces: Union[gpd.GeoDataFrame, gpd.GeoSeries]
traces: Union[gpd.GeoDataFrame, gpd.GeoSeries],
) -> Union[gpd.GeoDataFrame, gpd.GeoSeries]:
"""
Dissolve MultiLineStrings in GeoDataFrame or GeoSeries.
Expand Down Expand Up @@ -1510,7 +1519,7 @@ def within_bounds(


def geom_bounds(
geom: Union[LineString, Polygon, MultiPolygon]
geom: Union[LineString, Polygon, MultiPolygon],
) -> Tuple[float, float, float, float]:
"""
Get LineString or Polygon bounds.
Expand Down Expand Up @@ -1539,7 +1548,7 @@ def geom_bounds(


def total_bounds(
geodata: Union[gpd.GeoSeries, gpd.GeoDataFrame]
geodata: Union[gpd.GeoSeries, gpd.GeoDataFrame],
) -> Tuple[float, float, float, float]:
"""
Get total bounds of geodataset.
Expand All @@ -1561,7 +1570,7 @@ def total_bounds(


def pygeos_spatial_index(
geodataset: Union[gpd.GeoDataFrame, gpd.GeoSeries]
geodataset: Union[gpd.GeoDataFrame, gpd.GeoSeries],
) -> PyGEOSSTRTreeIndex:
"""
Get PyGEOSSTRTreeIndex from geopandas dataset.
Expand Down Expand Up @@ -2065,7 +2074,7 @@ def check_for_z_coordinates(geodata: Union[gpd.GeoDataFrame, gpd.GeoSeries]) ->


def remove_z_coordinates_from_geodata(
geodata: Union[gpd.GeoDataFrame, gpd.GeoSeries]
geodata: Union[gpd.GeoDataFrame, gpd.GeoSeries],
) -> Union[gpd.GeoDataFrame, gpd.GeoSeries]:
"""
Remove Z-coordinates from geometries in geopandasgeodata.
Expand Down
12 changes: 10 additions & 2 deletions fractopo/tval/trace_validation_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Direct utilities of trace validation.
"""

import logging
from typing import List, Optional, Tuple

Expand Down Expand Up @@ -93,7 +94,7 @@ def segment_within_buffer(
min_x=min_x,
min_y=min_y,
max_x=max_x,
max_y=max_y
max_y=max_y,
# *end, min_x, min_y, max_x, max_y
):
ls = LineString([start, end])
Expand Down Expand Up @@ -262,7 +263,14 @@ def is_underlapping(
"""
Determine if a geom is underlapping.
"""
split_results = list(split(geom, trace).geoms)
try:
split_results = list(split(geom, trace).geoms)
except ValueError:
log.warning(
"Expected split to work between geom and trace. Probably overlapping geometries.",
exc_info=True,
)
return None
if len(split_results) == 1:
# Do not intersect
return True
Expand Down
26 changes: 10 additions & 16 deletions fractopo/tval/trace_validators.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Contains Validator classes which each have their own error to handle and mark.
"""

import logging
from typing import Any, List, Optional, Set, Tuple, Type, Union

Expand Down Expand Up @@ -35,7 +36,6 @@


class BaseValidator:

"""
Base validator that all classes inherit.

Expand All @@ -62,7 +62,6 @@ def validation_method(**_) -> bool:


class GeomTypeValidator(BaseValidator):

"""
Validates the geometry type.

Expand Down Expand Up @@ -117,7 +116,6 @@ def validation_method(geom: Any, **_) -> bool:


class MultiJunctionValidator(BaseValidator):

"""
Validates that junctions consists of a maximum of two lines crossing.
"""
Expand Down Expand Up @@ -178,7 +176,6 @@ def determine_faulty_junctions(


class VNodeValidator(BaseValidator):

"""
Finds V-nodes within trace data.
"""
Expand Down Expand Up @@ -229,7 +226,6 @@ def determine_v_nodes(


class MultipleCrosscutValidator(BaseValidator):

"""
Find traces that cross-cut each other multiple times.

Expand Down Expand Up @@ -281,7 +277,6 @@ def validation_method(


class UnderlappingSnapValidator(BaseValidator):

"""
Find snapping errors of underlapping traces.

Expand Down Expand Up @@ -353,19 +348,23 @@ def validation_method(
snap_threshold_error_multiplier,
)
if is_ul_result is None:
raise ValueError("Expected is_ul_result to not be None.")
if is_ul_result:
if geom.overlaps(trace):
cls.ERROR = StackedTracesValidator.ERROR
else:
raise ValueError(
"Expected None is_ul_result to indicate overlapping traces."
)
elif is_ul_result:
# Underlapping
cls.ERROR = cls._UNDERLAPPING
return False
cls.ERROR = cls._OVERLAPPING
else:
cls.ERROR = cls._OVERLAPPING
return False

return True


class TargetAreaSnapValidator(BaseValidator):

"""
Validator for traces that underlap the target area.
"""
Expand Down Expand Up @@ -520,7 +519,6 @@ def is_candidate_underlapping(


class GeomNullValidator(BaseValidator):

"""
Validate the geometry for NULL GEOMETRY errors.
"""
Expand Down Expand Up @@ -557,7 +555,6 @@ def validation_method(geom: Any, **_) -> bool:


class StackedTracesValidator(BaseValidator):

"""
Find stacked traces and small triangle intersections.
"""
Expand Down Expand Up @@ -651,7 +648,6 @@ def validation_method(


class SimpleGeometryValidator(BaseValidator):

"""
Use shapely is_simple and is_ring attributes to validate LineString.

Expand All @@ -669,7 +665,6 @@ def validation_method(geom: LineString, **_) -> bool:


class SharpCornerValidator(BaseValidator):

"""
Find sharp cornered traces.
"""
Expand Down Expand Up @@ -724,7 +719,6 @@ def validation_method(


class EmptyTargetAreaValidator(BaseValidator):

"""
Stub validator for empty target area.

Expand Down
Loading
Loading