1 // -*- c-basic-offset: 4 -*-
2 /** @file ImageVariableGroup.cpp
3  *
4  *  @author James Legg
5  *
6  * @brief Implement the ImageVariableGroup class.
7  *
8  *  This is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU General Public
10  *  License as published by the Free Software Foundation; either
11  *  version 2 of the License, or (at your option) any later version.
12  *
13  *  This software is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  Lesser General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public
19  *  License along with this software. If not, see
20  *  <http://www.gnu.org/licenses/>.
21  *
22  */
23 
24 #include <hugin_utils/utils.h>
25 
26 #include "ImageVariableGroup.h"
27 
28 namespace HuginBase
29 {
30 
ConstImageVariableGroup(std::set<ImageVariableEnum> variables,const PanoramaData & pano)31 ConstImageVariableGroup::ConstImageVariableGroup(std::set<ImageVariableEnum> variables,
32                                                  const PanoramaData & pano)
33     : m_variables (variables),
34       m_pano (pano)
35 {
36     // work out the initial image number to part number matching.
37     setPartNumbers();
38 }
39 
~ConstImageVariableGroup()40 ConstImageVariableGroup::~ConstImageVariableGroup()
41 {
42 }
43 
getPartNumber(unsigned int imageNr) const44 unsigned int ConstImageVariableGroup::getPartNumber(unsigned int imageNr) const
45 {
46     DEBUG_ASSERT(imageNr < m_image_part_numbers.size());
47     DEBUG_ASSERT(m_image_part_numbers.size() == m_pano.getNrOfImages());
48     return m_image_part_numbers[imageNr];
49 }
50 
getPartsSet() const51 UIntSetVector ConstImageVariableGroup::getPartsSet() const
52 {
53     UIntSetVector result(getNumberOfParts(), HuginBase::UIntSet());
54     for (unsigned int imgNr = 0; imgNr<m_image_part_numbers.size(); ++imgNr)
55     {
56         result[m_image_part_numbers[imgNr]].insert(imgNr);
57     };
58     return result;
59 }
60 
getVarLinkedInPart(ImageVariableEnum variable,std::size_t part) const61 bool ConstImageVariableGroup::getVarLinkedInPart(ImageVariableEnum variable,
62                                                  std::size_t part) const
63 {
64     /* Variables can be linked in strange ways, but this ignores most of that.
65      * For the sake of the user interface, a variable should be linked across
66      * all images in the part, or not linked across any images in a part. This
67      * function returns true in the first case and false in the second, but is
68      * a bit weird about any other cases:
69      * If the first image in the part has links in this variable, true is
70      * returned.
71      * If the second image in the part has no links in this variable, false is
72      * returned.
73      * If there is only one image in this part, true is returned.
74      * This is just to make it fast. We could check explicitly for one of the
75      * cases above, but they are probably all that is used.
76      */
77 
78     // Have we found a unlinked image previously?
79     bool found_first = false;
80     switch (variable)
81     {
82 #define image_variable( name, type, default_value )\
83         case IVE_##name:\
84             for (std::size_t imageNr = 0; imageNr < m_pano.getNrOfImages(); imageNr++)\
85             {\
86                 if (m_image_part_numbers[imageNr] == part)\
87                 {\
88                     if (!found_first)\
89                     {\
90                         found_first = true;\
91                         if (m_pano.getImage(imageNr).name##isLinked())\
92                         {\
93                             return true;\
94                         }\
95                     } else {\
96                         return false;\
97                     }\
98                 }\
99             }\
100             break;
101 #include "image_variables.h"
102 #undef image_variable
103     }
104     // only one image found:
105     return true;
106 }
107 
unlinkVariablePart(ImageVariableEnum variable,unsigned int partNr)108 void ImageVariableGroup::unlinkVariablePart(ImageVariableEnum variable,
109                                             unsigned int partNr)
110 {
111     DEBUG_ASSERT(m_variables.find(variable) != m_variables.end());
112     // find all images in the requested part.
113     for (unsigned int i = 0; i < m_image_part_numbers.size(); i++)
114     {
115         if (m_image_part_numbers[i] == partNr)
116         {
117             // unlink the variable
118             switch (variable)
119             {
120 #define image_variable( name, type, default_value )\
121                 case IVE_##name:\
122                     m_pano.unlinkImageVariable##name(i);\
123                     break;
124 #include "image_variables.h"
125 #undef image_variable
126             }
127         }
128     }
129     setPartNumbers();
130 }
131 
unlinkVariableImage(ImageVariableEnum variable,unsigned int imageNr)132 void ImageVariableGroup::unlinkVariableImage(ImageVariableEnum variable,
133                                              unsigned int imageNr)
134 {
135     unlinkVariablePart(variable, m_image_part_numbers[imageNr]);
136 }
137 
linkVariablePart(ImageVariableEnum variable,unsigned int partNr)138 void ImageVariableGroup::linkVariablePart(ImageVariableEnum variable,
139                                           unsigned int partNr)
140 {
141     DEBUG_ASSERT(m_variables.find(variable) != m_variables.end());
142     // find all images in the requested part.
143     bool found_first_image = false;
144     int first_image_number;
145     for (unsigned int i = 0; i < m_image_part_numbers.size(); i++)
146     {
147         if (m_image_part_numbers[i] == partNr)
148         {
149             // make a note of the first image.
150             if (!found_first_image)
151             {
152                 first_image_number = i;
153                 found_first_image = true;
154                 continue;
155             }
156             // for the other images, link the variable to the first image.
157             switch (variable)
158             {
159 #define image_variable( name, type, default_value )\
160                 case IVE_##name:\
161                     m_pano.linkImageVariable##name(first_image_number, i);\
162                     break;
163 #include "image_variables.h"
164 #undef image_variable
165             }
166         }
167     }
168     setPartNumbers();
169 }
170 
linkVariableImage(ImageVariableEnum variable,unsigned int imageNr)171 void ImageVariableGroup::linkVariableImage(ImageVariableEnum variable,
172                                            unsigned int imageNr)
173 {
174     linkVariablePart(variable, m_image_part_numbers[imageNr]);
175 }
176 
switchParts(unsigned int imageNr,unsigned int partNr)177 void ImageVariableGroup::switchParts (unsigned int imageNr, unsigned int partNr)
178 {
179     if (partNr == m_image_part_numbers[imageNr])
180     {
181         // We're asked to switch an image to its own part, achieving nothing:
182         return;
183     }
184     DEBUG_TRACE("Switching image " << imageNr << " to part " << partNr);
185     if (partNr > m_num_parts)
186     {
187         DEBUG_ERROR( "Request to switch an image to a nonexistent part." );
188         return;
189     }
190     // find an image in this part.
191     unsigned int part_image_index;
192     for (part_image_index = 0; m_image_part_numbers[part_image_index] != partNr; part_image_index++);
193 
194     // Decide which variables to link.
195     // Find which variables are linked in the other image.
196     std::set<ImageVariableEnum> linked_variables;
197     for(std::set<ImageVariableEnum>::iterator i = m_variables.begin(); i != m_variables.end(); ++i)
198     {
199         switch (*i)
200         {
201 #define image_variable( name, type, default_value ) \
202             case IVE_##name: \
203                 if(m_pano.getImage(part_image_index).name##isLinked())\
204                 {\
205                     linked_variables.insert(IVE_##name);\
206                 }\
207             break;
208 #include "image_variables.h"
209 #undef image_variable
210         }
211     }
212 
213     // If none share links, link them all. The image must be the only one of its
214     // part.
215     bool singular = linked_variables.empty();
216     if (singular)
217     {
218         linked_variables = m_variables;
219     }
220 
221     // unlink the image from the part it originally was part off.
222     for(std::set<ImageVariableEnum>::iterator i = m_variables.begin(); i != m_variables.end(); ++i)
223     {
224         switch (*i)
225         {
226 #define image_variable( name, type, default_value ) \
227             case IVE_##name: \
228                 m_pano.unlinkImageVariable##name(imageNr);\
229                 break;
230 #include "image_variables.h"
231 #undef image_variable
232         }
233     }
234 
235     // link the variables
236     for(std::set<ImageVariableEnum>::iterator i = linked_variables.begin(); i != linked_variables.end(); ++i)
237     {
238         switch (*i)
239         {
240             /* part_image_index and imageNr must be different, since if they
241              * were the same, the image would have already been in the
242              * correct part. This was the first thing we checked.
243              */
244 #define image_variable( name, type, default_value ) \
245             case IVE_##name: \
246                 m_pano.linkImageVariable##name(part_image_index, imageNr);\
247                 break;
248 #include "image_variables.h"
249 #undef image_variable
250         }
251     }
252 
253     // Changing the links inherits variable values from the new lens, so the
254     // variable values may have changed and the linking certainly has.
255     m_pano.imageChanged(imageNr);
256 
257     // update the mapping of image numbers to part numbers.
258     setPartNumbers();
259 }
260 
getNumberOfParts() const261 std::size_t ConstImageVariableGroup::getNumberOfParts() const
262 {
263     return m_num_parts;
264 }
265 
updatePartNumbers()266 void ConstImageVariableGroup::updatePartNumbers()
267 {
268     setPartNumbers();
269 }
270 
setPartNumbers()271 void ConstImageVariableGroup::setPartNumbers()
272 {
273     DEBUG_TRACE("")
274     // Find links.
275     m_image_part_numbers.clear();
276     if (m_pano.getNrOfImages() == 0)
277     {
278         // no images.
279         m_num_parts = 0;
280         return;
281     }
282     /* We will keep a list of parts, containing the image number of the first
283      * image that uses that part. When we want to find if another image is in
284      * a part, we can then check if it is linked to any images in the list.
285      */
286     std::vector<std::size_t> parts_first_image;
287     // image 0 always has part 0
288     parts_first_image.push_back(0);
289     m_image_part_numbers.push_back(0);
290     for (std::size_t i = 1; i < m_pano.getNrOfImages(); i++)
291     {
292         // find a part for this image.
293         /* We use parts_first_image.size() as a flag to determine when the
294          * images is not linked to any part we have previously found, as it
295          * will be the part number when we are done. */
296         std::size_t part_number = parts_first_image.size();;
297         for (std::size_t j = 0; j < parts_first_image.size(); j++)
298         {
299             // check each variable in the group
300             for (std::set<ImageVariableEnum>::const_iterator k = m_variables.begin();
301                  (k != m_variables.end()) && (part_number != j); ++k)
302             {
303                 switch (*k)
304                 {
305                     /** @todo Check for multiple parts. If there is some complex
306                      * set of links, we may need to merge two parts together.
307                      */
308 #define image_variable( name, type, default_value ) \
309                     case IVE_##name:\
310                         if (m_pano.getImage(i).name##isLinkedWith(m_pano.getImage(parts_first_image[j]))) \
311                             part_number = j;\
312                         break;
313 #include "image_variables.h"
314 #undef image_variable
315                 }
316             }
317         }
318         // We should have a suitable part number for now.
319         m_image_part_numbers.push_back(part_number);
320         // If this is a new part, keep this image number to check links.
321         if (part_number == parts_first_image.size())
322         {
323             parts_first_image.push_back(i);
324         }
325     }
326     // set the number of parts
327     m_num_parts = parts_first_image.size();
328 
329 }
330 
331 } // HuginBase namespace
332