Skip to content
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
2 changes: 2 additions & 0 deletions src/shapepy/bool2d/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from .base import Future
from .boolean import (
clean_bool2d,
contains_bool2d,
intersect_bool2d,
invert_bool2d,
unite_bool2d,
Expand All @@ -21,5 +22,6 @@
Future.clean = clean_bool2d
Future.convert = from_any
Future.xor = xor_bool2d
Future.contains = contains_bool2d

Is.lazy = is_lazy
16 changes: 15 additions & 1 deletion src/shapepy/bool2d/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ def __repr__(self) -> str: # pragma: no cover
def __hash__(self):
raise NotImplementedError

@debug("shapepy.bool2d.base")
def __contains__(self, other: SubSetR2) -> bool:
return Future.contains(self, other)

def clean(self) -> SubSetR2:
"""
Cleans the subset, changing its representation into a simpler form
Expand Down Expand Up @@ -272,7 +276,7 @@ def __xor__(self, other: SubSetR2) -> SubSetR2:
return Future.convert(other)

def __contains__(self, other: SubSetR2) -> bool:
return self is other
return self is Future.convert(other)

def __str__(self) -> str:
return "EmptyShape"
Expand Down Expand Up @@ -454,3 +458,13 @@ def clean(subset: SubSetR2) -> SubSetR2:
in the `shapepy.bool2d.boolean.py` file
"""
raise NotImplementedError

@staticmethod
def contains(subseta: SubSetR2, subsetb: SubSetR2) -> bool:
"""
Checks if subsetb is contained in subseta

This function is overrided by a function defined
in the `shapepy.bool2d.boolean.py` file
"""
raise NotImplementedError
50 changes: 50 additions & 0 deletions src/shapepy/bool2d/boolean.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@
from ..tools import CyclicContainer, Is, NotExpectedError
from . import boolalg
from .base import EmptyShape, SubSetR2, WholeShape
from .config import Config
from .convert import from_any
from .curve import SingleCurve
from .lazy import LazyAnd, LazyNot, LazyOr, RecipeLazy, is_lazy
from .point import SinglePoint
from .shape import (
ConnectedShape,
DisjointShape,
Expand Down Expand Up @@ -171,6 +175,52 @@ def clean_bool2d_not(subset: LazyNot) -> SubSetR2:
raise NotImplementedError(f"Missing typo: {type(inverted)}")


@debug("shapepy.bool2d.boolean")
def contains_bool2d(subseta: SubSetR2, subsetb: SubSetR2) -> bool:
"""
Checks if B is inside A

Parameters
----------
subseta: SubSetR2
The subset A
subsetb: SubSetR2
The subset B

Return
------
bool
The result if B is inside A
"""
subseta = from_any(subseta)
subsetb = from_any(subsetb)
if Is.instance(subseta, EmptyShape) or Is.instance(subsetb, WholeShape):
return subseta is subsetb
if Is.instance(subseta, WholeShape) or Is.instance(subsetb, EmptyShape):
return True
if Is.instance(subseta, (ConnectedShape, LazyAnd)):
return all(subsetb in s for s in subseta)
if Is.instance(subsetb, (DisjointShape, LazyOr)):
return all(s in subseta for s in subsetb)
if Is.instance(subseta, LazyNot) and Is.instance(subsetb, LazyNot):
return contains_bool2d(~subsetb, ~subseta)
if Is.instance(subseta, SimpleShape):
if Is.instance(subsetb, (SinglePoint, SingleCurve, SimpleShape)):
return subsetb in subseta
if Is.instance(subsetb, ConnectedShape):
return ~subseta in ~subsetb
if not Config.auto_clean:
raise ValueError(
f"Needs clean to evaluate: {type(subseta)}, {type(subsetb)}"
)
return subsetb.clean() in subseta.clean()
if Is.instance(subseta, (LazyOr, DisjointShape)):
return any(subsetb in s for s in subseta) # Needs improvement
raise NotImplementedError(
f"Invalid typos: {type(subseta)}, {type(subsetb)}"
)


class Boolalg:
"""Static methods to clean a SubSetR2 using algebraic simplifier"""

Expand Down
2 changes: 2 additions & 0 deletions src/shapepy/bool2d/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class Config:
"inv": True,
}

auto_clean = True


@contextmanager
def disable_auto_clean():
Expand Down
25 changes: 9 additions & 16 deletions src/shapepy/bool2d/shape.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from __future__ import annotations

from copy import copy
from typing import Iterable, Set, Tuple, Union
from typing import Iterable, Iterator, Set, Tuple, Union

from ..geometry.box import Box
from ..geometry.jordancurve import JordanCurve
Expand All @@ -19,7 +19,7 @@
from ..scalar.angle import Angle
from ..scalar.reals import Real
from ..tools import Is, To
from .base import EmptyShape, Future, SubSetR2
from .base import Future, SubSetR2
from .curve import SingleCurve
from .density import (
Density,
Expand Down Expand Up @@ -133,20 +133,15 @@ def invert(self) -> SimpleShape:
self.__jordancurve.invert()
return self

@debug("shapepy.bool2d.shape")
def __contains__(self, other: SubSetR2) -> bool:
if not Is.instance(other, SubSetR2):
other = Future.convert(other)
if Is.instance(other, SinglePoint):
return self.__contains_point(other)
if Is.instance(other, SingleCurve):
return self.__contains_curve(other)
if Is.instance(other, SimpleShape):
return self.__contains_simple(other)
if Is.instance(other, ConnectedShape):
return ~self in ~other
if Is.instance(other, DisjointShape):
return all(o in self for o in other.subshapes)
return Is.instance(other, EmptyShape)
return super().__contains__(other)

def __contains_point(self, point: SinglePoint) -> bool:
point = Future.convert(point)
Expand Down Expand Up @@ -261,6 +256,9 @@ def __eq__(self, other: SubSetR2) -> bool:
def __hash__(self):
return hash(self.area)

def __iter__(self) -> Iterator[SimpleShape]:
yield from self.subshapes

@property
def jordans(self) -> Tuple[JordanCurve, ...]:
"""Jordan curves that defines the shape
Expand Down Expand Up @@ -308,9 +306,6 @@ def subshapes(self, simples: Iterable[SimpleShape]):
raise TypeError
self.__subshapes = simples

def __contains__(self, other) -> bool:
return all(other in s for s in self.subshapes)

def move(self, vector: Point2D) -> JordanCurve:
vector = To.point(vector)
for subshape in self.subshapes:
Expand Down Expand Up @@ -376,10 +371,8 @@ def __deepcopy__(self, memo):
subshapes = tuple(map(copy, self.subshapes))
return DisjointShape(subshapes)

def __contains__(self, other: SubSetR2) -> bool:
if Is.instance(other, DisjointShape):
return all(o in self for o in other.subshapes)
return any(other in s for s in self.subshapes)
def __iter__(self) -> Iterator[Union[SimpleShape, ConnectedShape]]:
yield from self.subshapes

@property
def area(self) -> Real:
Expand Down
49 changes: 49 additions & 0 deletions tests/bool2d/test_lazy.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,54 @@ def test_density():
assert abs(float(density) - value) < 1e-9


@pytest.mark.order(33)
@pytest.mark.dependency(
depends=[
"test_begin",
"test_invert",
"test_unite",
"test_intersect",
"test_hash",
"test_xor",
"test_transformation_move",
"test_transformation_scale",
"test_transformation_rotate",
"test_printing",
"test_clean",
]
)
def test_contains():
small = Primitive.square(side=1)
bigsq = Primitive.square(side=2)
assert small in bigsq
assert LazyNot(bigsq) in LazyNot(small)

inters = LazyAnd([small, bigsq])
assert small in inters
assert bigsq not in inters
assert inters in inters
assert LazyNot(bigsq) in LazyNot(inters)
assert (0, 0) in small
assert (0, 0) in bigsq
assert (0, 0) in inters
assert (1, 1) not in inters

union = LazyOr([small, bigsq])
assert small in union
assert bigsq in union
assert union in union
assert (0, 0) in small
assert (0, 0) in bigsq
assert (0, 0) in union
assert (1, 1) in union

left = Primitive.square(side=4, center=(-1, 0))
righ = Primitive.square(side=4, center=(1, 0))
union = LazyOr([left, righ])
assert left in union
assert righ in union


@pytest.mark.order(33)
@pytest.mark.dependency(
depends=[
Expand All @@ -409,6 +457,7 @@ def test_density():
"test_hash",
"test_copy",
"test_density",
"test_contains",
]
)
def test_all():
Expand Down
Loading