root/trunk/papywizard/model/data.py

Revision 2498, 9.7 KB (checked in by fma, 13 months ago)

Updated copyright date

  • Property svn:keywords set to Id
Line 
1# -*- coding: utf-8 -*-
2
3""" Panohead remote control.
4
5License
6=======
7
8 - B{Papywizard} (U{http://www.papywizard.org}) is Copyright:
9  - (C) 2007-2011 Frédéric Mantegazza
10
11This software is governed by the B{CeCILL} license under French law and
12abiding by the rules of distribution of free software.  You can  use,
13modify and/or redistribute the software under the terms of the CeCILL
14license as circulated by CEA, CNRS and INRIA at the following URL
15U{http://www.cecill.info}.
16
17As a counterpart to the access to the source code and  rights to copy,
18modify and redistribute granted by the license, users are provided only
19with a limited warranty  and the software's author,  the holder of the
20economic rights,  and the successive licensors  have only  limited
21liability.
22
23In this respect, the user's attention is drawn to the risks associated
24with loading,  using,  modifying and/or developing or reproducing the
25software by the user in light of its specific status of free software,
26that may mean  that it is complicated to manipulate,  and  that  also
27therefore means  that it is reserved for developers  and  experienced
28professionals having in-depth computer knowledge. Users are therefore
29encouraged to load and test the software's suitability as regards their
30requirements in conditions enabling the security of their systems and/or
31data to be ensured and,  more generally, to use and operate it in the
32same conditions as regards security.
33
34The fact that you are presently reading this means that you have had
35knowledge of the CeCILL license and that you accept its terms.
36
37Module purpose
38==============
39
40Data management
41
42Implements
43==========
44
45 - Data
46 - MosaicData
47 - Presetdata
48
49Usage
50=====
51
52Data is used during shooting, and generate a xml file containing
53usefull information for stitchers. AutoPano Pro takes advantage of
54such datas, for example to correctly set unlinked pictures at their
55correct place (sky pictures without any details are often unlinked).
56
57@author: Frédéric Mantegazza
58@copyright: (C) 2007-2011 Frédéric Mantegazza
59@license: CeCILL
60"""
61
62__revision__ = "$Id$"
63
64import time
65import os.path
66import xml.dom.minidom
67
68from papywizard.common import config
69from papywizard.common.configManager import ConfigManager
70from papywizard.common.loggingServices import Logger
71
72
73class AbstractData(object):
74    """ Manage the data.
75    """
76    def __init__(self):
77        """ Init object.
78        """
79        super(AbstractData, self).__init__()
80        date, time_ = self._getDateTime().split('_')
81        #date = time.strftime("%Y-%m-%d", time.localtime())
82        #time_ = time.strftime("%Hh%Mm%Ss", time.localtime())
83        mode = self._getMode()
84        self._dataFileFormatDict = {'date': date,
85                                    'time': time_,
86                                    'date_time': "%s_%s" % (date, time_),
87                                    'mode': mode}
88
89        # Create xml tree
90        Logger().debug("Data.__init__(): create xml tree")
91        self.__impl = xml.dom.minidom.getDOMImplementation()
92        self._doc = self.__impl.createDocument(None, "papywizard", None)
93        self._rootNode = self._doc.documentElement
94        self._rootNode.setAttribute("version", config.VERSION_XML)
95
96        # Create 'header' node
97        self._headerNode = self._doc.createElement('header')
98        self._rootNode.appendChild(self._headerNode)
99
100        # Create 'shoot' node
101        self._shootNode = self._doc.createElement('shoot')
102        self._rootNode.appendChild(self._shootNode)
103
104        self._pictId = 1
105
106    def _getDateTime(self):
107        """ Return the curent date and time.
108
109        Format as %Y-%m-%d_%Hh%Mm%Ss
110        """
111        return time.strftime("%Y-%m-%d_%Hh%Mm%Ss", time.localtime())
112
113    def _getMode(self):
114        """ Return the shooting mode.
115        """
116        raise NotImplementedError
117
118    def _createNode(self, parent, tag):
119        """ Create a node.
120
121        @param parent: parent node
122        @type parent: {DOM Element}
123
124        @param tag: name of the tag
125        @type tag: str
126        """
127        node = self._doc.createElement(tag)
128        parent.appendChild(node)
129        return node
130
131    def _createTextNode(self, parent, tag, text):
132        """ Create a text node.
133
134        @param parent: parent node
135        @type parent: {DOM Element}
136
137        @param tag: name of the text tag
138        @type tag: str
139
140        @param text: text to use
141        @type text: str
142        """
143        textNode = self._createNode(parent, tag)
144        text = self._doc.createTextNode(text)
145        textNode.appendChild(text)
146        return textNode
147
148    def _addNode(self, parent, tag, value=None, **attr):
149        """ Add a sub node.
150
151        @param parent: parent node
152        @type parent: {DOM Element}
153
154        @param tag: tag of the node
155        @type tag: str
156
157        @param value: value of the node
158        @type value: str
159
160        @param attr: optionnal attributes
161        @type attr: dict
162        """
163        Logger().debug("Data._addNode(): parent=%s, tag=%s, value=%s, attr=%s" % (parent.tagName, tag, value, attr))
164        if value is not None:
165            node = self._createTextNode(parent, tag, value)
166        else:
167            node = self._createNode(parent, tag)
168        for key, val in attr.iteritems():
169            node.setAttribute(key, val)
170        return node
171
172    def _serialize(self):
173        """ Serialize xml tree to file.
174        """
175        if ConfigManager().getBoolean('Configuration/DATA_FILE_ENABLE'):
176            Logger().trace("Data.serialize()")
177            dataFileFormat = "papywizard_%s.xml" % ConfigManager().get('Configuration/DATA_FILE_FORMAT')
178            dataStorageDir = os.path.join(ConfigManager().get('Configuration/DATA_STORAGE_DIR'))
179            if not dataStorageDir:
180                dataStorageDir = config.DATA_STORAGE_DIR
181            fileName = os.path.join(dataStorageDir, dataFileFormat)
182            xmlFile = file(fileName % self._dataFileFormatDict, 'w')
183            #Logger().debug("Data.serialize():\n%s" % self._doc.toprettyxml(indent="    ", newl='\n', encoding='utf-8'))
184            #self._doc.writexml(xmlFile, addindent="    ", newl='\n', encoding='utf-8')
185            xmlFile.write(self._doc.toprettyxml(indent="    ", newl='\n', encoding='utf-8'))
186            xmlFile.close()
187
188    def createHeader(self, values):
189        """ Create the header.
190
191        @param values: values to put in the header
192        @type values: dict
193        """
194        Logger().debug("Data.createHeader(): values=%s" % values)
195
196        # General
197        node = self._addNode(self._headerNode, 'general')
198        self._addNode(node, 'title', values['title'])
199        self._addNode(node, 'gps', values['gps'])
200        self._addNode(node, 'comment', values['comment'])
201
202        # Shooting
203        node = self._addNode(self._headerNode, 'shooting', mode=self._getMode())
204        self._addNode(node, 'headOrientation', values['headOrientation'])
205        self._addNode(node, 'cameraOrientation', values['cameraOrientation'])
206        self._addNode(node, 'stabilizationDelay', values['stabilizationDelay'])
207        self._addNode(node, 'counter', values['counter'])
208        dateTime = self._getDateTime()
209        self._addNode(node, 'startTime', dateTime)
210        self._headerShootingEndTime = self._addNode(node, 'endTime', dateTime)
211
212        # Camera
213        node = self._addNode(self._headerNode, 'camera')
214        self._addNode(node, 'timeValue', values['timeValue'])
215        self._addNode(node, 'bracketing', nbPicts=values['bracketingNbPicts'])
216        self._addNode(node, 'sensor', coef=values['sensorCoef'],
217                                      ratio=values['sensorRatio'])
218
219        # Lens
220        node = self._addNode(self._headerNode, 'lens', type=values['lensType'])
221        self._addNode(node, 'focal', values['focal'])
222
223    def addPicture(self, bracket, yaw, pitch, roll):
224        """ Add a new picture node to shoot node.
225
226        @param bracket: num of the pict (bracketing)
227        @type bracket: int
228
229        @param yaw: yaw position
230        @type yaw: float
231
232        @param pitch: pitch position
233        @type pitch: float
234
235        @param roll: roll value
236        @type roll: float
237        """
238        Logger().debug("Data.addPicture(): bracket=%d, yaw=%.1f, pitch=%.1f, roll=%.1f" % (bracket, yaw, pitch, roll))
239        node = self._addNode(self._shootNode, 'pict', id="%d" % self._pictId, bracket="%d" % bracket)
240        self._pictId += 1
241        dateTime = self._getDateTime()
242        self._addNode(node, 'time', dateTime)
243        self._addNode(node, 'position', yaw="%.1f" % yaw, pitch="%.1f" % pitch, roll="%.1f" % roll)
244        self._headerShootingEndTime.firstChild.data = dateTime
245
246        # Serialize xml file
247        self._serialize()
248
249
250class MosaicData(AbstractData):
251    """ Manage the data for mosaic.
252    """
253    def _getMode(self):
254        """ Return the shooting mode.
255        """
256        return 'mosaic'
257
258    def createHeader(self, values):
259        super(MosaicData, self).createHeader(values)
260
261        # Mosaic
262        node = self._addNode(self._headerNode, 'mosaic')
263        self._addNode(node, 'nbPicts', yaw=values['yawNbPicts'],
264                                       pitch=values['pitchNbPicts'])
265        self._addNode(node, 'overlap', minimum=values['overlap'],
266                                       yaw=values['yawRealOverlap'],
267                                       pitch=values['pitchRealOverlap'])
268
269        # Serialize xml file
270        self._serialize()
271
272
273class PresetData(AbstractData):
274    """ Manage the data for presets.
275    """
276    def _getMode(self):
277        """ Return the shooting mode.
278        """
279        return 'preset'
280
281    def createHeader(self, values):
282        super(PresetData, self).createHeader(values)
283
284        # Preset
285        node = self._addNode(self._headerNode, 'preset', name=values['name'])
286        #self._addNode(node, 'name', values['name'])
287
288        # Serialize xml file
289        self._serialize()
Note: See TracBrowser for help on using the browser.