def testConstruction(self): a1 = Angle(1.0) a2 = Angle.fromRadians(1.0) a3 = Angle.fromDegrees(57.29577951308232) self.assertEqual(a1, a2) self.assertEqual(a1.asRadians(), 1.0) self.assertEqual(a1, a3) self.assertEqual(a1.asDegrees(), 57.29577951308232)
def index(self, exposure_or_metadata, data_id, database): """Spatially index an |exposure| or |metadata| object. Parameters ---------- exposure_or_metadata : lsst.afw.image.Exposure[DFILU] or lsst.daf.base.PropertySet An afw |exposure| or corresponding |metadata| object. data_id : object An object identifying a single exposure (e.g. as used by the butler). It must be possible to pickle `data_id`. database : sqlite3.Connection or str A connection to (or filename of) a SQLite 3 database. Returns ------- ``None``, unless the |defer_writes| coniguration parameter is ``True``. In that case, an :class:`.ExposureInfo` object containing a pickled data-id and an |encoded| |polygon| is returned. """ # Get a pixel index bounding box for the exposure. if isinstance(exposure_or_metadata, daf_base.PropertySet): md = exposure_or_metadata # Map (LTV1, LTV2) to LSST (x0, y0). LSST convention says that # (x0, y0) is the location of the sub-image origin (the bottom-left # corner) relative to the origin of the parent, whereas LTVi encode # the origin of the parent relative to the origin of the subimage. pixel_bbox = afw_image.bboxFromMetadata(md) wcs = afw_image.makeWcs(md, False) else: pixel_bbox = exposure_or_metadata.getBBox() wcs = exposure_or_metadata.getWcs() # Pad the box by a configurable amount and bail if the result is empty. pixel_bbox.grow(self.config.pad_pixels) if pixel_bbox.isEmpty(): self.log.warn("skipping exposure indexing for dataId=%s: " "empty bounding box", data_id) return corners = [] for c in pixel_bbox.getCorners(): # Convert the box corners from pixel indexes to pixel positions, # and then to sky coordinates. c = wcs.pixelToSky(afw_image.indexToPosition(c.getX()), afw_image.indexToPosition(c.getY())) c = (c.getLongitude().asRadians(), c.getLatitude().asRadians()) # Bail if any coordinate is not finite. if any(math.isinf(x) or math.isnan(x) for x in c): self.log.warn("skipping exposure indexing for dataId=%s: " "NaN or Inf in bounding box sky coordinate(s)" " - bad WCS?", data_id) return # Convert from sky coordinates to unit vectors. corners.append(UnitVector3d(Angle.fromRadians(c[0]), Angle.fromRadians(c[1]))) # Create a convex polygon containing the exposure pixels. When sphgeom # gains support for non-convex polygons, this could be changed to map # exposure.getPolygon() to a spherical equivalent, or to subdivide box # edges in pixel space to account for non linear projections. This # would have higher accuracy than the current approach of connecting # corner sky coordinates with great circles. poly = ConvexPolygon(corners) # Finally, persist or return the exposure information. info = ExposureInfo(pickle.dumps(data_id), poly.encode()) if self.config.defer_writes: return info store_exposure_info(database, self.config.allow_replace, info)