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)
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: