Coverage for python / lsst / images / _intersection_bounds.py: 61%

29 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-05-06 08:48 +0000

1# This file is part of lsst-images. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# Use of this source code is governed by a 3-clause BSD-style 

10# license that can be found in the LICENSE file. 

11 

12from __future__ import annotations 

13 

14__all__ = ("IntersectionBounds",) 

15 

16from typing import TYPE_CHECKING, Any, Self, cast, overload 

17 

18import numpy as np 

19 

20from ._geom import Bounds, Box 

21 

22if TYPE_CHECKING: 

23 from ._concrete_bounds import SerializableBounds 

24 

25 

26class IntersectionBounds: 

27 """An implementation of the `Bounds` protocol that acts as a lazy 

28 intersection of two other `Bounds` objects. 

29 """ 

30 

31 def __init__(self, a: Bounds, b: Bounds): 

32 self._a = a 

33 self._b = b 

34 

35 @property 

36 def bbox(self) -> Box: 

37 """The intersection of the bounding boxes of the operands (`.Box`).""" 

38 from ._concrete_bounds import _intersect_box_box 

39 

40 return _intersect_box_box(self._a.bbox, self._b.bbox) 

41 

42 @overload 

43 def contains(self, *, x: int, y: int) -> bool: ... 43 ↛ exitline 43 didn't return from function 'contains' because

44 

45 @overload 

46 def contains(self, *, x: np.ndarray, y: np.ndarray) -> np.ndarray: ... 46 ↛ exitline 46 didn't return from function 'contains' because

47 

48 def contains(self, *, x: Any, y: Any) -> Any: 

49 """Test whether these bounds contain one or more points. 

50 

51 Parameters 

52 ---------- 

53 x 

54 One or more integer X coordinates to test for containment. 

55 If an array, an array of results will be returned. 

56 y 

57 One or more integer Y coordinates to test for containment. 

58 If an array, an array of results will be returned. 

59 

60 Returns 

61 ------- 

62 `bool` | `numpy.ndarray` 

63 If ``x`` and ``y`` are both scalars, a single `bool` value. If 

64 ``x`` and ``y`` are arrays, a boolean array with their broadcasted 

65 shape. 

66 """ 

67 return np.logical_and(self._a.contains(x=x, y=y), self._b.contains(x=x, y=y)) 

68 

69 def intersection(self, other: Bounds) -> Bounds: 

70 """Compute the intersection of this bounds object with another. 

71 

72 Notes 

73 ----- 

74 Bounds intersection is guaranteed to raise `NoOverlapError` when the 

75 operand bounding boxes do not overlap, but it may return a bounds 

76 implementation that contains no points in more complex cases. 

77 """ 

78 from ._concrete_bounds import _intersect_ib 

79 

80 return _intersect_ib(self, other) 

81 

82 def serialize(self) -> SerializableBounds: 

83 """Convert a bounds instance into a serializable object.""" 

84 # Cyclic dependencies prevent IntersectionBoundsSerializationModel 

85 # from being defined here. 

86 from ._concrete_bounds import IntersectionBoundsSerializationModel 

87 

88 return IntersectionBoundsSerializationModel(a=self._a.serialize(), b=self._b.serialize()) 

89 

90 @classmethod 

91 def deserialize(cls, serialized: SerializableBounds) -> Self: 

92 """Convert a serialized bounds object into its in-memory form.""" 

93 from ._concrete_bounds import deserialize_bounds 

94 

95 return cast(Self, deserialize_bounds(serialized))