diff --git a/regions/core/compound.py b/regions/core/compound.py index 1aedd179..916b432b 100644 --- a/regions/core/compound.py +++ b/regions/core/compound.py @@ -29,16 +29,21 @@ class CompoundSkyRegion(SkyRegion): Represents the logical combination of two regions in sky coordinates. """ - def __init__(self, region1, operator, region2): + def __init__(self, region1, region2, operator): self.region1 = region1 self.region2 = region2 self.operator = operator - def __contains__(self, skycoord): - raise NotImplementedError("") + def contains(self, skycoord): + return self.operator(self.region1.contains(skycoord), + self.region2.contains(skycoord)) def to_pixel(self, wcs, mode='local', tolerance=None): raise NotImplementedError("") def __repr__(self): - return "({0} {1} {2})".format(self.region1, self.operator, self.region2) + return "({0}\n{1}\n{2})".format(self.region1, self.operator, self.region2) + + @property + def area(self): + raise NotImplementedError("") \ No newline at end of file diff --git a/regions/core/core.py b/regions/core/core.py index 803a88e4..f04afc28 100644 --- a/regions/core/core.py +++ b/regions/core/core.py @@ -41,6 +41,10 @@ def __or__(self, other): def __xor__(self, other): return self.symmetric_difference(other) + def __contains__(self, coord): + # Todo: only works for scalar cases, test for this? + return self.contains(coord) + @six.add_metaclass(abc.ABCMeta) class PixelRegion(Region): @@ -72,7 +76,7 @@ def union(self, other): return CompoundPixelRegion(self, other, operator.or_) @abc.abstractmethod - def __contains__(self, pixcoord): + def contains(self, pixcoord): """ Checks whether a position or positions fall inside the region. @@ -192,7 +196,7 @@ def union(self, other): return CompoundSkyRegion(self, other, operator.or_) @abc.abstractmethod - def __contains__(self, skycoord): + def contains(self, skycoord): """ Checks whether a position or positions fall inside the region. diff --git a/regions/core/tests/__init__.py b/regions/core/tests/__init__.py new file mode 100644 index 00000000..2ff7e2a6 --- /dev/null +++ b/regions/core/tests/__init__.py @@ -0,0 +1,4 @@ +# Licensed under a 3-clause BSD style license - see LICENSE.rst +""" +This packages contains affiliated package tests. +""" diff --git a/regions/core/tests/coveragerc b/regions/core/tests/coveragerc new file mode 100644 index 00000000..bec7c291 --- /dev/null +++ b/regions/core/tests/coveragerc @@ -0,0 +1,31 @@ +[run] +source = {packagename} +omit = + {packagename}/_astropy_init* + {packagename}/conftest* + {packagename}/cython_version* + {packagename}/setup_package* + {packagename}/*/setup_package* + {packagename}/*/*/setup_package* + {packagename}/tests/* + {packagename}/*/tests/* + {packagename}/*/*/tests/* + {packagename}/version* + +[report] +exclude_lines = + # Have to re-enable the standard pragma + pragma: no cover + + # Don't complain about packages we have installed + except ImportError + + # Don't complain if tests don't hit assertions + raise AssertionError + raise NotImplementedError + + # Don't complain about script hooks + def main\(.*\): + + # Ignore branches that don't pertain to this version of Python + pragma: py{ignore_python_version} \ No newline at end of file diff --git a/regions/core/tests/test_compound.py b/regions/core/tests/test_compound.py new file mode 100644 index 00000000..1b79d7de --- /dev/null +++ b/regions/core/tests/test_compound.py @@ -0,0 +1,46 @@ +import astropy.units as u +from astropy.coordinates import SkyCoord + +from regions.shapes import CircleSkyRegion + + +def test_compound(): + + skycoord1 = SkyCoord(0 * u.deg, 0 * u.deg, frame='galactic') + c1 = CircleSkyRegion(skycoord1, 1 * u.deg) + + skycoord2 = SkyCoord(1 * u.deg, 1 * u.deg, frame='galactic') + c2 = CircleSkyRegion(skycoord2, 0.5 * u.deg) + + test_coord1 = SkyCoord(1.2 * u.deg, 1.2 * u.deg, frame='galactic') + test_coord2 = SkyCoord(0.5 * u.deg, 0.5 * u.deg, frame='galactic') + test_coord3 = SkyCoord(0.7 * u.deg, 0.7 * u.deg, frame='galactic') + test_coord4 = SkyCoord(2 * u.deg, 5 * u.deg, frame='galactic') + + assert test_coord1 in c2 and test_coord1 not in c1 + assert test_coord2 not in c2 and test_coord2 in c1 + assert test_coord3 in c1 and test_coord3 in c2 + assert test_coord4 not in c2 and test_coord4 not in c1 + + coords = SkyCoord([test_coord1, test_coord2, test_coord3, test_coord4], frame='galactic') + + union = c1 | c2 + assert (union.contains(coords) == [True, True, True, False]).all() + + intersection = c1 & c2 + assert (intersection.contains(coords) == [False, False, True, False]).all() + + diff = c1 ^ c2 + assert (diff.contains(coords) == [True, True, False, False]).all() + + + c3 = CircleSkyRegion(test_coord4, 0.1 * u.deg) + + union = c1 | c2 | c3 + assert (union.contains(coords) == [True, True, True, True]).all() + + intersection = c1 & c2 & c3 + assert (intersection.contains(coords) == [False, False, False, False]).all() + + diff = c1 ^ c2 ^ c3 + assert (diff.contains(coords) == [True, True, False, True]).all() diff --git a/regions/shapes/circle.py b/regions/shapes/circle.py index 64733e61..5548c663 100644 --- a/regions/shapes/circle.py +++ b/regions/shapes/circle.py @@ -35,7 +35,7 @@ def __init__(self, center, radius, meta=None, visual=None): def area(self): return math.pi * self.radius ** 2 - def __contains__(self, pixcoord): + def contains(self, pixcoord): return np.hypot(pixcoord.x - self.center.x, pixcoord.y - self.center.y) < self.radius @@ -87,8 +87,14 @@ def __init__(self, center, radius, meta=None, visual=None): def area(self): return math.pi * self.radius ** 2 - def __contains__(self, skycoord): - return self.center.separation(skycoord) + def contains(self, skycoord): + return self.center.separation(skycoord) < self.radius + + def __repr__(self): + clsnm = self.__class__.__name__ + coord = self.center + rad = self.radius + return '{clsnm}\nCenter:{coord}\nRadius:{rad}'.format(**locals()) def to_pixel(self, mywcs, mode='local', tolerance=None): """ diff --git a/regions/shapes/ellipse.py b/regions/shapes/ellipse.py index 67b5b074..9600825d 100644 --- a/regions/shapes/ellipse.py +++ b/regions/shapes/ellipse.py @@ -36,7 +36,7 @@ def __init__(self, center, minor, major, angle=0. * u.deg, meta=None, def area(self): return math.pi * self.minor * self.major - def __contains__(self, pixcoord): + def contains(self, pixcoord): # TODO: needs to be implemented raise NotImplementedError("") @@ -85,7 +85,7 @@ def area(self): # TODO: needs to be implemented raise NotImplementedError("") - def __contains__(self, skycoord): + def contains(self, skycoord): # TODO: needs to be implemented raise NotImplementedError("") diff --git a/regions/shapes/point.py b/regions/shapes/point.py index 90a9af90..b6b4cef3 100644 --- a/regions/shapes/point.py +++ b/regions/shapes/point.py @@ -26,7 +26,7 @@ def __init__(self, center, meta=None, visual=None): def area(self): return 0 - def __contains__(self, pixcoord): + def contains(self, pixcoord): return False def to_shapely(self): @@ -62,7 +62,7 @@ def __init__(self, center, meta=None, visual=None): def area(self): return 0 - def __contains__(self, skycoord): + def contains(self, skycoord): return False def to_pixel(self, wcs, mode='local', tolerance=None): diff --git a/regions/shapes/polygon.py b/regions/shapes/polygon.py index ba7d0f76..6c7bd5e4 100644 --- a/regions/shapes/polygon.py +++ b/regions/shapes/polygon.py @@ -22,7 +22,7 @@ def area(self): # TODO: needs to be implemented raise NotImplementedError("") - def __contains__(self, pixcoord): + def contains(self, pixcoord): # TODO: needs to be implemented raise NotImplementedError("") @@ -39,7 +39,6 @@ def to_mask(self, mode='center'): raise NotImplementedError("") - class PolygonSkyRegion(SkyRegion): """ A polygon in sky coordinates. @@ -61,7 +60,7 @@ def area(self): # TODO: needs to be implemented raise NotImplementedError("") - def __contains__(self, skycoord): + def contains(self, skycoord): # TODO: needs to be implemented raise NotImplementedError("") diff --git a/regions/shapes/rectangle.py b/regions/shapes/rectangle.py index 562d2bc8..3b8a2a1a 100644 --- a/regions/shapes/rectangle.py +++ b/regions/shapes/rectangle.py @@ -33,7 +33,7 @@ def __init__(self, center, height, width, angle=0 * u.deg, meta=None, visual=Non def area(self): return self.width * self.height - def __contains__(self, pixcoord): + def contains(self, pixcoord): # TODO: needs to be implemented raise NotImplementedError("") @@ -81,7 +81,7 @@ def __init__(self, center, height, width, angle=0 * u.deg, meta=None, visual=Non def area(self): return self.width * self.height - def __contains__(self, skycoord): + def contains(self, skycoord): # TODO: needs to be implemented raise NotImplementedError("") diff --git a/regions/shapes/tests/test_circle.py b/regions/shapes/tests/test_circle.py index e4fe73fa..ea6a714d 100644 --- a/regions/shapes/tests/test_circle.py +++ b/regions/shapes/tests/test_circle.py @@ -26,6 +26,7 @@ def test_init_sky(): # Todo : restructure test to use same circle everywhere +# see https://github.com/astropy/regions/pull/20 @pytest.mark.skipif('not HAS_MATPLOTLIB') def test_plot(): import matplotlib.pyplot as plt