23__all__ = [
"TractInfo"]
26from deprecated.sphinx
import deprecated
32from .detail
import makeSkyPolygonFromBBox, Index2D
36 """Information about a tract in a SkyMap sky pixelization
42 tractBuilder : Subclass of `lsst.skymap.BaseTractBuilder`
43 Object used to compute patch geometry.
44 ctrCoord : `lsst.geom.SpherePoint`
45 ICRS sky coordinate of center of inner region of tract; also used as
46 the CRVAL for the WCS.
47 vertexCoordList : `list` of `lsst.geom.SpherePoint`
48 Vertices that define the boundaries of the inner region.
49 tractOverlap : `lsst.geom.Angle`
50 Minimum overlap between adjacent sky tracts; this defines the minimum
51 distance the tract extends beyond the inner region in all directions.
52 wcs : `lsst.afw.image.SkyWcs`
53 WCS for tract. The reference pixel will be shifted as required so that
54 the lower left-hand pixel (index 0,0) has pixel position 0.0, 0.0.
55 innerBoxCorners : `list` [`lsst.sphgeom.LonLat`], optional
56 If set then the ``inner_sky_region`` will be a `lsst.sphgeom.Box` with
57 these corners as opposed to a `lsst.sphgeom.ConvexPolygon` built from
62 The tract is subdivided into rectangular patches. Each patch has the
65 - An inner region defined by an inner bounding box. The inner regions of
66 the patches exactly tile the tract, and all inner regions have the same
67 dimensions. The tract is made larger as required to make this work.
69 - An outer region defined by an outer bounding box. The outer region
70 extends beyond the inner region by patchBorder pixels in all directions,
71 except there is no border at the edges of the tract.
72 Thus patches overlap each other but never extend off the tract.
73 If you do not want any overlap between adjacent patches then set
76 - An index that consists of a pair of integers:
78 * 0 <= x index < numPatches[0]
80 * 0 <= y index < numPatches[1]
82 Patch 0,0 is at the minimum corner of the tract bounding box.
84 - It is not enforced that ctrCoord is the center of vertexCoordList, but
87 def __init__(self, id, tractBuilder, ctrCoord, vertexCoordList, tractOverlap, wcs, innerBoxCorners=None):
100 """Calculate the minimum bounding box for the tract, given the WCS.
102 The bounding box is created in the frame of the supplied WCS,
103 so that it's OK if the coordinates are negative.
105 We compute the bounding box that holds all the vertices and the
112 minBBoxD.include(wcs.skyToPixel(vertexCoord))
115 angleIncr =
geom.Angle(360.0, geom.degrees) / float(numAngles)
116 for i
in range(numAngles):
117 offAngle = angleIncr * i
118 offCoord = vertexCoord.offset(offAngle, halfOverlap)
119 pixPos = wcs.skyToPixel(offCoord)
120 minBBoxD.include(pixPos)
124 """Determine the final orientation
126 We offset everything so the lower-left corner is at 0,0
127 and compute the final Wcs.
131 bbox : `lsst.geom.Box2I`
132 Current bounding box.
133 wcs : `lsst.afw.geom.SkyWcs
138 finalBBox : `lsst.geom.Box2I`
139 Revised bounding box.
140 wcs : `lsst.afw.geom.SkyWcs`
146 pixPosOffset =
geom.Extent2D(finalBBox.getMinX() - bbox.getMinX(),
147 finalBBox.getMinY() - bbox.getMinY())
148 wcs = wcs.copyAtShiftedPixelOrigin(pixPosOffset)
149 return finalBBox, wcs
152 """Return a single integer that uniquely identifies
153 the given patch within this tract.
157 patchInfo : `lsst.skymap.PatchInfo`
161 sequentialIndex : `int`
166 """Return a single integer that uniquely identifies
167 the patch index within the tract.
171 index : `lsst.skymap.Index2D`
175 sequentialIndex : `int`
180 """Convert sequential index into patch index (x,y) pair.
184 sequentialIndex : `int`
188 x, y : `lsst.skymap.Index2D`
193 """Find the patch containing the specified coord.
197 coord : `lsst.geom.SpherePoint`
198 ICRS sky coordinate to search for.
202 result : `lsst.skymap.PatchInfo`
203 PatchInfo of patch whose inner bbox contains the specified coord
208 Raised if coord is not in tract or we cannot determine the
209 pixel coordinate (which likely means the coord is off the tract).
212 pixel = self.
wcs.skyToPixel(coord)
215 raise LookupError(
"Unable to determine pixel position for coordinate %s" % (coord,))
218 raise LookupError(
"coord %s is not in tract %s" % (coord, self.
tract_id))
225 """Find patches containing the specified list of coords.
229 coordList : `list` of `lsst.geom.SpherePoint`
230 ICRS sky coordinates to search for.
234 result : `list` of `lsst.skymap.PatchInfo`
235 List of PatchInfo for patches that contain, or may contain, the
236 specified region. The list will be empty if there is no overlap.
242 - This may give incorrect answers on regions that are larger than a
245 - This uses a naive algorithm that may find some patches that do not
246 overlap the region (especially if the region is not a rectangle
247 aligned along patch x,y).
250 for coord
in coordList:
252 pixelPos = self.
wcs.skyToPixel(coord)
257 box2D.include(pixelPos)
260 bbox.clip(self.
_bbox)
267 for xInd
in range(llPatchInd[0], urPatchInd[0]+1)
268 for yInd
in range(llPatchInd[1], urPatchInd[1]+1))
271 """Get bounding box of tract (as an geom.Box2I)
275 bbox = property(getBBox)
278 """Get ICRS sky coordinate of center of tract
279 (as an lsst.geom.SpherePoint)
283 ctr_coord = property(getCtrCoord)
290 tract_id = property(getId)
293 """Get the number of patches in x, y.
297 result : `lsst.skymap.Index2D`
298 The number of patches in x, y
302 num_patches = property(getNumPatches)
307 patch_border = property(getPatchBorder)
310 """Return information for the specified patch.
314 index : `typing.NamedTuple` ['x': `int`, 'y': `int`]
315 Index of patch, as a pair of ints;
316 or a sequential index as returned by getSequentialPatchIndex;
317 negative values are not supported.
321 result : `lsst.skymap.PatchInfo`
322 The patch info for that index.
327 Raised if index is out of range.
332 """Get dimensions of inner region of the patches (all are the same)
336 patch_inner_dimensions = property(getPatchInnerDimensions)
339 """Get minimum overlap of adjacent sky tracts.
343 tract_overlap = property(getTractOverlap)
346 """Get list of ICRS sky coordinates of vertices that define the
347 boundary of the inner region.
351 **warning:** this is not a deep copy.
355 vertex_list = property(getVertexList)
358 @deprecated(reason="getInnerSkyPolygon()/inner_sky_polygon has been deprecated
in favor of
"
359 "inner_sky_region, and will be removed after v28.",
360 category=FutureWarning, version=28)
362 """Get inner on-sky region as a sphgeom.ConvexPolygon.
364 skyUnitVectors = [sp.getVector()
for sp
in self.
getVertexList()]
365 return ConvexPolygon.convexHull(skyUnitVectors)
367 inner_sky_polygon = property(getInnerSkyPolygon)
370 """Get inner on-sky region.
375 skyUnitVectors = [sp.getVector()
for sp
in self.
getVertexList()]
376 return ConvexPolygon.convexHull(skyUnitVectors)
378 inner_sky_region = property(getInnerSkyRegion)
381 """Get outer on-sky region as a sphgeom.ConvexPolygon
383 return makeSkyPolygonFromBBox(bbox=self.
getBBox(), wcs=self.
getWcs())
385 outer_sky_polygon = property(getOuterSkyPolygon)
392 wcs : `lsst.afw.geom.SkyWcs`
393 The WCS of this tract
397 wcs = property(getWcs)
400 return "TractInfo(id=%s)" % (self.
_id,)
403 return "TractInfo(id=%s, ctrCoord=%s)" % (self.
_id, self.
_ctrCoord.getVector())
407 for y
in range(yNum):
408 for x
in range(xNum):
419 """Does this tract contain the coordinate?"""
421 pixel = self.
getWcs().skyToPixel(coord)
425 if not np.isfinite(pixel.getX())
or not np.isfinite(pixel.getY()):
432 """Information for a tract specified explicitly.
434 A tract is placed at the explicitly defined coordinates, with the nominated
435 radius. The tracts are square (i.e., the radius is really a half-size).
441 tractBuilder : Subclass of `lsst.skymap.BaseTractBuilder`
442 Object used to compute patch geometry.
443 ctrCoord : `lsst.geom.SpherePoint`
444 ICRS sky coordinate of center of inner region of tract; also used as
445 the CRVAL for the WCS.
446 radius : `lsst.geom.Angle`
448 tractOverlap : `lsst.geom.Angle`
449 Minimum overlap between adjacent sky tracts; this defines the minimum
450 distance the tract extends beyond the inner region in all directions.
451 wcs : `lsst.afw.image.SkyWcs`
452 WCS for tract. The reference pixel will be shifted as required so that
453 the lower left-hand pixel (index 0,0) has pixel position 0.0, 0.0.
454 innerBoxCorners : `list` [`lsst.sphgeom.LonLat`], optional
455 If set then the ``inner_sky_region`` will be a `lsst.sphgeom.Box` with
456 these corners as oppsed to a `lsst.sphgeom.ConvexPolygon` built from
459 def __init__(self, id, tractBuilder, ctrCoord, radius, tractOverlap, wcs, innerBoxCorners=None):
464 super(ExplicitTractInfo, self).
__init__(
471 innerBoxCorners=innerBoxCorners,
480 """Calculate the minimum bounding box for the tract, given the WCS, and
481 the nominated radius.
486 pixPos = wcs.skyToPixel(cornerCoord)
__init__(self, id, tractBuilder, ctrCoord, radius, tractOverlap, wcs, innerBoxCorners=None)
_minimumBoundingBox(self, wcs)
getPatchInnerDimensions(self)
getSequentialPatchIndexFromPair(self, index)
getSequentialPatchIndex(self, patchInfo)
getPatchInfo(self, index)
_finalOrientation(self, bbox, wcs)
getPatchIndexPair(self, sequentialIndex)
findPatchList(self, coordList)
__init__(self, id, tractBuilder, ctrCoord, vertexCoordList, tractOverlap, wcs, innerBoxCorners=None)
_minimumBoundingBox(self, wcs)