23 __all__ = [
"TractInfo"]
31 from .detail
import makeSkyPolygonFromBBox, Index2D
35 """Information about a tract in a SkyMap sky pixelization
41 tractBuilder : Subclass of `lsst.skymap.BaseTractBuilder`
42 Object used to compute patch geometry.
43 ctrCoord : `lsst.geom.SpherePoint`
44 ICRS sky coordinate of center of inner region of tract; also used as
45 the CRVAL for the WCS.
46 vertexCoordList : `list` of `lsst.geom.SpherePoint`
47 Vertices that define the boundaries of the inner region.
48 tractOverlap : `lsst.geom.Angle`
49 Minimum overlap between adjacent sky tracts; this defines the minimum
50 distance the tract extends beyond the inner region in all directions.
51 wcs : `lsst.afw.image.SkyWcs`
52 WCS for tract. The reference pixel will be shifted as required so that
53 the lower left-hand pixel (index 0,0) has pixel position 0.0, 0.0.
57 The tract is subdivided into rectangular patches. Each patch has the
60 - An inner region defined by an inner bounding box. The inner regions of
61 the patches exactly tile the tract, and all inner regions have the same
62 dimensions. The tract is made larger as required to make this work.
64 - An outer region defined by an outer bounding box. The outer region
65 extends beyond the inner region by patchBorder pixels in all directions,
66 except there is no border at the edges of the tract.
67 Thus patches overlap each other but never extend off the tract.
68 If you do not want any overlap between adjacent patches then set
71 - An index that consists of a pair of integers:
73 * 0 <= x index < numPatches[0]
75 * 0 <= y index < numPatches[1]
77 Patch 0,0 is at the minimum corner of the tract bounding box.
79 - It is not enforced that ctrCoord is the center of vertexCoordList, but
82 def __init__(self, id, tractBuilder, ctrCoord, vertexCoordList, tractOverlap, wcs):
93 def _minimumBoundingBox(self, wcs):
94 """Calculate the minimum bounding box for the tract, given the WCS.
96 The bounding box is created in the frame of the supplied WCS,
97 so that it's OK if the coordinates are negative.
99 We compute the bounding box that holds all the vertices and the
106 minBBoxD.include(wcs.skyToPixel(vertexCoord))
109 angleIncr =
geom.Angle(360.0, geom.degrees) / float(numAngles)
110 for i
in range(numAngles):
111 offAngle = angleIncr * i
112 offCoord = vertexCoord.offset(offAngle, halfOverlap)
113 pixPos = wcs.skyToPixel(offCoord)
114 minBBoxD.include(pixPos)
117 def _finalOrientation(self, bbox, wcs):
118 """Determine the final orientation
120 We offset everything so the lower-left corner is at 0,0
121 and compute the final Wcs.
125 bbox : `lsst.geom.Box2I`
126 Current bounding box.
127 wcs : `lsst.afw.geom.SkyWcs
132 finalBBox : `lsst.geom.Box2I`
133 Revised bounding box.
134 wcs : `lsst.afw.geom.SkyWcs`
140 pixPosOffset =
geom.Extent2D(finalBBox.getMinX() - bbox.getMinX(),
141 finalBBox.getMinY() - bbox.getMinY())
142 wcs = wcs.copyAtShiftedPixelOrigin(pixPosOffset)
143 return finalBBox, wcs
146 """Return a single integer that uniquely identifies
147 the given patch within this tract.
151 patchInfo : `lsst.skymap.PatchInfo`
155 sequentialIndex : `int`
160 """Return a single integer that uniquely identifies
161 the patch index within the tract.
165 index : `lsst.skymap.Index2D`
169 sequentialIndex : `int`
174 """Convert sequential index into patch index (x,y) pair.
178 sequentialIndex : `int`
182 x, y : `lsst.skymap.Index2D`
187 """Find the patch containing the specified coord.
191 coord : `lsst.geom.SpherePoint`
192 ICRS sky coordinate to search for.
196 result : `lsst.skymap.PatchInfo`
197 PatchInfo of patch whose inner bbox contains the specified coord
202 If coord is not in tract or we cannot determine the
203 pixel coordinate (which likely means the coord is off the tract).
206 pixel = self.
wcswcs.skyToPixel(coord)
209 raise LookupError(
"Unable to determine pixel position for coordinate %s" % (coord,))
211 if not self._bbox.
contains(pixelInd):
212 raise LookupError(
"coord %s is not in tract %s" % (coord, self.
tract_idtract_id))
219 """Find patches containing the specified list of coords.
223 coordList : `list` of `lsst.geom.SpherePoint`
224 ICRS sky coordinates to search for.
228 result : `list` of `lsst.skymap.PatchInfo`
229 List of PatchInfo for patches that contain, or may contain, the
230 specified region. The list will be empty if there is no overlap.
236 - This may give incorrect answers on regions that are larger than a
239 - This uses a naive algorithm that may find some patches that do not
240 overlap the region (especially if the region is not a rectangle
241 aligned along patch x,y).
244 for coord
in coordList:
246 pixelPos = self.
wcswcs.skyToPixel(coord)
250 box2D.include(pixelPos)
253 bbox.clip(self._bbox)
257 llPatchInd = tuple(int(bbox.getMin()[i]/self.
patch_inner_dimensionspatch_inner_dimensions[i])
for i
in range(2))
258 urPatchInd = tuple(int(bbox.getMax()[i]/self.
patch_inner_dimensionspatch_inner_dimensions[i])
for i
in range(2))
259 return tuple(self.
getPatchInfogetPatchInfo((xInd, yInd))
260 for xInd
in range(llPatchInd[0], urPatchInd[0]+1)
261 for yInd
in range(llPatchInd[1], urPatchInd[1]+1))
264 """Get bounding box of tract (as an geom.Box2I)
268 bbox = property(getBBox)
271 """Get ICRS sky coordinate of center of tract
272 (as an lsst.geom.SpherePoint)
276 ctr_coord = property(getCtrCoord)
283 tract_id = property(getId)
286 """Get the number of patches in x, y.
290 result : `lsst.skymap.Index2D`
291 The number of patches in x, y
295 num_patches = property(getNumPatches)
300 patch_border = property(getPatchBorder)
303 """Return information for the specified patch.
307 index : `typing.NamedTuple` ['x': `int`, 'y': `int`]
308 Index of patch, as a pair of ints;
309 or a sequential index as returned by getSequentialPatchIndex;
310 negative values are not supported.
314 result : `lsst.skymap.PatchInfo`
315 The patch info for that index.
320 If index is out of range.
325 """Get dimensions of inner region of the patches (all are the same)
329 patch_inner_dimensions = property(getPatchInnerDimensions)
332 """Get minimum overlap of adjacent sky tracts.
336 tract_overlap = property(getTractOverlap)
339 """Get list of ICRS sky coordinates of vertices that define the
340 boundary of the inner region.
344 **warning:** this is not a deep copy.
348 vertex_list = property(getVertexList)
351 """Get inner on-sky region as a sphgeom.ConvexPolygon.
353 skyUnitVectors = [sp.getVector()
for sp
in self.
getVertexListgetVertexList()]
354 return ConvexPolygon.convexHull(skyUnitVectors)
356 inner_sky_polygon = property(getInnerSkyPolygon)
359 """Get outer on-sky region as a sphgeom.ConvexPolygon
363 outer_sky_polygon = property(getOuterSkyPolygon)
370 wcs : `lsst.afw.geom.SkyWcs`
371 The WCS of this tract
375 wcs = property(getWcs)
378 return "TractInfo(id=%s)" % (self.
_id_id,)
381 return "TractInfo(id=%s, ctrCoord=%s)" % (self.
_id_id, self.
_ctrCoord_ctrCoord.getVector())
385 for y
in range(yNum):
386 for x
in range(xNum):
397 """Does this tract contain the coordinate?"""
399 pixel = self.
getWcsgetWcs().skyToPixel(coord)
403 if not np.isfinite(pixel.getX())
or not np.isfinite(pixel.getY()):
410 """Information for a tract specified explicitly.
412 A tract is placed at the explicitly defined coordinates, with the nominated
413 radius. The tracts are square (i.e., the radius is really a half-size).
415 def __init__(self, id, tractBuilder, ctrCoord, radius, tractOverlap, wcs):
419 super(ExplicitTractInfo, self).
__init__(id, tractBuilder, ctrCoord,
420 vertexList, tractOverlap, wcs)
424 finalWcs = self.
getWcsgetWcs()
427 def _minimumBoundingBox(self, wcs):
428 """Calculate the minimum bounding box for the tract, given the WCS, and
429 the nominated radius.
434 pixPos = wcs.skyToPixel(cornerCoord)
A class representing an angle.
A floating-point coordinate rectangle geometry.
An integer coordinate rectangle.
Reports arguments outside the domain of an operation.
Reports errors that are due to events beyond the control of the program.
def __init__(self, id, tractBuilder, ctrCoord, radius, tractOverlap, wcs)
def getTractOverlap(self)
def _finalOrientation(self, bbox, wcs)
def getSequentialPatchIndex(self, patchInfo)
def findPatchList(self, coordList)
def getPatchInfo(self, index)
def __getitem__(self, index)
def __init__(self, id, tractBuilder, ctrCoord, vertexCoordList, tractOverlap, wcs)
def getInnerSkyPolygon(self)
def getSequentialPatchIndexFromPair(self, index)
def contains(self, coord)
def getPatchIndexPair(self, sequentialIndex)
def getPatchInnerDimensions(self)
def getOuterSkyPolygon(self)
def findPatch(self, coord)
def _minimumBoundingBox(self, wcs)
def makeSkyPolygonFromBBox(bbox, wcs)