예제 #1
0
    def __init__(self):
        """ Init the object.
        """
        QtCore.QObject.__init__(self)
        self.__shooting = False
        self.__pause = False
        self.__paused = False
        self.__stop = False
        self.__stepByStep = False
        self.__forceNewPosition = False
        self.__startTime = None
        self.__pauseTime = None
        self.__totalPausedTime = 0.

        # Sub-models
        self.head = Head()
        self.camera = Camera()
        self.mosaic = MosaicScan(self)
        self.preset = PresetScan(self)
예제 #2
0
class Shooting(QtCore.QObject):
    """ Shooting model.
    """
    def __init__(self):
        """ Init the object.
        """
        QtCore.QObject.__init__(self)
        self.__shooting = False
        self.__pause = False
        self.__paused = False
        self.__stop = False
        self.__stepByStep = False
        self.__forceNewPosition = False
        self.__startTime = None
        self.__pauseTime = None
        self.__totalPausedTime = 0.

        # Sub-models
        self.head = Head()
        self.camera = Camera()
        self.mosaic = MosaicScan(self)
        self.preset = PresetScan(self)

    # Properties
    def __getShutter(self):
        """
        """
        shutterName = ConfigManager().get('Plugins/PLUGIN_SHUTTER')
        return PluginsManager ().get('shutter', shutterName)[0] # Use getModel()?

    shutter = property(__getShutter)

    def __getMode(self):
        """
        """
        return ConfigManager().get('Core/SHOOTING_MODE')

    def __setMode(self, mode):
        """
        """
        ConfigManager().set('Core/SHOOTING_MODE', mode)

    mode = property(__getMode, __setMode)

    def __getHeadOrientation(self):
        """
        """
        return ConfigManager().get('Configuration/SHOOTING_HEAD_ORIENTATION')

    def __setHeadOrientation(self, headOrientation):
        """
        """
        ConfigManager().set('Configuration/SHOOTING_HEAD_ORIENTATION', headOrientation)

    headOrientation = property(__getHeadOrientation, __setHeadOrientation)

    def __getCameraOrientation(self):
        """
        """
        return ConfigManager().get('Configuration/SHOOTING_CAMERA_ORIENTATION')

    def __setCameraOrientation(self, cameraOrientation):
        """
        """
        ConfigManager().set('Configuration/SHOOTING_CAMERA_ORIENTATION', cameraOrientation)

    cameraOrientation = property(__getCameraOrientation, __setCameraOrientation)

    def __getCameraRoll(self):
        """
        """
        return ConfigManager().getFloat('Configuration/SHOOTING_CAMERA_ROLL')

    def __setCameraRoll(self, cameraRoll):
        """
        """
        ConfigManager().setFloat('Configuration/SHOOTING_CAMERA_ROLL', cameraRoll, 1)

    cameraRoll = property(__getCameraRoll, __setCameraRoll)

    def __getStabilizationDelay(self):
        """
        """
        return ConfigManager().getFloat('Configuration/SHOOTING_STABILIZATION_DELAY')

    def __setStabilizationDelay(self, stabilizationDelay):
        """
        """
        ConfigManager().setFloat('Configuration/SHOOTING_STABILIZATION_DELAY', stabilizationDelay, 1)

    stabilizationDelay = property(__getStabilizationDelay, __setStabilizationDelay)

    # Remove from model?
    def __getTimerAfter(self):
        """
        """
        return hmsAsStrToS(ConfigManager().get('Configuration/TIMER_AFTER'))

    def __setTimerAfter(self, s):
        """
        """
        ConfigManager().set('Configuration/TIMER_AFTER', sToHmsAsStr(s))

    timerAfter = property(__getTimerAfter, __setTimerAfter)

    def __getTimerAfterEnable(self):
        """
        """
        return ConfigManager().getBoolean('Configuration/TIMER_AFTER_ENABLE')

    def __setTimerAfterEnable(self, flag):
        """
        """
        ConfigManager().setBoolean('Configuration/TIMER_AFTER_ENABLE', flag)

    timerAfterEnable = property(__getTimerAfterEnable, __setTimerAfterEnable)

    def __getTimerRepeat(self):
        """
        """
        return ConfigManager().getInt('Configuration/TIMER_REPEAT')

    def __setTimerRepeat(self, repeat):
        """
        """
        ConfigManager().setInt('Configuration/TIMER_REPEAT', repeat)

    timerRepeat = property(__getTimerRepeat, __setTimerRepeat)

    def __getTimerRepeatEnable(self):
        """
        """
        return ConfigManager().getBoolean('Configuration/TIMER_REPEAT_ENABLE')

    def __setTimerRepeatEnable(self, flag):
        """
        """
        ConfigManager().setBoolean('Configuration/TIMER_REPEAT_ENABLE', flag)

    timerRepeatEnable = property(__getTimerRepeatEnable, __setTimerRepeatEnable)

    def __getTimerEvery(self):
        """
        """
        return hmsAsStrToS(ConfigManager().get('Configuration/TIMER_EVERY'))

    def __setTimerEvery(self, s):
        """
        """
        ConfigManager().set('Configuration/TIMER_EVERY', sToHmsAsStr(s))

    timerEvery = property(__getTimerEvery, __setTimerEvery)

    def __getTimerReverseDirection(self):
        """
        """
        return ConfigManager().getBoolean('Configuration/TIMER_REVERSE_DIRECTION')

    def __setTimerReverseDirection(self, timerReverseDirection):
        """
        """
        ConfigManager().setBoolean('Configuration/TIMER_REVERSE_DIRECTION', timerReverseDirection)

    timerReverseDirection = property(__getTimerReverseDirection, __setTimerReverseDirection)

    def __getShootingCounter(self):
        """
        """
        return ConfigManager().getInt('Configuration/SHOOTING_COUNTER')

    def __setShootingCounter(self, counter):
        """
        """
        ConfigManager().setInt('Configuration/SHOOTING_COUNTER', counter)

    shootingCounter = property(__getShootingCounter, __setShootingCounter)

    def __getShowShootingCounter(self):
        """
        """
        return ConfigManager().getBoolean('Configuration/SHOW_SHOOTING_COUNTER')

    def __setShowShootingCounter(self, flag):
        """
        """
        ConfigManager().setBoolean('Configuration/SHOW_SHOOTING_COUNTER', flag)

    showShootingCounter = property(__getShowShootingCounter, __setShowShootingCounter)

    def __getPauseEvery(self):
        """
        """
        return ConfigManager().getInt('Configuration/PAUSE_EVERY')

    def __setPauseEvery(self, flag):
        """
        """
        ConfigManager().setInt('Configuration/PAUSE_EVERY', flag)

    pauseEvery = property(__getPauseEvery, __setPauseEvery)

    def __getPauseEveryEnable(self):
        """
        """
        return ConfigManager().getBoolean('Configuration/PAUSE_EVERY_ENABLE')

    def __setPauseEveryEnable(self, flag):
        """
        """
        ConfigManager().setBoolean('Configuration/PAUSE_EVERY_ENABLE', flag)

    pauseEveryEnable = property(__getPauseEveryEnable, __setPauseEveryEnable)

    def __getScan(self):
        """
        """
        if self.mode == 'mosaic':
            return self.mosaic
        else:
            return self.preset

    scan = property(__getScan)

    # Signals
    def started(self):
        """ Shooting started.
        """
        self.emit(QtCore.SIGNAL("started"))

    def paused(self):
        """ Shooting paused.
        """
        self.emit(QtCore.SIGNAL("paused"))

    def resumed(self):
        """ Shooting resumed.
        """
        self.emit(QtCore.SIGNAL("resumed"))

    def stopped(self, status):
        """ Shooting stopped.

        @param status: shooting status
        @type status: str
        """
        self.emit(QtCore.SIGNAL("stopped"), status)

    def waiting(self, wait):
        """ Shooting waiting.

        @param wait: remaining time to wait (s)
        @type wait: float
        """
        self.emit(QtCore.SIGNAL("waiting"), wait)

    def progress(self, shootingProgress=None, totalProgress=None):
        """ Shooting progress.

        @param shootingProgress: shooting progress value
        @type shootingProgress: float

        @param totalProgress: total progress value
        @type totalProgress: float
        """
        self.emit(QtCore.SIGNAL("progress"), shootingProgress, totalProgress)

    def repeat(self, repeat):
        """ Shooting repeat counter.

        @param repeat: repeat counter
        @type repeat: int
        """
        self.emit(QtCore.SIGNAL("repeat"), repeat)

    def update(self, index, yaw, pitch, state=None, next=None):
        """ Shooting update.

        @param index: position index
        @type int

        @param yaw: position yaw
        @type yaw: float

        @param pitch: position pitch
        @type pitch: float

        @param state: position state
        @type state: str

        @param next: next position flag
        @type next: bool
        """
        self.emit(QtCore.SIGNAL("update"), index, yaw, pitch, state, next)

    def sequence(self, sequence, bracket=None):
        """ Shooting sequence.

        @param sequence: name of the current sequence
        @type sequence: str

        @param bracket: number of the bracket
        @type bracket: int
        """
        self.emit(QtCore.SIGNAL("sequence"), sequence, bracket)

    def beforeRepeat(self):
        """ Shooting before repeat.

        This signal is emitted at the end of a shooting sequence,
        before any repeat
        """
        self.emit(QtCore.SIGNAL("beforeRepeat"))

    # Interface
    def setCornersFromFov(self, yawFov, pitchFov):
        """ Set yaw start/end positions from total fov.

        @param yawFov: total yaw fov (°)
        @type yawFov: float

        @param pitchFov: total pitch fov (°)
        @type pitchFov: float
        """
        yawPos, pitchPos = 0., 0.
        yawDelta = yawFov - self.camera.getYawFov(self.cameraOrientation)
        if yawDelta < 0.:
            yawDelta = 0.
        self.mosaic.corners[0]['yaw'] = yawPos - yawDelta / 2.
        self.mosaic.corners[1]['yaw'] = yawPos + yawDelta / 2.
        pitchDelta = pitchFov - self.camera.getPitchFov(self.cameraOrientation)
        if pitchDelta < 0.:
            pitchDelta = 0.
        self.mosaic.corners[0]['pitch'] = pitchPos - pitchDelta / 2.
        self.mosaic.corners[1]['pitch'] = pitchPos + pitchDelta / 2.

    def setCornersFromNbPicts(self, yawNbPicts, pitchNbPicts):
        """ Set the start/end positions from nb picts.

        @param yawNbPicts: yaw nb picts
        @type yawNbPicts: int

        @param pitchNbPicts: pitch nb picts
        @type pitchNbPicts: int
        """
        yawPos, pitchPos = 0., 0.
        yawDelta = self.camera.getYawFov(self.cameraOrientation) * (1 - self.mosaic.overlap) * (yawNbPicts - 1)
        if yawNbPicts > 1:
            yawDelta -= .01
        self.mosaic.corners[0]['yaw'] = yawPos - yawDelta / 2.
        self.mosaic.corners[1]['yaw'] = yawPos + yawDelta / 2.
        pitchDelta = self.camera.getPitchFov(self.cameraOrientation) * (1 - self.mosaic.overlap) * (pitchNbPicts - 1)
        if pitchNbPicts > 1:
            pitchDelta -= .01
        self.mosaic.corners[0]['pitch'] = pitchPos - pitchDelta / 2.
        self.mosaic.corners[1]['pitch'] = pitchPos + pitchDelta / 2.

    def setStepByStep(self, flag):
        """ Turn on/off step-by-step shooting.

        If active, the head switch to pause at each end of position.

        @param flag: flag for step-by-step shooting
        @type flag: bool
        """
        self.__stepByStep = flag

    def forceNewPosition(self):
        self.__forceNewPosition = True

    def getShootingElapsedTime(self):
        """ Get the shooting elapsed time.

        @return: shooting time and elapsed time (s)
        @rtype: tuple of int
        """
        shootingTime = time.time() - self.__startTime - self.__totalPausedTime
        if self.__paused and self.__pauseTime is not None:
            shootingTime -= time.time() - self.__pauseTime
        elapsedTime = time.time() - self.__startTime
        return shootingTime, elapsedTime

    def start(self):
        """ Start pano shooting.
        """
        def checkPause():
            """ Check if pause requested.
            """
            if self.__pause:
                Logger().info("Pause shooting")
                self.__pauseTime = time.time()
                self.__paused = True
                self.paused()
                while self.__pause:
                    time.sleep(0.1)
                self.__paused = False
                self.resumed()
                self.__totalPausedTime += time.time() - self.__pauseTime
                Logger().info("Resume shooting")

        def checkStop():
            """ Check if stop requested.
            """
            if self.__stop:
                Logger().info("Stop shooting")
                raise StopIteration

        Logger().trace("Shooting.start()")
        self.__startTime = time.time()
        self.__totalPausedTime = 0.
        self.__stop = False
        self.__pause = False
        self.__paused = False
        self.__shooting = True
        self.started()
        self.progress(0., 0.)

        if self.cameraOrientation == 'portrait':
            roll = 90.
        elif self.cameraOrientation == 'landscape':
            roll = 0.
        elif self.cameraOrientation == 'custom':
            roll = self.cameraRoll
        else:
            raise ValueError("cameraOrientation must be in ('portrait', 'landscape', 'custom'")
        focal = self.camera.lens.focal
        if self.camera.lens.type_ == 'rectilinear':
            focal *= self.camera.lens.opticalMultiplier
        values = {'title' : ConfigManager().get('Configuration/DATA_TITLE'),
                  'gps': ConfigManager().get('Configuration/DATA_GPS'),
                  'comment': ConfigManager().get('Configuration/DATA_COMMENT') % {'version': config.VERSION},
                  'headOrientation': "up",
                  'cameraOrientation': "%s" % self.cameraOrientation,
                  'roll': "%.1f" % roll,
                  'stabilizationDelay': "%.1f" % self.stabilizationDelay,
                  'counter': "%03d" % self.shootingCounter,
                  'timeValue': "%.1f" % self.shutter.timeValue,
                  'bracketingNbPicts': "%d" % self.shutter.bracketingNbPicts,
                  'sensorCoef': "%.1f" % self.camera.sensorCoef,
                  'sensorRatio': "%s" % self.camera.sensorRatio,
                  'lensType': "%s" % self.camera.lens.type_,
                  'focal': "%.1f" % focal
                  }

        Logger().info("Start shooting process...")
        try:

            # Timer after
            if self.timerAfterEnable:
                initialTime = time.time()
                remainingTime = self.timerAfter - (time.time() - initialTime)
                while remainingTime > 0:
                    Logger().debug("Shooting.start(): start in %s" % sToHmsAsStr(remainingTime))
                    self.waiting(remainingTime)
                    time.sleep(1)

                    # Check only stop
                    checkStop()

                    remainingTime = self.timerAfter - (time.time() - initialTime)

            # Timer repeat
            if self.timerRepeatEnable:
                numRepeat =  self.timerRepeat
            else:
                numRepeat = 1
            for repeat in xrange(1, numRepeat + 1):

                # Create data object (use a factory)
                if self.mode == 'mosaic':
                    Logger().debug("Shooting.start(): create mosaic data object")
                    data = MosaicData()
                    values.update({'yawNbPicts': "%d" % self.mosaic.yawNbPicts,
                                   'pitchNbPicts': "%d" % self.mosaic.pitchNbPicts,
                                   'overlap': "%.2f" % self.mosaic.overlap,
                                   'yawRealOverlap': "%.2f" % self.mosaic.yawRealOverlap,
                                   'pitchRealOverlap': "%.2f" % self.mosaic.pitchRealOverlap})
                else:
                    Logger().debug("Shooting.start(): create preset data object")
                    data = PresetData()
                    values.update({'name': "%s" % self.preset.name})

                # Create header
                data.createHeader(values)

                # Increase shooting counter
                self.shootingCounter += 1
                if self.shootingCounter > config.SHOOTING_COUNTER_MAX:
                    self.shootingCounter = 1
                ConfigManager().save()

                startTime = time.time()
                Logger().debug("Shooting.start(): repeat %d/%d" % (repeat, numRepeat))
                self.repeat(repeat)
                self.progress(0.)

                # Loop over all positions
                self.scan.index = 1
                while True:
                    try:
                        index, (yaw, pitch) = self.scan.getCurrentPosition()
                        if isinstance(index, tuple):
                            index_, yawIndex, pitchIndex = index
                        else:
                            index_ = index
                        Logger().debug("Shooting.start(): pict #%d of %d, index=%s, yaw=%.1f, pitch=%.1f" % (index_, self.scan.totalNbPicts, str(index), yaw, pitch))
                        self.update(index, yaw, pitch, next=True)

                        self.__forceNewPosition = False

                        Logger().info("Moving")
                        self.sequence('moving')
                        self.head.gotoPosition(yaw, pitch)

                        # Test step-by-step flag (use a function)
                        if self.__stepByStep and not self.__stop:
                            self.__pause = True
                            Logger().info("Wait for manual shooting trigger...")

                        # 'Pause every' feature
                        if self.pauseEveryEnable and self.scan.index > 1 and not self.scan.index % self.pauseEvery - 1:
                            self.__pause = True
                            Logger().info("Automatic pausing...")

                        checkPause()
                        checkStop()

                        # If a new shooting position has been requested (rewind/forward),
                        # we start over
                        if self.__forceNewPosition:
                            continue

                        # Take pictures
                        for bracket in xrange(1, self.shutter.bracketingNbPicts + 1):

                            # Mirror lockup sequence
                            # TODO: move call to plugin!
                            if self.shutter.mirrorLockup:
                                Logger().info("Mirror lockup")
                                self.sequence('mirror')
                                retCode = self.shutter.lockupMirror()
                                if retCode:
                                    raise HardwareError(self.tr("Shutter failed while mirror locking up"))

                                self.__LastShootTime = time.time()

                            Logger().info("Stabilization")
                            self.sequence('stabilization')
                            time.sleep(self.stabilizationDelay)

                            # Take pictures
                            Logger().info("Shutter cycle")
                            Logger().debug("Shooting.start(): bracket #%d of %d" % (bracket, self.shutter.bracketingNbPicts))
                            self.sequence('shutter', bracket)

                            retCode = self.shutter.shoot(bracket)
                            if retCode:
                                raise HardwareError(self.tr("Shutter failed while shooting"))

                            # Add image to the xml data file
                            realYaw, realPitch = self.head.readPosition()
                            data.addPicture(bracket, realYaw, realPitch, roll)

                            checkStop()

                    except OutOfLimitsError, msg:
                        self.head.stopAxis()
                        Logger().warning("Shooting.start(): %s" % unicode(msg))
                        state = 'invalid'

                    except HardwareError, msg:
                        self.head.stopAxis()
                        Logger().exception("Shooting.start()")
                        #Logger().warning("Shooting.start(): position index=%s, yaw=%.1f, pitch=%.1f out of limits" % (index_, yaw, pitch))
                        state = 'error'

                    else: