def testPixel(self): """Verifies that the center of pixel P is mapped back to P. """ for R in (64, 65): qs = skypix.QuadSpherePixelization(R, 0.0) for i in qs: c = geom.sphericalCoords(qs.getCenter(i)) pixelId = qs.pixel(math.radians(c[0]), math.radians(c[1])) self.assertEqual(i, pixelId)
def pointsOnCircle(c, r, n): """Generates an n-gon lying on the circle with center c and radius r. Vertices are equi-spaced. """ points = [] c = geom.cartesianUnitVector(c) north, east = geom.northEast(c) sr = math.sin(math.radians(r)) cr = math.cos(math.radians(r)) aoff = random.uniform(0.0, 2.0 * math.pi) for i in xrange(n): a = 2.0 * i * math.pi / n sa = math.sin(a + aoff) ca = math.cos(a + aoff) p = (ca * north[0] + sa * east[0], ca * north[1] + sa * east[1], ca * north[2] + sa * east[2]) points.append( geom.sphericalCoords((cr * c[0] + sr * p[0], cr * c[1] + sr * p[1], cr * c[2] + sr * p[2]))) return points
def pointsOnCircle(c, r, n): """Generates an n-gon lying on the circle with center c and radius r. Vertices are equi-spaced. """ points = [] c = geom.cartesianUnitVector(c) north, east = geom.northEast(c) sr = math.sin(math.radians(r)) cr = math.cos(math.radians(r)) aoff = random.uniform(0.0, 2.0 * math.pi) for i in xrange(n): a = 2.0 * i * math.pi / n sa = math.sin(a + aoff) ca = math.cos(a + aoff) p = (ca * north[0] + sa * east[0], ca * north[1] + sa * east[1], ca * north[2] + sa * east[2]) points.append(geom.sphericalCoords((cr * c[0] + sr * p[0], cr * c[1] + sr * p[1], cr * c[2] + sr * p[2]))) return points
def testPrune2(self): coarseRes = 3 subdiv = 6 fineRes = coarseRes * subdiv coarseQs = skypix.QuadSpherePixelization(coarseRes, 0.0) fineQs = skypix.QuadSpherePixelization(fineRes, 0.0) for skyTileId in coarseQs: root, cx, cy = coarseQs.coords(skyTileId) skyTile = utils.PT1SkyTile(coarseRes, root, cx, cy, skyTileId) for cid in coarseQs: root2, cx2, cy2 = coarseQs.coords(cid) for x in xrange(cx2 * subdiv, (cx2 + 1) * subdiv): for y in xrange(cy2 * subdiv, (cy2 + 1) * subdiv): pixelCenter = geom.sphericalCoords( fineQs.getCenter(fineQs.id(root2, x, y))) s = afwCoord.IcrsCoord(pixelCenter[0] * degrees, pixelCenter[1] * degrees) if root == root2 and cx == cx2 and cy == cy2: self.assertEqual(skyTile.contains(s), True) else: self.assertEqual(skyTile.contains(s), False)
def findWcsCoveringSkyTile(skyPixelization, skyTileId, imageRes): """Computes and returns a TAN WCS such that a 2D image with the given WCS and the following properties completely covers the sky-tile with the given pixel id: - NAXIS1/NAXIS2 >= imageRes - CRPIX1 = NAXIS1 / 2 + 0.5 - CRPIX2 = NAXIS2 / 2 + 0.5 """ if not isinstance(imageRes, (int, long)): raise TypeError("Image resolution must be an integer") if imageRes < 1: raise RuntimeError("Image resolution must be at least 1") crpix = afwGeom.Point2D(0.5 * (imageRes + 1), 0.5 * (imageRes + 1)) crval = geom.sphericalCoords(skyPixelization.getCenter(skyTileId)) crval = afwCoord.makeCoord(afwCoord.ICRS, crval[0] * afwGeom.degrees, crval[1] * afwGeom.degrees) skyTile = skyPixelization.getGeometry(skyTileId) # Start with a huge TAN image centered at the sky-tile center, # then shrink it using binary search to determine suitable # CD matrix coefficients scale = 1000.0 # deg/pixel, ridiculously large delta = 0.5 * scale frac = 0.01 # desired relative accuracy of CD matrix coeffs wcs = afwImage.makeWcs(crval, crpix, scale, 0.0, 0.0, scale) imagePoly = skypix.imageToPolygon(wcs, imageRes, imageRes) # Make sure the initial guess really is too large if not imagePoly.contains(skyTile): raise RuntimeError("Failed to construct image WCS covering sky-tile") # Search for a WCS with a tight fit to the sky-tile. Note that the # tightness of fit could be further improved by searching for a rotation # and not just a pixel scale. while delta >= frac * scale: tmp = scale - delta wcs = afwImage.makeWcs(crval, crpix, tmp, 0.0, 0.0, tmp) imagePoly = skypix.imageToPolygon(wcs, imageRes, imageRes) delta *= 0.5 if imagePoly.contains(skyTile): scale = tmp return afwImage.makeWcs(crval, crpix, scale, 0.0, 0.0, scale)
def findWcsCoveringSkyTile(skyPixelization, skyTileId, imageRes): """Computes and returns a TAN WCS such that a 2D image with the given WCS and the following properties completely covers the sky-tile with the given pixel id: - NAXIS1/NAXIS2 >= imageRes - CRPIX1 = NAXIS1 / 2 + 0.5 - CRPIX2 = NAXIS2 / 2 + 0.5 """ if not isinstance(imageRes, (int, long)): raise TypeError("Image resolution must be an integer") if imageRes < 1: raise RuntimeError("Image resolution must be at least 1") crpix = afwGeom.Point2D(0.5*(imageRes + 1), 0.5*(imageRes + 1)) crval = geom.sphericalCoords(skyPixelization.getCenter(skyTileId)) crval = afwCoord.makeCoord(afwCoord.ICRS, crval[0] * afwGeom.degrees, crval[1] * afwGeom.degrees) skyTile = skyPixelization.getGeometry(skyTileId) # Start with a huge TAN image centered at the sky-tile center, # then shrink it using binary search to determine suitable # CD matrix coefficients scale = 1000.0 # deg/pixel, ridiculously large delta = 0.5*scale frac = 0.01 # desired relative accuracy of CD matrix coeffs wcs = afwImage.makeWcs(crval, crpix, scale, 0.0, 0.0, scale) imagePoly = skypix.imageToPolygon(wcs, imageRes, imageRes) # Make sure the initial guess really is too large if not imagePoly.contains(skyTile): raise RuntimeError("Failed to construct image WCS covering sky-tile") # Search for a WCS with a tight fit to the sky-tile. Note that the # tightness of fit could be further improved by searching for a rotation # and not just a pixel scale. while delta >= frac * scale: tmp = scale - delta wcs = afwImage.makeWcs(crval, crpix, tmp, 0.0, 0.0, tmp) imagePoly = skypix.imageToPolygon(wcs, imageRes, imageRes) delta *= 0.5 if imagePoly.contains(skyTile): scale = tmp return afwImage.makeWcs(crval, crpix, scale, 0.0, 0.0, scale)
def buildPoints(refFile, posFile, radius): """Builds test data for point within circle matches. """ assert radius > 0.0 and radius < 5.0 # Divide unit sphere into latitude angle stripes phiMin = -90.0 phiMax = 90.0 i = 0 deltaPhi = 4.0 * radius; phi = phiMin while phi < phiMax: centerPhi = geom.clampPhi(max(abs(phi), abs(phi + deltaPhi))) deltaTheta = geom.maxAlpha(4.0 * radius, centerPhi) theta = 0.0 refOutput = [] posOutput = [] # Divide latitude angle stripes into boxes (by longitude angle) while theta < 360.0 - 2.0 * deltaTheta: # Create a random point inside a sub-region of each box # such that a circle of the given radius centered on that # point is guaranteed not to cross the box boundaries if theta == 0.0: # make sure longitude angle wrap-around is tested p = pointInBox(360.0 - 0.125 * deltaTheta, 0.125 * deltaTheta, geom.clampPhi(phi + deltaPhi * 0.38), geom.clampPhi(phi + deltaPhi * 0.62)) else: p = pointInBox(theta + deltaTheta * 0.38, theta + deltaTheta * 0.62, geom.clampPhi(phi + deltaPhi * 0.38), geom.clampPhi(phi + deltaPhi * 0.62)) refId = i i += 1 # Generate matches numMatches = random.randint(0, MAX_MATCHES) pIn = pointsOnCircle(p, radius - MATCH_ACCURACY, numMatches) pOut = pointsOnCircle(p, radius + MATCH_ACCURACY, numMatches) if len(pIn) > 1: # shift first point inwards towards p to make it the # closest match v1 = geom.cartesianUnitVector(p) v2 = geom.cartesianUnitVector(pIn[0]) v3 = geom.normalize((v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2])) pIn[0] = geom.sphericalCoords(v3) matches = ' '.join(map(str, xrange(i, i + len(pIn)))) # Write out reference position refOutput.append( (p[1], "%d,%s,%s,%s\n" % (refId, repr(p[0]), repr(p[1]), matches))) # Write out matching positions for p in pIn: posOutput.append( (p[1], "%d,%s,%s,%d\n" % (i, repr(p[0]), repr(p[1]), refId))) i += 1 # Write out positions with no matches for p in pOut: posOutput.append( (p[1], "%d,%s,%s,\n" % (i, repr(p[0]), repr(p[1])))) i += 1 theta += deltaTheta posOutput.sort() refOutput.sort() for r in refOutput: refFile.write(r[1]) for p in posOutput: posFile.write(p[1]) phi += deltaPhi refFile.flush() posFile.flush()
def buildPoints(refFile, posFile, radius): """Builds test data for point within circle matches. """ assert radius > 0.0 and radius < 5.0 # Divide unit sphere into latitude angle stripes phiMin = -90.0 phiMax = 90.0 i = 0 deltaPhi = 4.0 * radius phi = phiMin while phi < phiMax: centerPhi = geom.clampPhi(max(abs(phi), abs(phi + deltaPhi))) deltaTheta = geom.maxAlpha(4.0 * radius, centerPhi) theta = 0.0 refOutput = [] posOutput = [] # Divide latitude angle stripes into boxes (by longitude angle) while theta < 360.0 - 2.0 * deltaTheta: # Create a random point inside a sub-region of each box # such that a circle of the given radius centered on that # point is guaranteed not to cross the box boundaries if theta == 0.0: # make sure longitude angle wrap-around is tested p = pointInBox(360.0 - 0.125 * deltaTheta, 0.125 * deltaTheta, geom.clampPhi(phi + deltaPhi * 0.38), geom.clampPhi(phi + deltaPhi * 0.62)) else: p = pointInBox(theta + deltaTheta * 0.38, theta + deltaTheta * 0.62, geom.clampPhi(phi + deltaPhi * 0.38), geom.clampPhi(phi + deltaPhi * 0.62)) refId = i i += 1 # Generate matches numMatches = random.randint(0, MAX_MATCHES) pIn = pointsOnCircle(p, radius - MATCH_ACCURACY, numMatches) pOut = pointsOnCircle(p, radius + MATCH_ACCURACY, numMatches) if len(pIn) > 1: # shift first point inwards towards p to make it the # closest match v1 = geom.cartesianUnitVector(p) v2 = geom.cartesianUnitVector(pIn[0]) v3 = geom.normalize( (v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2])) pIn[0] = geom.sphericalCoords(v3) matches = ' '.join(map(str, xrange(i, i + len(pIn)))) # Write out reference position refOutput.append( (p[1], "%d,%s,%s,%s\n" % (refId, repr(p[0]), repr(p[1]), matches))) # Write out matching positions for p in pIn: posOutput.append( (p[1], "%d,%s,%s,%d\n" % (i, repr(p[0]), repr(p[1]), refId))) i += 1 # Write out positions with no matches for p in pOut: posOutput.append( (p[1], "%d,%s,%s,\n" % (i, repr(p[0]), repr(p[1])))) i += 1 theta += deltaTheta posOutput.sort() refOutput.sort() for r in refOutput: refFile.write(r[1]) for p in posOutput: posFile.write(p[1]) phi += deltaPhi refFile.flush() posFile.flush()