Пример #1
0
    def testTransformAccess(self):
        """Test hasTransform and getTransform
        """
        detector = DetectorWrapper().detector
        for fromSys in (cameraGeom.FOCAL_PLANE, cameraGeom.PIXELS,
                        cameraGeom.TAN_PIXELS):
            fullFromSys = detector.makeCameraSys(fromSys)
            for toSys in (cameraGeom.FOCAL_PLANE, cameraGeom.PIXELS,
                          cameraGeom.TAN_PIXELS):
                fullToSys = detector.makeCameraSys(toSys)
                self.assertTrue(detector.hasTransform(fromSys))
                self.assertTrue(detector.hasTransform(fullFromSys))
                self.assertTrue(detector.hasTransform(toSys))
                self.assertTrue(detector.hasTransform(fullToSys))
                detector.getTransform(fromSys, toSys)
                detector.getTransform(fromSys, fullToSys)
                detector.getTransform(fullFromSys, toSys)
                detector.getTransform(fullFromSys, fullToSys)

        for badCamSys in (cameraGeom.CameraSys("badName"),
                          cameraGeom.CameraSys("pixels", "badDetectorName")):
            self.assertFalse(detector.hasTransform(badCamSys))
            self.assertTrue(detector.hasTransform(cameraGeom.PIXELS))
            with self.assertRaises(lsst.pex.exceptions.Exception):
                detector.getTransform(cameraGeom.PIXELS, badCamSys)
Пример #2
0
 def testHashing(self):
     """Test that hashing works as expected"""
     cs1 = cameraGeom.CameraSys("pixels", "det1")
     cs1Copy = cameraGeom.CameraSys("pixels", "det1")
     cs2 = cameraGeom.CameraSys("pixels", "det2")
     cs2Copy = cameraGeom.CameraSys("pixels", "det2")
     # import pdb; pdb.set_trace()
     csSet = set((cs1, cs1Copy, cs2, cs2Copy))
     self.assertEqual(len(csSet), 2)
Пример #3
0
    def testBasics(self):
        """Test CameraSys and CameraSysPrefix
        """
        for sysName in ("fieldAngle", "pixels"):
            for detectorName in ("", "det1", "det2"):
                cameraSys = cameraGeom.CameraSys(sysName, detectorName)
                self.assertEqual(cameraSys.getSysName(), sysName)
                self.assertEqual(cameraSys.getDetectorName(), detectorName)
                self.assertEqual(cameraSys.hasDetectorName(),
                                 bool(detectorName))

                noDetSys = cameraGeom.CameraSys(sysName)
                self.assertEqual(noDetSys.getSysName(), sysName)
                self.assertEqual(noDetSys.getDetectorName(), "")
                self.assertFalse(noDetSys.hasDetectorName())

                camSysPrefix = cameraGeom.CameraSysPrefix(sysName)
                self.assertEqual(camSysPrefix.getSysName(), sysName)

                cameraSys2 = cameraGeom.CameraSys(camSysPrefix, detectorName)
                self.assertEqual(cameraSys2.getSysName(), sysName)
                self.assertEqual(cameraSys2.getDetectorName(), detectorName)
                self.assertEqual(cameraSys2, cameraSys)

                if detectorName:
                    self.assertNotEqual(cameraSys, noDetSys)
                else:
                    self.assertEqual(cameraSys, noDetSys)

                # The following tests are checking the functionality of the
                # == and != operators and should not be replaced with
                # assertEqual or assertNotEqual
                self.assertTrue(cameraSys != camSysPrefix)
                self.assertTrue(noDetSys != camSysPrefix)
                self.assertFalse(cameraSys == camSysPrefix)
                self.assertFalse(noDetSys == camSysPrefix)

            for sysName2 in ("fieldAngle", "pixels"):
                for detectorName2 in ("", "det1", "det2"):
                    cameraSys2 = cameraGeom.CameraSys(sysName2, detectorName2)
                    if sysName == sysName2 and detectorName == detectorName2:
                        self.assertEqual(cameraSys, cameraSys2)
                        # test __eq__ and __ne__
                        self.assertTrue(cameraSys == cameraSys2)
                        self.assertFalse(cameraSys != cameraSys2)
                    else:
                        self.assertNotEqual(cameraSys, cameraSys2)
                        # test __eq__ and __ne__
                        self.assertTrue(cameraSys != cameraSys2)
                        self.assertFalse(cameraSys == cameraSys2)

                    camSysPrefix2 = cameraGeom.CameraSysPrefix(sysName2)
                    if sysName2 == sysName:
                        self.assertEqual(camSysPrefix2, camSysPrefix)
                    else:
                        self.assertNotEqual(camSysPrefix2, camSysPrefix)
Пример #4
0
 def testHashing(self):
     """Test that hashing gives equal CameraSys equal hashes"""
     # Not sure CameraSys has diverse enough values for testing
     # hash uniformity to be worthwhile
     cs1 = cameraGeom.CameraSys("pixels", "det1")
     cs1Copy = cameraGeom.CameraSys("pixels", "det1")
     cs2 = cameraGeom.CameraSys("pixels", "det2")
     cs2Copy = cameraGeom.CameraSys("pixels", "det2")
     csSet = set((cs1, cs1Copy, cs2, cs2Copy))
     self.assertEqual(len(csSet), 2)
Пример #5
0
    def testRepr(self):
        """Test __repr__
        """
        cs1 = cameraGeom.CameraSys("pixels", "det1")
        self.assertEqual(repr(cs1), "CameraSys(pixels, det1)")

        cs2 = cameraGeom.CameraSys("pixels")
        self.assertEqual(repr(cs2), "CameraSys(pixels)")

        dsp = cameraGeom.CameraSysPrefix("pixels")
        self.assertEqual(repr(dsp), "CameraSysPrefix(pixels)")
Пример #6
0
    def testMakeCameraSys(self):
        """Test the makeCameraSys method
        """
        dw = DetectorWrapper()
        for sysName in ("csys1", "csys2"):
            for detectorName in ("", dw.name, "a different detector"):
                inCamSys = cameraGeom.CameraSys(sysName, detectorName)
                outCamSys = dw.detector.makeCameraSys(inCamSys)
                self.assertEquals(inCamSys, outCamSys)

            inCamSysPrefix = cameraGeom.CameraSysPrefix(sysName)
            outCamSys2 = dw.detector.makeCameraSys(inCamSysPrefix)
            self.assertEquals(outCamSys2, cameraGeom.CameraSys(sysName, dw.name))
Пример #7
0
    def testGet(self):
        """Test the get method
        """
        for cs in self.transformMap.getCoordSysList():
            xyTrans2 = self.transformMap.get(cs)
            self.assertTrue(isinstance(xyTrans2, afwGeom.XYTransform))

        missingCamSys = cameraGeom.CameraSys("missing")
        shouldBeNone = self.transformMap.get(missingCamSys)
        self.assertTrue(shouldBeNone is None)
        self.assertRaises(Exception, self.transformMap.get, "badDataType")

        for default in (1, "hello", cameraGeom.CameraSys("default")):
            res = self.transformMap.get(missingCamSys, default)
            self.assertEquals(res, default)
Пример #8
0
    def testBasics(self):
        """Test CameraSys and CameraSysPrefix
        """
        for sysName in ("pupil", "pixels"):
            for detectorName in ("", "det1", "det2"):
                cameraSys = cameraGeom.CameraSys(sysName, detectorName)
                self.assertEquals(cameraSys.getSysName(), sysName)
                self.assertEquals(cameraSys.getDetectorName(), detectorName)
                self.assertEquals(cameraSys.hasDetectorName(),
                                  bool(detectorName))

                noDetSys = cameraGeom.CameraSys(sysName)
                self.assertEquals(noDetSys.getSysName(), sysName)
                self.assertEquals(noDetSys.getDetectorName(), "")
                self.assertFalse(noDetSys.hasDetectorName())

                camSysPrefix = cameraGeom.CameraSysPrefix(sysName)
                self.assertEquals(camSysPrefix.getSysName(), sysName)

                if detectorName:
                    self.assertFalse(cameraSys == noDetSys)
                    self.assertTrue(cameraSys != noDetSys)
                else:
                    self.assertTrue(cameraSys == noDetSys)
                    self.assertFalse(cameraSys != noDetSys)

                self.assertTrue(cameraSys != camSysPrefix)
                self.assertTrue(noDetSys != camSysPrefix)
                self.assertFalse(cameraSys == camSysPrefix)
                self.assertFalse(noDetSys == camSysPrefix)

            for sysName2 in ("pupil", "pixels"):
                for detectorName2 in ("", "det1", "det2"):
                    cameraSys2 = cameraGeom.CameraSys(sysName2, detectorName2)
                    if sysName == sysName2 and detectorName == detectorName2:
                        self.assertTrue(cameraSys == cameraSys2)
                        self.assertFalse(cameraSys != cameraSys2)
                    else:
                        self.assertFalse(cameraSys == cameraSys2)
                        self.assertTrue(cameraSys != cameraSys2)

                    camSysPrefix2 = cameraGeom.CameraSysPrefix(sysName2)
                    if sysName2 == sysName:
                        self.assertTrue(camSysPrefix2 == camSysPrefix)
                        self.assertFalse(camSysPrefix2 != camSysPrefix)
                    else:
                        self.assertFalse(camSysPrefix2 == camSysPrefix)
                        self.assertTrue(camSysPrefix2 != camSysPrefix)
Пример #9
0
    def testTransform(self):
        """Test the transform method
        """
        dw = DetectorWrapper()
        pixOffset = dw.orientation.getReferencePoint()
        for xyMM in ((25.6, -31.07), (0, 0), (-1.234e5, 3.123e4)):
            fpPoint = afwGeom.Point2D(*xyMM)
            fpCamPoint = cameraGeom.CameraPoint(fpPoint,
                                                cameraGeom.FOCAL_PLANE)
            pixCamPoint = dw.detector.transform(fpCamPoint, cameraGeom.PIXELS)
            pixPoint = pixCamPoint.getPoint()
            for i in range(2):
                self.assertAlmostEquals(
                    fpPoint[i] / dw.pixelSize[i] + pixOffset[i], pixPoint[i])
            fpCamPoint2 = dw.detector.transform(pixCamPoint,
                                                cameraGeom.FOCAL_PLANE)
            fpPoint2 = fpCamPoint2.getPoint()
            for i in range(2):
                self.assertAlmostEquals(fpPoint[i], fpPoint2[i])

            # test pix to pix
            pixCamPoint2 = dw.detector.transform(pixCamPoint,
                                                 cameraGeom.PIXELS)
            for i in range(2):
                self.assertAlmostEquals(pixCamPoint.getPoint()[i],
                                        pixCamPoint2.getPoint()[i])

        # make sure you cannot transform to a different detector
        pixCamPoint = dw.detector.makeCameraPoint(afwGeom.Point2D(1, 1),
                                                  cameraGeom.PIXELS)
        otherCamSys = cameraGeom.CameraSys(cameraGeom.PIXELS, "other detector")
        with self.assertRaises(lsst.pex.exceptions.Exception):
            dw.detector.transform(pixCamPoint, otherCamSys)
Пример #10
0
    def testGetItem(self):
        """Test that the contained transforms are the ones expected
        """
        nativeTr = self.transformMap.getTransform(self.nativeSys,
                                                  self.nativeSys)
        self.compare2DFunctions(nativeTr.applyForward, unityTransform)
        self.compare2DFunctions(nativeTr.applyInverse, unityTransform)

        fieldTr = self.transformMap.getTransform(self.nativeSys,
                                                 cameraGeom.FIELD_ANGLE)
        self.compare2DFunctions(fieldTr.applyForward,
                                self.fieldTransform.applyForward)
        self.compare2DFunctions(fieldTr.applyInverse,
                                self.fieldTransform.applyInverse)

        fieldTrInv = self.transformMap.getTransform(cameraGeom.FIELD_ANGLE,
                                                    self.nativeSys)
        self.compare2DFunctions(fieldTrInv.applyForward,
                                self.fieldTransform.applyInverse)
        self.compare2DFunctions(fieldTrInv.applyInverse,
                                self.fieldTransform.applyForward)

        missingCamSys = cameraGeom.CameraSys("missing")
        with self.assertRaises(lsst.pex.exceptions.Exception):
            self.transformMap.getTransform(missingCamSys, self.nativeSys)
        with self.assertRaises(lsst.pex.exceptions.Exception):
            self.transformMap.getTransform(self.nativeSys, missingCamSys)
Пример #11
0
    def testTransform(self):
        """Test the transform method
        """
        dw = DetectorWrapper()
        pixOffset = dw.orientation.getReferencePoint()
        for xyMM in ((25.6, -31.07), (0, 0), (-1.234e5, 3.123e4)):
            fpPoint = afwGeom.Point2D(*xyMM)
            pixPoint = dw.detector.transform(fpPoint, cameraGeom.FOCAL_PLANE,
                                             cameraGeom.PIXELS)
            for i in range(2):
                self.assertAlmostEqual(
                    fpPoint[i] / dw.pixelSize[i] + pixOffset[i], pixPoint[i])
            fpPoint2 = dw.detector.transform(pixPoint, cameraGeom.PIXELS,
                                             cameraGeom.FOCAL_PLANE)
            self.assertPairsAlmostEqual(fpPoint, fpPoint2)

            # test pix to pix
            pixPoint2 = dw.detector.transform(pixPoint, cameraGeom.PIXELS,
                                              cameraGeom.PIXELS)
            self.assertPairsAlmostEqual(pixPoint, pixPoint2)

        # make sure you cannot transform to or from a different detector
        otherCamSys = cameraGeom.CameraSys(cameraGeom.PIXELS, "other detector")
        for goodSys in (cameraGeom.PIXELS, cameraGeom.FOCAL_PLANE):
            with self.assertRaises(lsst.pex.exceptions.Exception):
                dw.detector.transform(pixPoint, goodSys, otherCamSys)
            with self.assertRaises(lsst.pex.exceptions.Exception):
                dw.detector.transform(pixPoint, otherCamSys, goodSys)
Пример #12
0
def makeCamera(cameraFile):
    """An imaging camera (e.g. the LSST 3Gpix camera)

    Parameters
    ----------
    cameraFile : `str`
        Camera description YAML file.

    Returns
    -------
    camera : `lsst.afw.cameraGeom.Camera`
        The desired Camera
    """

    with open(cameraFile) as fd:
        cameraParams = yaml.load(fd, Loader=yaml.CLoader)

    cameraName = cameraParams["name"]

    #
    # Handle distortion models.
    #
    plateScale = geom.Angle(cameraParams["plateScale"], geom.arcseconds)
    nativeSys = cameraGeom.CameraSys(cameraParams["transforms"].pop("nativeSys"))
    transforms = makeTransformDict(nativeSys, cameraParams["transforms"], plateScale)

    ccdParams = cameraParams["CCDs"]
    detectorConfigList = makeDetectorConfigList(ccdParams)

    amplifierDict = {}
    for ccdName, ccdValues in ccdParams.items():
        amplifierDict[ccdName] = makeAmplifierList(ccdValues)

    return makeCameraFromCatalogs(cameraName, detectorConfigList, nativeSys, transforms, amplifierDict)
Пример #13
0
def makeTransformDict(nativeSys, transformDict, plateScale):
    """Make a dictionary of TransformPoint2ToPoint2s from yaml, mapping from
    nativeSys

    Parameters
    ----------
    nativeSys : `lsst.afw.cameraGeom.CameraSys`
    transformDict : `dict`
        A dict specifying parameters of transforms; keys are camera system
        names.
    plateScale : `lsst.geom.Angle`
        The size of a pixel in angular units/mm (e.g. 20 arcsec/mm for LSST)

    Returns
    -------
    transforms : `dict`
        A dict of `lsst.afw.cameraGeom.CameraSys` :
        `lsst.afw.geom.TransformPoint2ToPoint2`

    The resulting dict's keys are `~lsst.afw.cameraGeom.CameraSys`,
    and the values are Transforms *from* NativeSys *to* CameraSys
    """
    # As other comments note this is required, and this is one function where
    # it's assumed
    assert nativeSys == cameraGeom.FOCAL_PLANE, "Cameras with nativeSys != FOCAL_PLANE are not supported."

    resMap = dict()

    for key, transform in transformDict.items():
        transformType = transform["transformType"]
        knownTransformTypes = ["affine", "radial"]
        if transformType not in knownTransformTypes:
            raise RuntimeError("Saw unknown transform type for %s: %s (known types are: [%s])" % (
                key, transform["transformType"], ", ".join(knownTransformTypes)))

        if transformType == "affine":
            affine = geom.AffineTransform(np.array(transform["linear"]),
                                          np.array(transform["translation"]))

            transform = afwGeom.makeTransform(affine)
        elif transformType == "radial":
            # radial coefficients of the form [0, 1 (no units), C2 (rad),
            # usually 0, C3 (rad^2), ...]
            # Radial distortion is modeled as a radial polynomial that converts
            # from focal plane radius (in mm) to field angle (in radians).
            # The provided coefficients are divided by the plate
            # scale (in radians/mm) meaning that C1 is always 1.
            radialCoeffs = np.array(transform["coeffs"])

            radialCoeffs *= plateScale.asRadians()
            transform = afwGeom.makeRadialTransform(radialCoeffs)
        else:
            raise RuntimeError("Impossible condition \"%s\" is not in: [%s])" % (
                transform["transformType"], ", ".join(knownTransformTypes)))

        resMap[cameraGeom.CameraSys(key)] = transform

    return resMap
Пример #14
0
    def testTransformAccess(self):
        """Test hasTransform and getTransform
        """
        detector = DetectorWrapper().detector
        for camSys in (cameraGeom.FOCAL_PLANE, cameraGeom.PIXELS, cameraGeom.TAN_PIXELS):
            # camSys may be a CameraSys or a CameraSysPrefix
            fullCamSys = detector.makeCameraSys(camSys)
            self.assertTrue(detector.hasTransform(camSys))
            self.assertTrue(detector.hasTransform(fullCamSys))
            detector.getTransform(camSys)
            detector.getTransform(fullCamSys)

        for badCamSys in (
            cameraGeom.CameraSys("badName"),
            cameraGeom.CameraSys("pixels", "badDetectorName")
        ):
            self.assertFalse(detector.hasTransform(badCamSys))
            self.assertRaises(lsst.pex.exceptions.Exception, detector.getTransform, badCamSys)
Пример #15
0
    def testMakeCameraPoint(self):
        """Test the makeCameraPoint method
        """
        dw = DetectorWrapper()
        for xyMM in ((25.6, -31.07), (0, 0)):
            point = afwGeom.Point2D(*xyMM)
            for sysName in ("csys1", "csys2"):
                for detectorName in ("", dw.name, "a different detector"):
                    cameraSys1 = cameraGeom.CameraSys(sysName, detectorName)
                    cameraPoint1 = dw.detector.makeCameraPoint(point, cameraSys1)

                    self.assertEquals(cameraPoint1.getPoint(), point)
                    self.assertEquals(cameraPoint1.getCameraSys(), cameraSys1)

                cameraSysPrefix = cameraGeom.CameraSysPrefix(sysName)
                cameraPoint2 = dw.detector.makeCameraPoint(point, cameraSysPrefix)
                predCameraSys2 = cameraGeom.CameraSys(sysName, dw.name)
                self.assertEquals(cameraPoint2.getPoint(), point)
                self.assertEquals(cameraPoint2.getCameraSys(), predCameraSys2)
Пример #16
0
    def testBasics(self):
        """Test basic attributes
        """
        for methodName in ("begin", "end", "contains", "size"):
            self.assertFalse(hasattr(self.transformMap, methodName))

        self.assertIn(self.nativeSys, self.transformMap)
        self.assertIn(cameraGeom.FIELD_ANGLE, self.transformMap)
        self.assertNotIn(cameraGeom.CameraSys("garbage"), self.transformMap)

        self.assertIn(self.nativeSys, self.transformMap)
        self.assertIn(cameraGeom.FIELD_ANGLE, self.transformMap)
Пример #17
0
    def testBasics(self):
        """Test basic attributes
        """
        for methodName in ("begin", "end", "contains", "size"):
            self.assertFalse(hasattr(self.transformMap, methodName))

        self.assertTrue(self.nativeSys in self.transformMap)
        self.assertTrue(cameraGeom.PUPIL in self.transformMap)
        self.assertFalse(cameraGeom.CameraSys("garbage") in self.transformMap)

        csList = self.transformMap.getCoordSysList()
        self.assertTrue(len(csList) == 2)
        self.assertTrue(self.nativeSys in csList)
        self.assertTrue(cameraGeom.PUPIL in csList)
Пример #18
0
    def testGetItem(self):
        """Test that the contained transforms are the ones expected
        """
        nativeTr = self.transformMap[self.nativeSys]
        self.compare2DFunctions(nativeTr.forwardTransform, unityTransform)
        self.compare2DFunctions(nativeTr.reverseTransform, unityTransform)

        pupilTr = self.transformMap[cameraGeom.PUPIL]
        self.compare2DFunctions(pupilTr.forwardTransform,
                                self.pupilTransform.forwardTransform)
        self.compare2DFunctions(pupilTr.reverseTransform,
                                self.pupilTransform.reverseTransform)

        missingCamSys = cameraGeom.CameraSys("missing")
        self.assertRaises(lsst.pex.exceptions.Exception,
                          self.transformMap.__getitem__, missingCamSys)
Пример #19
0
    def testBasics(self):
        """Test getters and other basics
        """
        dw = DetectorWrapper()
        detector = dw.detector
        for methodName in ("begin", "end", "size"):
            if hasattr(detector, methodName):
                self.assertFalse(hasattr(detector, methodName))
        self.assertEqual(dw.name, detector.getName())
        self.assertEqual(dw.id, detector.getId())
        self.assertEqual(dw.type, detector.getType())
        self.assertEqual(dw.serial, detector.getSerial())
        bbox = detector.getBBox()
        for i in range(2):
            self.assertEqual(bbox.getMin()[i], dw.bbox.getMin()[i])
            self.assertEqual(bbox.getMax()[i], dw.bbox.getMax()[i])
        self.assertAlmostEqual(dw.pixelSize, detector.getPixelSize())
        self.assertEqual(len(detector), len(dw.ampInfo))

        orientation = detector.getOrientation()

        transformMap = detector.getTransformMap()
        # add 1 for null transform
        self.assertEqual(len(transformMap), len(dw.transMap) + 1)
        for cameraSys in dw.transMap:
            self.assertTrue(cameraSys in transformMap)

        self.assertEqual(detector.getPhysicalType(),
                         "CCD")  # the default in DetectorWrapper, not Detector

        # make sure some complex objects stick around after detector is deleted

        detectorName = detector.getName()
        nativeCoordSys = detector.getNativeCoordSys()
        offset = dw.orientation.getFpPosition()
        del detector
        del dw
        self.assertEqual(orientation.getFpPosition(), offset)
        self.assertEqual(
            nativeCoordSys,
            cameraGeom.CameraSys(cameraGeom.PIXELS.getSysName(), detectorName))
Пример #20
0
#!/usr/bin/env python
import lsst.pex.policy as pexPolicy
import lsst.afw.table as afwTable
import lsst.afw.geom as afwGeom
import lsst.afw.cameraGeom as cameraGeom
from lsst.afw.cameraGeom import SCIENCE, FOCAL_PLANE, PUPIL, CameraConfig, DetectorConfig,\
                                makeCameraFromCatalogs

import argparse
import eups
import os
import copy
import shutil

FOCAL_PLANE_PIXELS = cameraGeom.CameraSys('Focal_Plane_Pixels')

PIXELSIZE = 1.0  # LSST likes to use mm/pix, but Subaru works in pixels


def makeDir(dirPath, doClobber=False):
    """Make a directory; if it exists then clobber or fail, depending on doClobber

    @param[in] dirPath: path of directory to create
    @param[in] doClobber: what to do if dirPath already exists:
        if True and dirPath is a dir, then delete it and recreate it, else raise an exception
    @throw RuntimeError if dirPath exists and doClobber False
    """
    if os.path.exists(dirPath):
        if doClobber and os.path.isdir(dirPath):
            print "Clobbering directory %r" % (dirPath, )
            shutil.rmtree(dirPath)
Пример #21
0
 def addBadCameraSys(dw):
     """Add an invalid camera system"""
     dw.transMap[cameraGeom.CameraSys("foo", "wrong detector")] = \
         afwGeom.makeIdentityTransform()
Пример #22
0
def makeCameraFromCatalogs(cameraName, detectorConfigList, nativeSys, transformDict, amplifierDict,
                           pupilFactoryClass=cameraGeom.pupil.PupilFactory):
    """Construct a Camera instance from a dictionary of
       detector name : `lsst.afw.cameraGeom.amplifier`

    Parameters
    ----------
    cameraName : `str`
        The name of the camera
    detectorConfigList : `list`
        A list of `lsst.afw.cameraGeom.cameraConfig.DetectorConfig`
    nativeSys : `lsst.afw.cameraGeom.CameraSys`
        The native transformation type; must be `lsst.afw.cameraGeom.FOCAL_PLANE`
    transformDict : `dict`
        A dict of lsst.afw.cameraGeom.CameraSys : `lsst.afw.geom.TransformPoint2ToPoint2`
    amplifierDict : `dict`
        A dictionary of detector name :
                           `lsst.afw.cameraGeom.Amplifier.Builder`
    pupilFactoryClass : `type`, optional
        Class to attach to camera;
             `lsst.default afw.cameraGeom.PupilFactory`

    Returns
    -------
    camera : `lsst.afw.cameraGeom.Camera`
        New Camera instance.

    Notes
    ------
    Copied from `lsst.afw.cameraGeom.cameraFactory` with permission and encouragement
    from Jim Bosch
    """

    # nativeSys=FOCAL_PLANE seems to be assumed in various places in this file
    # (e.g. the definition of TAN_PIXELS), despite CameraConfig providing the
    # illusion that it's configurable.
    # Note that we can't actually get rid of the nativeSys config option
    # without breaking lots of on-disk camera configs.
    assert nativeSys == cameraGeom.FOCAL_PLANE, "Cameras with nativeSys != FOCAL_PLANE are not supported."

    focalPlaneToField = transformDict[cameraGeom.FIELD_ANGLE]

    cameraBuilder = Camera.Builder(cameraName)
    cameraBuilder.setPupilFactoryClass(pupilFactoryClass)

    # Ensure all transforms in the camera transform dict are included.
    for toSys, transform in transformDict.items():
        cameraBuilder.setTransformFromFocalPlaneTo(toSys, transform)

    for detectorConfig in detectorConfigList:
        # This should build all detector pixel -> focalPlane transforms.
        cameraGeom.addDetectorBuilderFromConfig(cameraBuilder, detectorConfig,
                                                amplifierDict[detectorConfig.name],
                                                focalPlaneToField)

        # For reasons I don't understand, some obs_ packages (e.g. HSC) set
        # nativeSys to None for their detectors (which doesn't seem to be
        # permitted by the config class!), but they really mean PIXELS. For
        # backwards compatibility we use that as the default...
        detectorNativeSys = detectorConfig.transformDict.nativeSys
        detectorNativeSys = (cameraGeom.PIXELS if detectorNativeSys is None else
                             cameraGeom.CameraSysPrefix(detectorNativeSys))

        # ...well, actually, it seems that we've always assumed down in C++
        # that the answer is always PIXELS without ever checking that it is.
        # So let's assert that it is, since there are hints all over this file
        # (e.g. the definition of TAN_PIXELS) that other parts of the codebase
        # have regularly made that assumption as well.  Note that we can't
        # actually get rid of the nativeSys config option without breaking
        # lots of on-disk camera configs.
        assert detectorNativeSys == cameraGeom.PIXELS, \
            "Detectors with nativeSys != PIXELS are not supported."
        detectorNativeSys = cameraGeom.CameraSys(detectorNativeSys, detectorConfig.name)

    return cameraBuilder.finish()