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

Forward-merge branch-23.04 to branch-23.06 #1041

Merged
merged 1 commit into from
Apr 6, 2023
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
12 changes: 10 additions & 2 deletions python/cuspatial/cuspatial/core/binops/intersection.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Copyright (c) 2023, NVIDIA CORPORATION.

from typing import TYPE_CHECKING

import cudf
from cudf.core.column import arange, build_list_column

Expand All @@ -8,15 +10,17 @@
)
from cuspatial.core._column.geocolumn import GeoColumn
from cuspatial.core._column.geometa import Feature_Enum, GeoMeta
from cuspatial.core.geoseries import GeoSeries
from cuspatial.utils.column_utils import (
contains_only_linestrings,
empty_geometry_column,
)

if TYPE_CHECKING:
from cuspatial.core.geoseries import GeoSeries


def pairwise_linestring_intersection(
linestrings1: GeoSeries, linestrings2: GeoSeries
linestrings1: "GeoSeries", linestrings2: "GeoSeries"
):
"""
Compute the intersection of two GeoSeries of linestrings.
Expand Down Expand Up @@ -45,6 +49,8 @@ def pairwise_linestring_intersection(
the intersection results came from.
"""

from cuspatial.core.geoseries import GeoSeries

if len(linestrings1) == 0 and len(linestrings2) == 0:
return (
cudf.Series([0]),
Expand Down Expand Up @@ -97,6 +103,8 @@ def pairwise_linestring_intersection(
meta = GeoMeta(
{"input_types": types_buffer, "union_offsets": offset_buffer}
)
from cuspatial.core.geoseries import GeoSeries

geometries = GeoSeries(
GeoColumn(
(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
from cuspatial.core.binpreds.feature_crosses import ( # NOQA F401
DispatchDict as CROSSES_DISPATCH,
)
from cuspatial.core.binpreds.feature_disjoint import ( # NOQA F401
DispatchDict as DISJOINT_DISPATCH,
)
from cuspatial.core.binpreds.feature_equals import ( # NOQA F401
DispatchDict as EQUALS_DISPATCH,
)
Expand All @@ -26,6 +29,9 @@
from cuspatial.core.binpreds.feature_overlaps import ( # NOQA F401
DispatchDict as OVERLAPS_DISPATCH,
)
from cuspatial.core.binpreds.feature_touches import ( # NOQA F401
DispatchDict as TOUCHES_DISPATCH,
)
from cuspatial.core.binpreds.feature_within import ( # NOQA F401
DispatchDict as WITHIN_DISPATCH,
)
28 changes: 26 additions & 2 deletions python/cuspatial/cuspatial/core/binpreds/binpred_interface.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# Copyright (c) 2022-2023, NVIDIA CORPORATION.

from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Tuple

from cudf import Series

from cuspatial.utils.binpred_utils import _false_series

if TYPE_CHECKING:
from cuspatial.core.geoseries import GeoSeries

Expand Down Expand Up @@ -139,6 +141,19 @@ def __str__(self):
return self.__repr__()


class IntersectsOpResult(OpResult):
"""Result of an Intersection binary predicate operation."""

def __init__(self, result: Tuple):
self.result = result

def __repr__(self):
return f"OpResult(result={self.result})"

def __str__(self):
return self.__repr__()


class BinPred:
"""Base class for binary predicates. This class is an abstract base class
and can not be instantiated directly. `BinPred` is the base class that
Expand Down Expand Up @@ -241,7 +256,7 @@ def __init__(self, **kwargs):
0 False
dtype: bool
"""
self.kwargs = kwargs
self.config = BinPredConfig(**kwargs)

def __call__(self, lhs: "GeoSeries", rhs: "GeoSeries") -> Series:
"""System call for the binary predicate. Calls the _call method,
Expand Down Expand Up @@ -441,3 +456,12 @@ class NotImplementedPredicate(BinPred):

def __init__(self, *args, **kwargs):
raise NotImplementedError


class ImpossiblePredicate(BinPred):
"""There are many combinations that are impossible. This is the base class
to simply return a series of False values for these cases.
"""

def _preprocess(self, lhs, rhs):
return _false_series(len(lhs))
31 changes: 20 additions & 11 deletions python/cuspatial/cuspatial/core/binpreds/feature_contains.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,11 @@
from cuspatial.core._column.geocolumn import GeoColumn
from cuspatial.core.binpreds.binpred_interface import (
BinPred,
BinPredConfig,
ContainsOpResult,
NotImplementedPredicate,
PreprocessorResult,
)
from cuspatial.core.binpreds.contains import contains_properly
from cuspatial.core.binpreds.feature_equals import (
DispatchDict as EQUALS_DISPATCH_DICT,
)
from cuspatial.utils.binpred_utils import (
LineString,
MultiPoint,
Expand Down Expand Up @@ -57,7 +53,7 @@ def __init__(self, **kwargs):
right-hand GeoSeries. If False, the feature will be compared in a
1:1 fashion with the corresponding feature in the other GeoSeries.
"""
self.config = BinPredConfig(**kwargs)
super().__init__(**kwargs)
self.config.allpairs = kwargs.get("allpairs", False)

def _preprocess(self, lhs, rhs):
Expand Down Expand Up @@ -307,6 +303,11 @@ class PolygonComplexContains(ContainsPredicateBase):
This class is shared by the Polygon*Contains classes that use
a non-points object on the right hand side: MultiPoint, LineString,
MultiLineString, Polygon, and MultiPolygon.

Used by:
(Polygon, MultiPoint)
(Polygon, LineString)
(Polygon, Polygon)
"""

def _postprocess(self, lhs, rhs, preprocessor_output):
Expand Down Expand Up @@ -334,12 +335,20 @@ def _postprocess(self, lhs, rhs, preprocessor_output):
return final_result


class PointPointContains(ContainsPredicateBase):
class ContainsByIntersection(BinPred):
"""Point types are contained only by an intersection test.

Used by:
(Point, Point)
(LineString, Point)
"""

def _preprocess(self, lhs, rhs):
"""PointPointContains that simply calls the equals predicate on the
points."""
from cuspatial.core.binpreds.binpred_dispatch import (
INTERSECTS_DISPATCH,
)

predicate = EQUALS_DISPATCH_DICT[(lhs.column_type, rhs.column_type)](
predicate = INTERSECTS_DISPATCH[(lhs.column_type, rhs.column_type)](
align=self.config.align
)
return predicate(lhs, rhs)
Expand All @@ -348,15 +357,15 @@ def _preprocess(self, lhs, rhs):
"""DispatchDict listing the classes to use for each combination of
left and right hand side types. """
DispatchDict = {
(Point, Point): PointPointContains,
(Point, Point): ContainsByIntersection,
(Point, MultiPoint): NotImplementedPredicate,
(Point, LineString): NotImplementedPredicate,
(Point, Polygon): NotImplementedPredicate,
(MultiPoint, Point): NotImplementedPredicate,
(MultiPoint, MultiPoint): NotImplementedPredicate,
(MultiPoint, LineString): NotImplementedPredicate,
(MultiPoint, Polygon): NotImplementedPredicate,
(LineString, Point): NotImplementedPredicate,
(LineString, Point): ContainsByIntersection,
(LineString, MultiPoint): NotImplementedPredicate,
(LineString, LineString): NotImplementedPredicate,
(LineString, Polygon): NotImplementedPredicate,
Expand Down
8 changes: 6 additions & 2 deletions python/cuspatial/cuspatial/core/binpreds/feature_covers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

from cuspatial.core.binpreds.binpred_interface import NotImplementedPredicate
from cuspatial.core.binpreds.feature_equals import EqualsPredicateBase
from cuspatial.core.binpreds.feature_intersects import (
LineStringPointIntersects,
PointLineStringIntersects,
)
from cuspatial.utils.binpred_utils import (
LineString,
MultiPoint,
Expand Down Expand Up @@ -35,13 +39,13 @@ class CoversPredicateBase(EqualsPredicateBase):
DispatchDict = {
(Point, Point): CoversPredicateBase,
(Point, MultiPoint): NotImplementedPredicate,
(Point, LineString): NotImplementedPredicate,
(Point, LineString): PointLineStringIntersects,
(Point, Polygon): CoversPredicateBase,
(MultiPoint, Point): NotImplementedPredicate,
(MultiPoint, MultiPoint): NotImplementedPredicate,
(MultiPoint, LineString): NotImplementedPredicate,
(MultiPoint, Polygon): NotImplementedPredicate,
(LineString, Point): NotImplementedPredicate,
(LineString, Point): LineStringPointIntersects,
(LineString, MultiPoint): NotImplementedPredicate,
(LineString, LineString): NotImplementedPredicate,
(LineString, Polygon): CoversPredicateBase,
Expand Down
14 changes: 12 additions & 2 deletions python/cuspatial/cuspatial/core/binpreds/feature_crosses.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Copyright (c) 2023, NVIDIA CORPORATION.

from cuspatial.core.binpreds.binpred_interface import NotImplementedPredicate
from cuspatial.core.binpreds.binpred_interface import (
ImpossiblePredicate,
NotImplementedPredicate,
)
from cuspatial.core.binpreds.feature_equals import EqualsPredicateBase
from cuspatial.utils.binpred_utils import (
LineString,
Expand All @@ -15,6 +18,13 @@ class CrossesPredicateBase(EqualsPredicateBase):
"""Base class for binary predicates that are defined in terms of a
the equals binary predicate. For example, a Point-Point Crosses
predicate is defined in terms of a Point-Point Equals predicate.

Used by:
(Point, Polygon)
(Polygon, Point)
(Polygon, MultiPoint)
(Polygon, LineString)
(Polygon, Polygon)
"""

pass
Expand All @@ -35,7 +45,7 @@ def _preprocess(self, lhs, rhs):
(MultiPoint, MultiPoint): NotImplementedPredicate,
(MultiPoint, LineString): NotImplementedPredicate,
(MultiPoint, Polygon): NotImplementedPredicate,
(LineString, Point): NotImplementedPredicate,
(LineString, Point): ImpossiblePredicate,
(LineString, MultiPoint): NotImplementedPredicate,
(LineString, LineString): NotImplementedPredicate,
(LineString, Polygon): NotImplementedPredicate,
Expand Down
76 changes: 76 additions & 0 deletions python/cuspatial/cuspatial/core/binpreds/feature_disjoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Copyright (c) 2023, NVIDIA CORPORATION.

from cuspatial.core.binpreds.binpred_interface import (
BinPred,
NotImplementedPredicate,
)
from cuspatial.core.binpreds.feature_intersects import (
IntersectsPredicateBase,
PointLineStringIntersects,
)
from cuspatial.utils.binpred_utils import (
LineString,
MultiPoint,
Point,
Polygon,
)


class ContainsDisjoint(BinPred):
def _preprocess(self, lhs, rhs):
"""Disjoint is the opposite of contains, so just implement contains
and then negate the result.

Used by:
(Point, Point)
(Point, Polygon)
(Polygon, Point)
"""
from cuspatial.core.binpreds.binpred_dispatch import CONTAINS_DISPATCH

predicate = CONTAINS_DISPATCH[(lhs.column_type, rhs.column_type)](
align=self.config.align
)
return ~predicate(lhs, rhs)


class PointLineStringDisjoint(PointLineStringIntersects):
def _postprocess(self, lhs, rhs, op_result):
"""Disjoint is the opposite of intersects, so just implement intersects
and then negate the result."""
result = super()._postprocess(lhs, rhs, op_result)
return ~result


class LineStringPointDisjoint(PointLineStringDisjoint):
def _preprocess(self, lhs, rhs):
"""Swap ordering for Intersects."""
return super()._preprocess(rhs, lhs)


class LineStringLineStringDisjoint(IntersectsPredicateBase):
def _postprocess(self, lhs, rhs, op_result):
"""Disjoint is the opposite of intersects, so just implement intersects
and then negate the result."""
result = super()._postprocess(lhs, rhs, op_result)
return ~result


DispatchDict = {
(Point, Point): ContainsDisjoint,
(Point, MultiPoint): NotImplementedPredicate,
(Point, LineString): PointLineStringDisjoint,
(Point, Polygon): ContainsDisjoint,
(MultiPoint, Point): NotImplementedPredicate,
(MultiPoint, MultiPoint): NotImplementedPredicate,
(MultiPoint, LineString): NotImplementedPredicate,
(MultiPoint, Polygon): NotImplementedPredicate,
(LineString, Point): LineStringPointDisjoint,
(LineString, MultiPoint): NotImplementedPredicate,
(LineString, LineString): LineStringLineStringDisjoint,
(LineString, Polygon): NotImplementedPredicate,
(Polygon, Point): ContainsDisjoint,
(Polygon, MultiPoint): NotImplementedPredicate,
(Polygon, LineString): NotImplementedPredicate,
(Polygon, Polygon): NotImplementedPredicate,
}
17 changes: 16 additions & 1 deletion python/cuspatial/cuspatial/core/binpreds/feature_equals.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ class EqualsPredicateBase(BinPred, Generic[GeoSeries]):
"""Base class for binary predicates that are defined in terms of the equals
basic predicate. `EqualsPredicateBase` implements utility functions that
are used within many equals-related binary predicates.

Used by:
(Point, Point)
(Point, Polygon)
(LineString, Polygon)
(Polygon, Point)
(Polygon, MultiPoint)
(Polygon, LineString)
(Polygon, Polygon)
"""

def _offset_equals(self, lhs, rhs):
Expand Down Expand Up @@ -320,6 +329,12 @@ def _compute_predicate(self, lhs, rhs, preprocessor_result):
)


class LineStringPointEquals(EqualsPredicateBase):
def _preprocess(self, lhs, rhs):
"""A LineString cannot be equal to a point. So, return False."""
return _false_series(len(lhs))


"""DispatchDict for Equals operations."""
DispatchDict = {
(Point, Point): EqualsPredicateBase,
Expand All @@ -330,7 +345,7 @@ def _compute_predicate(self, lhs, rhs, preprocessor_result):
(MultiPoint, MultiPoint): MultiPointMultiPointEquals,
(MultiPoint, LineString): NotImplementedPredicate,
(MultiPoint, Polygon): NotImplementedPredicate,
(LineString, Point): NotImplementedPredicate,
(LineString, Point): LineStringPointEquals,
(LineString, MultiPoint): NotImplementedPredicate,
(LineString, LineString): LineStringLineStringEquals,
(LineString, Polygon): EqualsPredicateBase,
Expand Down
Loading