forked from micmacIGN/Documentation
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Doc_Qt_tools.tex
289 lines (198 loc) · 18 KB
/
Doc_Qt_tools.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
\section{Visual interfaces "vCommands"}
\subsection{Introduction}
Each command of {\tt MicMac} can be called in a command line prompt with the general syntax:
\begin{verbatim}
mm3d Command arg1 arg2 ... argn NameOpt1=Argot1 ...
\end{verbatim}
For example, a possible call to the {\tt Tapas} tool is:
\begin{verbatim}
mm3d Tapas RadialStd ".*.PEF" Out=All
\end{verbatim}
To help filling arguments for {\tt MicMac} commands, visual interfaces based on {\tt Qt} can be launched by adding the letter "v" in front of the command name. For example, a possible call to the {\tt Tapas} visual interface is:
\begin{verbatim}
mm3d vTapas
\end{verbatim}
An other possible call to the {\tt Tapas} visual interface is:
\begin{verbatim}
mm3d vTapas RadialStd ".*.PEF" Out=All
\end{verbatim}
This will fill visual interface with corresponding arguments.\\*
NB: this is also true for some commands in {\tt TestLib} such as:
\begin{verbatim}
mm3d TestLib vOriMatis2MM
\end{verbatim}
\subsection{Compilation and code}
Visual interfaces are available with option {\tt WITH\_QT4} or {\tt WITH\_QT5} activated.
\begin{verbatim}
cmake -DWITH_QT4=ON ..
\end{verbatim}
or
\begin{verbatim}
cmake -DWITH_QT5=ON ..
\end{verbatim}
If necessary, see {\tt CMakeLists.txt}.\\*
At revision 5520, code is located in:
\begin{verbatim}
include/general/visual_mainwindow.h
include/general/visual_buttons.h
src/util/visual_main_window.cpp
src/util/visual_buttons.cpp
src/util/visual_arg_main.cpp
src/util/arg_main.cpp
src/CBinaires/mm3d.cpp
\end{verbatim}
\subsection{How it works?}
Each command has a set of mandatory arguments, and may have a set of optional arguments. Basically, a visual interface is shown by parsing the two lists of mandatory and optional arguments, getting their type, and depending on their type, displaying in a widget the corresponding selection object (ComboBox, buttons, text edition field, button, or {\tt SaisieBoxQT}, etc.).\\*
This is based on \textbf{ElInitArgMain} method from {\tt arg\_main.cpp}, which is usually called in the main method for each command in {\tt MicMac}. This method fills the two lists of mandatory and optional arguments, following this syntax:
\begin{verbatim}
std::vector <char *> ElInitArgMain
(
int argc,char ** argv,
const LArgMain & LGlob,
const LArgMain & L1,
const std::string & aFirstArg = "",
bool VerifInit=EIAM_VerifInit,
bool AccUnK=EIAM_AccUnK,
int aNbArgGlobGlob = EIAM_NbArgGlobGlob
);
\end{verbatim}
{\tt LGlob} contains the list of mandatory arguments, while {\tt L1} has optional arguments.
Adding an argument is usually done like this:
\begin{verbatim}
int Function_main(int argc,char ** argv)
{
string aFullName, aOri, aPly, aOut;
ElInitArgMain
(
argc,argv,
LArgMain() << EAMC(aFullName,"Full Name (Dir+Pat)")
<< EAMC(aOri,"Orientation path")
<< EAMC(aPly,"Ply file"),
LArgMain() << EAM(aOut,"Out",true,"Output filename")
etc.
);
etc.
}
\end{verbatim}
To transform an existing {\tt MicMac} function into a function which can be launched in visual mode, one has to specify the type of the arguments. For example, here:
\begin{verbatim}
int Function_main(int argc,char ** argv)
{
string aFullName, aOri, aPly, aOut;
ElInitArgMain
(
argc,argv,
LArgMain() << EAMC(aFullName,"Full Name (Dir+Pat)",eSAM_IsPatFile)
<< EAMC(aOri,"Orientation path",eSAM_IsExistDirOri)
<< EAMC(aPly,"Ply file", eSAM_IsExistFile),
LArgMain() << EAM(aOut,"Out",true,"Output filename")
etc.
);
etc.
}
\end{verbatim}
The arguments types can be:\\*
\begin{itemize}
\item {\tt eSAM\_IsPatFile}, for a pattern string,
\item {\tt eSAM\_IsBool}, for a bool,
\item {\tt eSAM\_IsPowerOf2}, for an integer power of 2
\item {\tt eSAM\_IsDir}, for a directory string
\item {\tt eSAM\_IsExistDirOri}, for an existing Orientation directory string,
\item {\tt eSAM\_IsOutputDirOri}, for an Output Orientation directory string,
\item {\tt eSAM\_IsExistFile}, for an existing file string,
\item {\tt eSAM\_IsExistFileRP}, for an existing file to be given with a relative path
\item {\tt eSAM\_IsOutputFile}, for an output file string,
\item {\tt eSAM\_Normalize}, for a 2d box that has to be normalized (Box2dr),
\item {\tt eSAM\_NoInit}, for an argument that has not been initialized,
\item {\tt eSAM\_InternalUse}, for an argument that we don't want to display in the visual interface,
\item {\tt eSAM\_None}, for a list of strings.\\*
\end{itemize}
Type has not to be specified for an integer, a float, a point ({\tt Pt2di}, {\tt Pt2dr}), a box terrain ({\tt Box2dr}).\\*
To check if a visual interface has to be launched a global variable {\tt MMVisualMode} is set to {\tt true} in {\tt GenMain} in {\tt src/CBinaires/mm3d.cpp}. When calling {\tt mm3d} for a visual interface, we first run the {\tt Function\_main} with its \textbf{ElInitArgMain} to fill the visual interface, then we run a second time {\tt mm3d} with {\tt MMVisualMode} set to {\tt false}, to take into account modifications done in the visual interface, and to run the actual process.\\*
At the first call to {\tt Function\_main}, we just want to go through \textbf{ElInitArgMain}, to show the visual interface, so we need to exit this function without doing the main process. This is why we have to add after \textbf{ElInitArgMain}:
\begin{verbatim}
if (MMVisualMode) return EXIT_SUCCESS;
\end{verbatim}
Another small trick is done to enable user to set some arguments directly in the command line (which will be automatically filled in the visual interface). If command line contains more than {\tt mm3d vCommmand}, we initialize arguments with these values by a call to \textbf{ElInitArgMain} in {\tt arg\_main.cpp}.
\begin{verbatim}
if(argc > 1)
{
MMVisualMode = false;
ElInitArgMain(argc,argv,LGlob,L1,aFirstArg,VerifInit,AccUnK,aNbArgGlobGlob);
MMVisualMode = true;
}
\end{verbatim}
NB: there is a bug in this part, since we check if an argument has been modified in the visual interface, and this state is set to unchanged when we call \textbf{ElInitArgMain} twice.\\*
In \textbf{ElInitArgMain}, \textbf{aFirstArg} is used to set the widget title.
\subsection{\textbf{visual\_MainWindow} class}
In {\tt include/general/visual\_mainwindow.h}, we define a class derived from \textbf{QWidget}, \textbf{ visual\_MainWindow}. A \textbf{visual\_MainWindow} is mainly composed of 2 \textbf{QGridLayout} where mandatory and optional arguments are displayed in rows. Optional arguments are sorted with regard to their name (\textbf{cMMSpecArg::NameArg()}). At the widget's bottom, a button "{\tt Run command}" runs the command with the selected arguments (\textit{slot} \textbf{onRunCommandPressed}) ; a checkbox "{\tt Show dialog when job is done}" allows user to continue working, and force a dialog to pop up when process is finished.\\*
Depending on the argument's type, specific objects are created in the corresponding row (see \textbf{buildUI} method). A label is added systematically at the left (see \textbf{add\_label} method), using argument comment (for mandatory argument) or name (for optional argument). A tool tip is added for optional arguments with comment, and is shown (when available) by putting cursor over the argument name.\\*
Dealing with files: many commands need several files, and sometimes several directories, which may be located in the same directory. To help choosing these files or directory, we store the first directory (\textbf{mLastDir}). We also store this directory in application settings, so that, at next call, the first open dialog is set to the last directory.\\*
Pushing "{\tt Run command}" button, we parse vector \textbf{vInputs} that stores the argument (as \textbf{ cMMSpecArg}), and build command line {\tt aCom} for {\tt mm3d}, adding only arguments that has been changed (see \textbf{cMMSpecArg::IsDefaultValue()}).
\subsection{Specific functions: vTapioca, vMalt, vC3DC, vSake}
Some functions have a slightly different workflow and behavior than the majority. These functions need to choose between several modes before calling \textbf{ElInitArgMain}. This mode is recovered with a \textbf{ QInputDialog}. See for example {\tt CPP\_Tapioca.cpp}.\\*
{\tt vMalt} has also some specific behavior depending on mode (Ortho, UrbanMNE, GeomImage). This is dealt in function \textbf{visual\_MainWindow::moveArgs} with boolean \textbf{\_bMaltGeomImg}. {\tt vMalt} has also two small special behaviors, dealt with function \textbf{isFirstArgMalt}: disabling mandatory argument edition after choosing mode in \textbf{add\_select}, and recovering mode in the final command line in \textbf{onRunCommandPressed}.
\subsection{ {\tt BoxClip} and {\tt BoxTerrain} }
Some functions need a 2d rectangular selection information (mainly to perform computations on reduced area). Most of the time, argument name are {\tt BoxClip} and {\tt BoxTerrain}. Previously, user had to measure two corners coordinates in image, and sometimes normalize these coordinates, then type argument for example, {\tt BoxClip=[0.13,0.11,0.89,0.87]}. Here, we use a new tool based on {\tt SaisieQT} (see next chapter), called {\tt SaisieBoxQT}, which is launched with "Selection editor" button (see \textbf{visual\_MainWindow::onSaisieButtonPressed}). User first choose which image to open, then draw a rectangle by click-n-drag in the image. User can also edit the rectangle selection afterward, by clicking close to a corner and drag it.
We must deal here with 3 cases: true image coordinates, normalized image coordinates, and box terrain coordinates.
Normalization is specified using {\tt eSAM\_Normalize}. Difference between box image and box terrain is done with the argument type (\textbf{Box2di} or \textbf{Box2dr}). For a box terrain, a {\tt FileOriMnt xml} has to be read to convert image coordinates to terrain coordinates through function \textbf{ visual\_MainWindow::transfoTerrain}.
\section{SaisieQT}
\subsection{Introduction}
{\tt SaisieQT} is a Qt application gathering a set of commands designed to mimic and extend the {\tt SaisiePts} X11 tool originally used for measuring data in images for {\tt MicMac}. It is cross-platform.
At revision 5520, there is 6 Qt tools: {\tt SaisieMasqQT}, {\tt SaisieAppuisInitQT}, {\tt SaisieAppuisPredicQT}, {\tt SaisieCylQT}, {\tt SaisieBascQT} and {\tt SaisieBoxQT}.\\*
{\tt SaisieMasqQT}, {\tt SaisieAppuisInitQT}, {\tt SaisieAppuisPredicQT}, {\tt SaisieCylQT} and {\tt SaisieBascQT} are designed as independent applications, while {\tt SaisieBoxQT} is, for now, only called through the visual interfaces (it does not output measures in a {\tt xml} file, it only sends data through \textit{slot/signal} connections.
\subsection{Compilation and code}
SaisieQT tools are available with option {\tt WITH\_QT4} or {\tt WITH\_QT5} activated.
\begin{verbatim}
cmake -DWITH_QT4=ON ..
\end{verbatim}
or
\begin{verbatim}
cmake -DWITH_QT5=ON ..
\end{verbatim}
If necessary, see {\tt CMakeLists.txt} and {\tt src/SaisieQT/CMakeLists.txt}.\\*
At revision 5520, code is located in:
\begin{verbatim}
src/uti_phgrm/CPP_SaisieQT.cpp
src/SaisieQT/
include/qt/
\end{verbatim}
When building binaries, one has to copy translation files {\tt .qm} and style sheet {\tt .qss} from {\tt include/qt/} in the same directory, next to {\tt bin/} directory. Scripts that build binaries and packages already do this, but this is to be remembered.
\subsection{How it works?}
{\tt SaisieQT} is a unique binary, based on a core structure deriving from \textbf{QMainWindow} (for now) and from \textbf{GLWidgetSet}: \textbf{SaisieQtWindow}. To follow and conform to the \textit{universal} command {\tt mm3d} an alias command is defined in {\tt src/uti\_phgrm/CPP\_SaisieQT.cpp} so
\begin{verbatim}
mm3d SaisieMasqQT IMG_5059.JPG
\end{verbatim}
actually runs:
\begin{verbatim}
SaisieQT SaisieMasqQT IMG_5059.JPG
\end{verbatim}
{\tt SaisieQT} then dispatches to each function main in {\tt SaisieQT/main/saisieQT\_main.cpp} depending on second argument ({\tt SaisieMasqQT} etc.).\\*
All applications share the same style sheet, loaded in {\tt saisieQT\_main.cpp} and stored in {\tt include/qt/style.qss}.\\*
Each application has its own settings (stored depending on the OS). Most of the settings can be edited through a \textbf{QDialog}: \textbf{cSettingsDialog} defined in {\tt include\_QT/Settings.h}.\\*
Switching between each application in code is managed with private member \textbf{\_appMode} of \textbf{ SaisieQtWindow} class. Corresponding enum is defined in {\tt include\_QT/Settings.h}.\\*
Some of the Saisie Qt tools make use of Elise library, and use the same core as {\tt SaisiePts} to compute 3D points from image measures, epipolar lines, etc. To mimic the way {\tt SaisiePts} works, a class \textbf{cVirtualInterface} has been created in {\tt include/SaisiePts/SaisiePts.h}. This class owns all methods that are shared both by {\tt SaisiePts} and {\tt SaisieQT}. Two classes derive from this mostly virtual class: \textbf{cX11\_Interface} in {\tt SaisiePts}, and \textbf{cQT\_Interface} in {\tt SaisieQT}.\textbf{ cQT\_Interface} needs {\tt cAppli\_SaisiePts} and a \textbf{ SaisieQtWindow} to be instantiated.
\subsection{SaisieMasqQT}
{\tt SaisieMasqQT} has 2 modes: a 2D mask selection mode, like X11 {\tt SaisieMasq}, and a 3D mask selection mode, useful for {\tt C3DC} command. {\tt SaisieMasqQT} uses the same command line arguments as {\tt SaisieMasq} which are read in \textbf{saisieMasq\_ElInitArgMain}, function common to both. Theses arguments are provided to \textbf{SaisieQtWindow} afterward.\\*
All the data in {\tt SaisieMasqQT} are rendered in an OpenGL context. These data are stored in \textbf{ cGLData} class. We use an ortho projection to render them (see \textbf{MatrixManager::mglOrtho}). The main container, after \textbf{SaisieQtWindow}, is \textbf{GLWidget} (derived from \textbf{QGLWidget}). Projection matrix and projection functions (from image to window, and back) can be found in \textbf{ MatrixManager} class.
\subsubsection{2D mode}
In 2D mode, {\tt SaisieMasqQT} loads one image, and displays it in the center of the viewport.\\*
An image, at first glance, is stored as a \textbf{cMaskedImageGL} ({\tt 3DObject.h}) which contains both image data and mask information.\\*
To deal with some very big images, we show a rescaled image in full size, and draw only visible tiles, at full scale when zooming in image. In this case, while loading image, a scale factor is computed, and a rescaled image is stored, next to the original image in \textbf{cMaskedImageGL}, and a vector of full scale image tiles in \textbf{cGLData::\_glMaskedTiles}.\\*
An image is drawn as a {\tt GL\_QUAD} (see \textbf{cImageGL::drawQuad}). When a mask has been measured, it is blended over the image (see \textbf{cMaskedImageGL::draw()}).\\*
Drawing vector data (polygons, points, text) is done in \textbf{GLWidget::overlay()}.\\*
Editing a mask is done in \textbf{cGLData::editImageMask} ({\tt cGLData.cpp}) by drawing a polygon (class \textbf{cPolygon}).
\subsubsection{3D mode}
3D mode allows loading a ply file (only point clouds, for now). 6 ply formats are currently managed (xyz, xyzrgb, xyz nx ny nz, xyzrgba, xyz nx ny nz rgb, xyz nx ny nz rgba) (see \textbf{GlCloud::loadPly}).\\*
There is two interaction modes: selection (one can draw a polygon, as in 2D mode), and move (rotate or translate camera). In \textbf{GLWidget} switching between the two modes is done with \textbf{getInteractionMode()} and \textbf{m\_interactionMode}. In the \textit{gui}, {\tt F9} shortcut switches between the 2 modes.\\*
Editing a mask is done in \textbf{cGLData::editCloudMask} ({\tt cGLData.cpp}). Editing a mask consists of two different operations: for each 3d point, decide if it is inside or outside the mask, and also store the mask selection information (to be able to recover the mask from other {\tt mm3d} commands, such as {\tt C3DC}). A mask consists of the intersection of several 3D cones, each 3D cone being defined by a 3D polygon (the cone section) and a direction. 3D polygon is built from the 2D polygon drawn in viewport and its camera and matrix information. Cone direction is known from camera orientation. So for each couple (polygonal selection-openGL camera), a virtual 3D cone has to be stored (see \ref{Conv:selection}). These information are stored in a vector of \textbf{selectInfos}, in \textbf{HistoryManager}. This allows to undo/redo actions, and also to edit actions through a \textbf{QAbstractTableModel} (QTableView \textbf{tableView\_Objects}).
\subsection{SaisieAppuisInitQT and SaisieAppuisPredicQT}
In {\tt SaisieAppuisInitQT} and {\tt SaisieAppuisPredicQT}, we use the same \textbf{cPolygon} object to draw a set of points, but we don't draw lines between points. This is done with boolean \textbf{\_bShowLines} in \textbf{cPolygon}, which can be checked with method \textbf{cPolygon::isLinear()}.\\*
\subsection{SaisieBascQT}
Mode=0 in {\tt src/uti\_phgrm/CPP\_SaisieQT.cpp} \\*
At this point, {\tt SaisieBascQT} has exactly the same behavior as {\tt SaisieBasc}: lines are drawn as two points, while it may be useful to display the complete line.
\subsection{SaisieCylQT}
Mode=1 in {\tt src/uti\_phgrm/CPP\_SaisieQT.cpp}
\subsection{SaisieBoxQT}
{\tt SaisieBoxQT} is a very simple use of \textbf{SaisieQtWindow}: it shows an image, allow to draw a \textbf{ cRectangle}, which is a \textbf{cPolygon} with 4 points defined in {\tt cObject.h}. At this point, {\tt SaisieBoxQT} is only meant to communicate with a visual interface (such as {\tt vMalt}) and we only send a \textit{signal} with\\ \textbf{void newRectanglePosition(QVector <QPointF> points)} in \textbf{ GLWidget::mouseMoveEvent}. This \textit{signal} is connected to \textbf{onRectanglePositionChanged} in \textbf{visual\_MainWindow::onSaisieButtonPressed} in {\tt visual\_mainWindow.cpp}.
{\tt SaisieBoxQT} is instantiated in \textbf{visual\_mainWindow} constructor ({\tt visual\_mainWindow.cpp}).