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