1 /*
2  * The following code is slightly based on the C# application
3  * SynthExport (http://synthexport.codeplex.com/) by Christoph Hausner
4  */
5 
6 #ifndef SYNTHDATA_H
7 #define SYNTHDATA_H
8 
9 #include <QString>
10 #include <QScriptValue>
11 #include <QtSoapHttpTransport>
12 #include <assert.h>
13 #include <common/interfaces.h>
14 #include <QMutex>
15 
16 using namespace vcg;
17 
18 typedef struct Point
19 {
20   float _x;
21   float _y;
22   float _z;
23   uchar _r;
24   uchar _g;
25   uchar _b;
26 } Point;
27 
28 typedef struct Image
29 {
30   int _ID;
31   int _width;
32   int _height;
33   int _exifWidth;
34   int _exifHeight;
35   QString _url;
36   QString _localPath;
37   int _shouldBeDownloaded; //tells how many times this image has to be downloaded, a value of zero means that this image won't be downloaded
38 } Image;
39 
40 class CameraParameters
41 {
42 public:
43   enum Field
44   {
45     FIRST = 0,
46     POS_X = FIRST,
47     POS_Y,
48     POS_Z,
49     ROT_X,
50     ROT_Y,
51     ROT_Z,
52     ASPECT_RATIO,
53     FOCAL_LENGTH, //apparently the value provided by photosynth is: ccd_dimension_in_mm / focal_length_in_mm
54     LAST = FOCAL_LENGTH
55   };
56 
CameraParameters()57   CameraParameters() : _ccdWidth(0), _focalLength(0), _pixelSizeMm(0) {}
58   Point3m getTranslation();
59   Matrix44m getRotation();
60 
61   //use this to access camera parameters values taken from photosynth json, using enum Field values as argument
62   inline qreal &operator [] (const int i)
63   {
64     assert(i >= 0 && i < 8);
65     return _fields[i];
66   }
67 
68   int _camID;
69   int _imageID; //the image whose this object represents the camera that took the shot
70   qreal _fields[8]; //contains position, rotation, aspect ratio, photosynth focal length, in the order of enum Field as taken from photosynth json
71   qreal _distortionRadius1; //from photosynth json
72   qreal _distortionRadius2; //from photosynth json
73   //intrinsics
74   float _ccdWidth; //taken from image exif data, or (when missing in exif) computed using image resolution in pixel and in dpi
75   float _focalLength; //estimated using _fields[8] and _ccdWidth
76   float _pixelSizeMm; //estimated using _ccdWidth and image resolution in pixel or, when the first is missing, with image resolution in dpi
77 };
78 
79 /*
80  * Represents a set of points
81  */
82 class PointCloud : public QObject
83 {
84 public:
85   PointCloud(int coordSysID, int binFileCount, QObject *parent = 0);
86 
87 public:
88   //the coordinate system id within the synth which this set belongs to
89   int _coordinateSystem;
90   //this is the n parameter in the points_m_n.bin files containing the synth point clounds
91   //and tells how many files this cloud is split into
92   int _binFileCount;
93   int _numberOfPoints;
94   QList<Point> _points;
95 };
96 
97 /*
98  * Represents an independent cluster of points within the synth,
99  * it is identified by an ID, contains a point cloud and
100  * has its own camera parameters
101  */
102 class CoordinateSystem : public QObject
103 {
104 public:
105   CoordinateSystem(int id, QObject *parent = 0);
106 
107 public:
108   //this is the m parameter in the points_m_n.bin files containing the synth point clounds
109   int _id;
110   bool _shouldBeImported;
111   PointCloud *_pointCloud;
112   QList<CameraParameters> _cameraParametersList;
113 };
114 
115 /*
116  * Represents the options of the import process
117  */
118 class ImportSettings
119 {
120 public:
ImportSettings()121   ImportSettings() { };
122   ImportSettings(QString url, int clusterID, QString imageSavePath = QString(""));
123 
124 public:
125   //the synth url
126   QString _url;
127   //specifies which coordinate system (cluster of point) has to be imported, -1 means all
128   int _clusterID;
129   //specifies the path where the images have to be saved to; if it is equal to the empty string, images won't be downloaded
130   QString _imageSavePath;
131 };
132 
133 /*
134  * Represents a Synth
135  */
136 class SynthData : public QObject
137 {
138   Q_OBJECT
139 
140 public:
141   //contains errors descriptions
142   static const QString errors[];
143   //contains the strings used by cb() funcion
144   static const char *steps[];
145 
146   enum Error
147   {
148     WRONG_URL = 0,
149     WRONG_PATH,
150     WEBSERVICE_ERROR,
151     NEGATIVE_RESPONSE,
152     UNEXPECTED_RESPONSE,
153     WRONG_COLLECTION_TYPE,
154     JSON_PARSING,
155     EMPTY,
156     READING_BIN_DATA,
157     BIN_DATA_FORMAT,
158     CREATE_DIR,
159     SAVE_IMG,
160     SYNTH_NO_ERROR,
161     PENDING
162   };
163 
164   enum Step
165   {
166     WEB_SERVICE = 0,
167     DOWNLOAD_JSON,
168     PARSE_JSON,
169     DOWNLOAD_BIN,
170     LOADING_BIN,
171     DOWNLOAD_IMG
172   };
173 
174   SynthData(ImportSettings &settings, QObject *parent = 0);
175   ~SynthData();
176   bool isValid();
177 
178 public:
179   void downloadSynthInfo(vcg::CallBackPos *cb);
180   int progressInfo();
181 
182 private slots:
183   void readWSresponse(const QtSoapMessage &response);
184   void parseJsonString(QNetworkReply *httpResponse);
185   void loadBinFile(QNetworkReply *httpResponse);
186   void saveImages(QNetworkReply *httpResponse);
187 
188 private:
189   void parseImageMap(QScriptValue &map);
190   void downloadJsonData(QString jsonURL);
191   void downloadBinFiles();
192   void downloadImages();
193   bool checkAndSetState(bool condition, Error errorCode, QNetworkReply *httpResponse = 0);
194   void setState(Error errorCode, QNetworkReply *httpResponse = 0);
195 
196 public:
197   //this is the cid parameter taken from the url used to access the synth on photosynth.net
198   QString _collectionID;
199   //the base url of the binary files points_m_n.bin containing point clouds data
200   QString _collectionRoot;
201   //Each coordinate system is a different cluster of point in the synth
202   QList<CoordinateSystem*> *_coordinateSystems;
203   //a dictionary mapping images id to image representation
204   QHash<int,Image> *_imageMap;
205   //tells if this synth is valid, or if errors were encountered during the import process
206   Error _state;
207   //tells the action the filter is performing during import process
208   Step _step;
209   //tells the progress (in percentage) of the step being executed
210   int _progress;
211   //during processing this string is set accordingly to the step is being executed
212   QString _info;
213   //when a SynthData is instantiated _dataReady == false
214   //until the data are downloaded from photosynth server
215   bool _dataReady;
216   ///Number of images of this synth
217   int _numImages;
218   int _imagesToDownloadCount;
219   //the callback function to inform the user about the progress of the filter
220   vcg::CallBackPos *_cb;
221   //contains import options
222   ImportSettings _settings;
223   QMutex _mutex;
224 
225 private:
226   //used to count how many responses to bin files requests have been processed
227   //when _semaphore reaches 0 _dataReady can be set to true
228   //used also to count how many responses to images requests have been processed
229   //when _semaphore reaches _numImages, all images have been downloaded
230   int _semaphore;
231   int _totalBinFilesCount;
232   //the images will be saved here
233   QString _savePath;
234 };
235 
236 /*********************
237  * Utility functions *
238  *********************/
239 
240 int readCompressedInt(QIODevice *device, bool &error);
241 float readBigEndianSingle(QIODevice *device, bool &error);
242 unsigned short readBigEndianUInt16(QIODevice *device, bool &error);
243 void printPoint(Point *p);
244 
245 #endif // SYNTHDATA_H
246