Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
VertexCoordRemapper.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
2 
23 #include "panoinc_WX.h"
24 #include "panoinc.h"
25 
26 #include "VertexCoordRemapper.h"
27 #include <math.h>
28 #include <iostream>
29 #include "ViewState.h"
30 
31 #include "panodata/SrcPanoImage.h"
32 
33 /*******************
34  * Face's bit flags
35  *******************/
36 // split_x is set if the node has been split into two children (subdivided) in x
37 const unsigned short int split_flag_x = 1;
38 // patch_flag_x is set if we are patching a hole / overlap that could be caused
39 // by the subdivision in the previous x location being more dense. It is set
40 // instead of split_flag_x, but we subdivide into faces that do not provide more
41 // detail except to the side where there is higher subdivision.
42 const unsigned short int patch_flag_x = 2;
43 // set if we have subdivided into two halves in the y direction
44 const unsigned short int split_flag_y = 4;
45 // patch misalignment due to higher subdivision a bit lower in the y direction.
46 const unsigned short int patch_flag_y = 8;
47 // We flag vertices in faces that should be two faces over each edge of the
48 // panorama's 180 degree seem, such that by flipping the flagged vertices to
49 // the other side we get a valid face for one side, and by flipping those not
50 // flagged we get the other.
51 const unsigned short int vertex_side_flag_start = 16;
52 // 32, 64 and 128 are for the other vertices.
53 // if the tranformation can't find a result, we set flags to indicate the
54 // vertices we had a problem with.
55 const unsigned short int transform_fail_flag = 256;
56 // 512, 1024, and 2048 are for the other vertices
57 
58 /* where we have a set of flags refering to different vertices, vertex [x][y]
59  * corresponds with first_vertex_flag << (y * 2 + x).
60  */
61 
62 
63 /*************************************
64  * Detail / Acuracy / Speed Tradeoffs
65  *************************************/
66 // Range of acceptable subdivision stopping points:
67 // Depth of forced subdivisions. Increase if there are transformations that show
68 // no signs of increasing detail level until subdivided more times, or cause
69 // problems with the seam detection.
70 const unsigned int min_depth = 4;
71 // Depth at which subdivision stops.
72 // When adjusting also adjust this, also adjust the definition of Tree's nodes
73 // to account for the extra memory required. A high value uses more memory,
74 // a low value limits the detail. The amount of elements in the array should be
75 // the sum from n = 0 to max_depth of 4^n. (so for n=6, 1+4+16+64+256+2048+4096)
76 const unsigned int max_depth = 6;
77 
78 // this is the length in screen pixels under which no subdivision occurs.
79 // higher values are faster, lower ones more accurate.
80 // TODO user preference? Increase during interactive changes?
81 const double min_length = 14.0;
82 // the angle in radians under which no subdivision occurs. Again, higher values
83 // will make it faster, lower ones will give higher accuracy. must be positive.
84 const double min_angle = 0.06;
85 // the distance in absolute screen pixels between twice the length of the
86 // children and the length of the parent nodes, under which no subdivision
87 // occurs. higher values are faster, lower values give higher accuracy. Must be
88 // positive.
89 const double min_length_difference = 3.0;
90 // This is the margin around the edge of the screen in pixels, outside of which
91 // any face is not subdivided. Higher values are less likely to crop small
92 // features from the edge of the display, lower values add speed when there is
93 // faces that are significantly off-screen. It can be any number, but only
94 // positive numbers are recommended.
95 const double offscreen_safety_margin = 10.0;
96 
97 template <class T>
98 inline T sqr(T val)
99 {
100  return val * val;
101 };
102 
105  VisualizationState *visualization_state_in)
106  : MeshRemapper(m_pano_in, image, visualization_state_in)
107 {
108 
109 }
110 
112 {
113  DEBUG_DEBUG("mesh update update reset index");
114  // this sets scale, height, and width.
116  // we need to record the output projection for flipping around 180 degrees.
120  // we want to make a remapped mesh, get the transformation we need:
121 // HuginBase::SrcPanoImage *src = visualization_state->GetSrcImage(image_number);
123  // use the scale to determine edge lengths in pixels for subdivision
124 // DEBUG_INFO("updating mesh for image " << image_number << ", using scale "
125 // << scale << ".\n");
126  // find key points used for +/- 180 degree boundary correction
127  // {x|y}_add_360's are added to a value near the left/top boundary to get
128  // the corresponding point over the right/bottom boundary.
129  // other values are used to check where the boundary is.
131  x_add_360 = info->GetXAdd360();
132  radius = info->GetRadius();
133  y_add_360 = info->GetYAdd360();
134  x_midpoint = info->GetMiddleX();
135  y_midpoint = info->GetMiddleY();
136  lower_bound = info->GetLowerX();
137  upper_bound = info->GetUpperX();
138  lower_bound_h = info->GetLowerY();
139  upper_bound_h = info->GetUpperY();
140  // Find the cropping region of the source image, so we can stick to the
141  // bounding rectangle.
142  SetCrop();
143  // the tree needs to know how to use the croping information for generating
148  // make the tree reflect the transformation
149  RecursiveUpdate(0, 0, 0);
150  // now set up for examining the tree contents.
151  tree.ResetIndex();
152  done_node = true;
153 }
154 
156 {
157 // DEBUG_DEBUG("mesh update get face coords");
158  result->tex_c = tex_coords;
159  result->vertex_c = s_vertex_coords;
160  // if we have some faces left over from a previous clipping operation, give
161  // one of those first:
162  if (GiveClipFaceResult(result)) return true;
163  // when 180 degree bounds correction is working, we'll have two nodes.
164  if (done_node)
165  {
166  do
167  {
168  // this will search the tree for the next leaf node.
170  if (!tree_node_id)
171  {
172  // we've reached last one
173  return false;
174  }
175  }
176  // some of the verticies may have arrived from undefined transformations
177  // if this is one, skip it and try to find another.
178  while ((tree.nodes[tree_node_id].flags & (transform_fail_flag * 15)));
179 
180  // find the coordinates from the tree node
181  result->vertex_c = tree.nodes[tree_node_id].verts;
182  // check that the transformation is properly defined.
183 
185  // if the node has a discontinuity, we want to split it into two
186  // faces and return each one on consecutive calls.
190  {
191  done_node = false;
192  // flip the marked nodes to the other side. copy the coordinates 1st
193  result->vertex_c = s_vertex_coords;
194  for (short unsigned int x = 0; x < 2; x++)
195  {
196  for (short unsigned int y = 0; y < 2; y++)
197  {
198  s_vertex_coords[x][y][0] =
199  tree.nodes[tree_node_id].verts[x][y][0];
200  s_vertex_coords[x][y][1] =
201  tree.nodes[tree_node_id].verts[x][y][1];
202  if (discontinuity_flags & (1 << (x*2 + y)))
203  {
205  }
206  }
207  }
208  }
209  } else {
210  // we flip the other vertices to the ones we did last time.
211  done_node = true;
212  for (short unsigned int x = 0; x < 2; x++)
213  {
214  for (short unsigned int y = 0; y < 2; y++)
215  {
216  s_vertex_coords[x][y][0] =
217  tree.nodes[tree_node_id].verts[x][y][0];
218  s_vertex_coords[x][y][1] =
219  tree.nodes[tree_node_id].verts[x][y][1];
220  if (!(discontinuity_flags & (1 << (x*2 + y))))
221  {
223  }
224  }
225  }
226  }
227  // if we are doing circular cropping, clip the face so it makes the shape
228  if (circle_crop)
229  {
230  // If all points are within the radius, then don't clip
231 // HuginBase::SrcPanoImage *src_img = visualization_state->GetSrcImage(image_number);
232  if ( image->isInside(vigra::Point2D(int(result->tex_c[0][0][0] * width),
233  int(result->tex_c[0][0][1] * height)))
234  && image->isInside(vigra::Point2D(int(result->tex_c[0][1][0] * width),
235  int(result->tex_c[0][1][1] * height)))
236  && image->isInside(vigra::Point2D(int(result->tex_c[1][0][0] * width),
237  int(result->tex_c[1][0][1] * height)))
238  && image->isInside(vigra::Point2D(int(result->tex_c[1][1][0] * width),
239  int(result->tex_c[1][1][1] * height))))
240  {
241  // all inside, doesn't need clipping.
242  return true;
243  }
244  // we do need to clip:
245  ClipFace(result);
246  // if there was anything left, return the first face and leave the rest
247  // for later.
248  if (GiveClipFaceResult(result)) return true;
249  // we clipped to nothing... try and get another face: from the top...
250  return (GetNextFaceCoordinates(result));
251  }
252  return true;
253 }
254 
256 {
257  // we want to flip the given vertex to be the other side of the 180 degree
258  // boundary, whatever the projection format.
259  switch (output_projection)
260  {
262  // There is no 180 degree boundary for rectilinear projections.
263  // Anything containing a vertex beyond 90 degrees (i.e. behind the
265  break;
273  // circular projections. These stretch rather nastily over the
274  // centre, and correcting them doesn't help much, so any image
275  // covering the outer circle is switched to a TexCoordRemapper.
276  break;
283  // flip to the other direction of the other side horizontally.
284  if (vertex_c[0] < x_midpoint) vertex_c[0] += x_add_360;
285  else vertex_c[0] -= x_add_360;
286  break;
289  if (vertex_c[0] < x_midpoint)
290  {
291  vertex_c[0] +=
293  } else {
294  vertex_c[0] -=
296  }
297  break;
299  // flip to the other direction of the other side vertically
300  if (vertex_c[1] < y_midpoint) vertex_c[1] += y_add_360;
301  else vertex_c[1] -= y_add_360;
302  break;
303  default:
304  // all other projection, no special handling
305  break;
306  }
307 }
308 
309 void VertexCoordRemapper::RecursiveUpdate(unsigned int node_num,
310  unsigned int stretch_x, unsigned stretch_y)
311 {
312  // find where we are and what we are mapping
313  // TODO? GetPosition is called by GetInputCoordinates, reuse results?
314  unsigned int x, y, row_size, depth;
315  tree.GetPosition(node_num, x, y, row_size, depth);
317  TreeNode *node = &tree.nodes[node_num],
318  *parent = (depth) ?
319  &tree.nodes[tree.GetParentId(x, y, row_size, depth)] : 0,
320  *left = (x % 2) ?
321  &tree.nodes[tree.GetIndex(x-1, y, row_size, depth)] : 0,
322  *top = (y % 2) ?
323  &tree.nodes[tree.GetIndex(x, y-1, row_size, depth)] : 0;
324  bool valid[2][2];
325  for (unsigned short int i = 0; i < 2; i++)
326  {
327  for (unsigned short int j = 0; j < 2; j++)
328  {
329  if (depth == 0)
330  {
331  // the top level has no parent, so we must calculate all points
332  valid[i][j] =
333  transform.transformImgCoord(node->verts[i][j][0],
334  node->verts[i][j][1],
335  tex_coords[i][j][0] * width,
336  tex_coords[i][j][1] * height);
337  } else
338  // Look up where the point in the tree so far. If this is the first
339  // occurrence of this point, we'll calculate the value.
340  if (i == x %2 && j == y%2 && depth)
341  {
342  // extract a corner from the parent.
343  node->verts[i][j][0] = parent->verts[i][j][0];
344  node->verts[i][j][1] = parent->verts[i][j][1];
345  valid[i][j] = !(parent->flags & (transform_fail_flag << (j*2 +i)));
346  } else if (x % 2 && !i) {
347  // copy from the left
348  node->verts[0][j][0] = left->verts[1][j][0];
349  node->verts[0][j][1] = left->verts[1][j][1];
350  valid[i][j] = !(left->flags & (transform_fail_flag << (j *2 + 1)));
351  } else if (y % 2 && !j) {
352  // copy from the top
353  node->verts[i][0][0] = top->verts[i][1][0];
354  node->verts[i][0][1] = top->verts[i][1][1];
355  valid[i][j] = !(top->flags & (transform_fail_flag << (2 + i)));
356  } else {
357  // We can't find it easily, try a more expensive search.
358  // this will linearly interpolate along the edges where the
359  // subdivision was higher, avoiding gaps when the detail level
360  // was lower above or to the left.
361  if (!tree.GetTransform(x + i * (1 << stretch_x),
362  y + j * (1 << stretch_y),
363  depth, x, y, node->verts[i][j][0],
364  node->verts[i][j][1]))
365  {
366  // We can't find it, so calculate it:
367  valid[i][j] =
368  transform.transformImgCoord(node->verts[i][j][0],
369  node->verts[i][j][1],
370  tex_coords[i][j][0] * width,
371  tex_coords[i][j][1] * height);
372  // If the face results from a patch subdivision (for
373  // aligning a subdivided face, otherwise it need not exist),
374  // use the midpoint of the parent's vertices instead of
375  // calculating a transformed one, so we can use less
376  // subdivision on the other side.
377  // subdivision in x
378  // FIXME there are still gaps. I think there's a logic error
379  if ( depth // not on the top level.
380  // patching in y
381  && (parent->flags & patch_flag_x)
382  // we must be in the middle of the split, the nodes on
383  // the corners of the parent line up anyway.
384  && ((i + x) % 2)
385  // we should be on the side away from the subdivison
386  // (+ve y).
387  && j
388  // If we are alao split in y we can use the middle
389  // node to provide more detail.
390  && (!((parent->flags & split_flag_y) && !(y % 2)))
391  // don't do this if we cross the 180 degree seam
392  && (!(parent->flags & (vertex_side_flag_start * 15))))
393  {
394  node->verts[i][1][0] = (parent->verts[0][1][0]
395  + parent->verts[1][1][0]) / 2.0;
396  node->verts[i][1][1] = (parent->verts[0][1][1]
397  + parent->verts[1][1][1]) / 2.0;
398  }
399  // subdivision in y
400  if ( depth
401  && (parent->flags & patch_flag_y)
402  && ((j + y) % 2)
403  && i
404  && (!((parent->flags & split_flag_x) && !(x % 2)))
405  && (!(parent->flags & (vertex_side_flag_start * 15))))
406  {
407  node->verts[1][j][0] = (parent->verts[1][0][0]
408  + parent->verts[1][1][0]) / 2.0;
409  node->verts[1][j][1] = (parent->verts[1][0][1]
410  + parent->verts[1][1][1]) / 2.0;
411  }
412  } else {
413  // we managed to find it from data already known.
414  valid[i][j] = true;
415  }
416  }
417  }
418  }
419 
420  // now for the recursion
421  // which directions should we divide in?
422  TestSubdivide(node_num);
423  // add the flags for invlaid transormations
424  for (unsigned int i = 0; i < 2; i++)
425  {
426  for (unsigned int j = 0; j < 2; j++)
427  {
428  if (!valid[i][j])
429  {
430  node->flags |= transform_fail_flag << (j * 2 + i);
431  }
432  }
433  }
434  // if the face should be split, now recurse to the child nodes.
435  if (node->flags & (split_flag_x | split_flag_y))
436  {
437  // we will split at least one way.
438  if (!(node->flags & split_flag_x))
439  {
440  // we are not splitting across x, but will will across y.
441  // so the quad will be twice as wide
442  stretch_x++;
443  }
444  else if (!(node->flags & split_flag_y))
445  {
446  stretch_y++;
447  }
448  // find the top left sub-quad
449  x *= 2;
450  y *= 2;
451  row_size *= 2;
452  depth++;
453  // the top left is always generated
454  RecursiveUpdate(tree.GetIndex(x, y, row_size, depth),
455  stretch_x, stretch_y);
456  // split in x
457  if (node->flags & split_flag_x)
458  {
459  RecursiveUpdate(tree.GetIndex(x + 1, y, row_size, depth),
460  stretch_x, stretch_y);
461  }
462  // split in y
463  if (node->flags & split_flag_y)
464  {
465  RecursiveUpdate(tree.GetIndex(x, y + 1, row_size, depth),
466  stretch_x, stretch_y);
467  // if we are splitting in both directions, do the lower right corner
468  if (node->flags & split_flag_x)
469  {
470  RecursiveUpdate(tree.GetIndex(x + 1, y + 1, row_size, depth),
471  stretch_x, stretch_y);
472  }
473  }
474  }
475 }
476 
477 void VertexCoordRemapper::TestSubdivide(unsigned int node_id)
478 {
479  TreeNode *node = &tree.nodes[node_id];
480  unsigned int x, y, row_size, depth;
481  tree.GetPosition(node_id, x, y, row_size, depth);
482  unsigned short int flags = 0;
483  if (depth < min_depth)
484  {
485  // subdivide at least min_depth times
486  // we will need more information for non-trivial children
487  SetLengthAndAngle(node);
488  flags |= split_flag_x | split_flag_y;
489  } else {
490  unsigned int parent_id = tree.GetParentId(node_id);
491  TreeNode *parent = &tree.nodes[parent_id];
492  // minimum length check. We use the length of the top edge to test for
493  // subdivision in x, and the length of the left edge for subdivision in
494  // y.
495  SetLengthAndAngle(node);
496  bool do_not_split_x = node->length_x * scale < min_length,
497  do_not_split_y = node->length_y * scale < min_length;
498  if (depth == max_depth)
499  {
500  // don't subdivide more than max_depth times
501  do_not_split_x = true;
502  do_not_split_y = true;
503  }
504  // if we have stopped splitting in some direction, don't consider
505  // splitting in that direction again.
506  if (!(tree.nodes[parent_id].flags & split_flag_x))
507  {
508  do_not_split_x = true;
509  }
510  else if (!(tree.nodes[parent_id].flags & split_flag_y))
511  {
512  do_not_split_y = true;
513  }
514  // if it has only subdivided to patch up between two subdivision levels,
515  // don't consider subdividing for adding more detail.
516  if (tree.nodes[parent_id].flags & patch_flag_x)
517  {
518  do_not_split_x = true;
519  }
520  else if (tree.nodes[parent_id].flags & patch_flag_y)
521  {
522  do_not_split_y = true;
523  }
524 
525  // If the angles have deviated too much from the parent then we should
526  // add more detail, however if it is fairly flat then we don't need to.
527  // It is possible for the angles to remain constant but the length
528  // of the lines to change dramatically, so we check for a big difference
529  // between the length of the parent node and twice the length of child.
530  // if the child does not change the length much and the angle is small,
531  // then we have enough detail, and we don't split.
532  float ang_x = node->angle_x - parent->angle_x;
533  if (ang_x < 0) ang_x = -ang_x;
534  if (ang_x > M_PI) ang_x = 2 * M_PI - ang_x;
535  float length_difference_x
536  = (parent->length_x - (2.0 * node->length_x)) * scale;
537  if (length_difference_x < 0.0)
538  {
539  length_difference_x = -length_difference_x;
540  }
541  if (ang_x < min_angle && length_difference_x < min_length_difference)
542  {
543  do_not_split_x = true;
544  }
545  float ang_y = node->angle_y - parent->angle_y;
546  if (ang_y < 0) ang_y = -ang_y;
547  if (ang_y > M_PI) ang_y = 2 * M_PI - ang_y;
548  float length_difference_y
549  = (parent->length_y - (2.0 * node->length_y)) * scale;
550  if (length_difference_y < 0.0)
551  {
552  length_difference_y = -length_difference_y;
553  }
554  if (ang_y < min_angle && length_difference_y < min_length_difference)
555  {
556  do_not_split_y = true;
557  }
558  // if the face is entirely off the screen, we should not subdivide it.
559  // get the screen area
560  vigra::Rect2D viewport = visualization_state->GetVisibleArea();
561  // add a margin for safety, we don't want to clip too much stuff that
562  // curls back on to the screen. We add 2 as we need some space around
563  // very small panoramas that have enlarged to fit the preview window,
564  // and even with a fairly large margin rounding to int may lose the
565  // border completely.
566  viewport.addBorder((int) (2.0 + offscreen_safety_margin * scale));
567  bool all_left = true, all_right = true,
568  all_above = true, all_bellow = true;
569  for (unsigned int ix = 0; ix < 2; ix++)
570  {
571  for (unsigned int iy = 0; iy < 2; iy++)
572  {
573  if (node->verts[ix][iy][0] > viewport.left())
574  all_left = false;
575  if (node->verts[ix][iy][0] < viewport.right())
576  all_right = false;
577  if (node->verts[ix][iy][1] > viewport.top())
578  all_above = false;
579  if (node->verts[ix][iy][1] < viewport.bottom())
580  all_bellow = false;
581  }
582  }
583  if (all_left || all_right || all_bellow || all_above)
584  {
585  // all vertices are off a side of the screen. This catches most
586  // cases where the face is off the screen. Don't allow subdivisions:
587  do_not_split_x = true;
588  do_not_split_y = true;
589  }
590  if (!do_not_split_x) flags |= split_flag_x;
591  if (!do_not_split_y) flags |= split_flag_y;
592  }
593  /* Flag the vertices on a different side of the +/-180 degree seam.
594  * We don't want to flag any vertices if the face covers a continuous
595  * area of the transformation.
596  */
597  // We don't need to mark the first few subdivisions, but this is necessary
598  // when patch subdivisions become possible.
599  if (depth >= min_depth)
600  {
601  // determine if it is likely to be non-continuous.
602  // this needs to be false for leaf-node faces in the centre that span
603  // across the '0 degree' point, and true for faces that span the +/-180
604  // degree split. It doesn't really matter what it is set to otherwise.
605  bool noncontinuous = false;
607  switch (output_projection)
608  {
610  // we don't need faces to cross from one side to another. Faces
611  // all / partially 'behind the viewer' are skipped because the
612  // vertices behind the viewer are marked.
613  break;
618  // A mesh covering the extremities of a disk projection should
619  // be using a TexCoordRemapper instead, otherwise, a point
620  // mapping to the border will be stretched across the disk.
621  break;
629  // Cylinderical-like projections have the seam across the left
630  // and right edge. We'll take any face within the middle third
631  // to be continuous, the rest possibly noncontinuous.
632  if ( node->verts[0][0][0] < lower_bound
633  || node->verts[0][0][0] > upper_bound
634  || node->verts[1][0][0] < lower_bound
635  || node->verts[1][0][0] > upper_bound
636  || node->verts[0][1][0] < lower_bound
637  || node->verts[0][1][0] > upper_bound
638  || node->verts[1][1][0] < lower_bound
639  || node->verts[1][1][0] > upper_bound)
640  {
641  noncontinuous = true;
642  // flag nodes on the right hand side.
643  if (node->verts[0][0][0] > x_midpoint)
644  {
645  flags |= vertex_side_flag_start;
646  }
647  if (node->verts[0][1][0] > x_midpoint)
648  {
649  flags |= vertex_side_flag_start * 2;
650  }
651  if (node->verts[1][0][0] > x_midpoint)
652  {
653  flags |= vertex_side_flag_start * 4;
654  }
655  if (node->verts[1][1][0] > x_midpoint)
656  {
657  flags |= vertex_side_flag_start * 8;
658  }
659  }
660  break;
662  // like above, but the bounds change with height
663  if ( node->verts[0][0][0] < i->GetLowerX(node->verts[0][0][1])
664  || node->verts[0][0][0] > i->GetUpperX(node->verts[0][0][1])
665  || node->verts[1][0][0] < i->GetLowerX(node->verts[1][0][1])
666  || node->verts[1][0][0] > i->GetUpperX(node->verts[1][0][1])
667  || node->verts[0][1][0] < i->GetLowerX(node->verts[0][1][1])
668  || node->verts[0][1][0] > i->GetUpperX(node->verts[0][1][1])
669  || node->verts[1][1][0] < i->GetLowerX(node->verts[1][1][1])
670  || node->verts[1][1][0] > i->GetUpperX(node->verts[1][1][1])
671  )
672  {
673  noncontinuous = true;
674  // flag nodes on the right hand side.
675  if (node->verts[0][0][0] > x_midpoint)
676  {
677  flags |= vertex_side_flag_start;
678  }
679  if (node->verts[0][1][0] > x_midpoint)
680  {
681  flags |= vertex_side_flag_start * 2;
682  }
683  if (node->verts[1][0][0] > x_midpoint)
684  {
685  flags |= vertex_side_flag_start * 4;
686  }
687  if (node->verts[1][1][0] > x_midpoint)
688  {
689  flags |= vertex_side_flag_start * 8;
690  }
691  }
692  break;
694  // like the cylindrical ones, but vertically.
695  if ( node->verts[0][0][1] < lower_bound_h
696  || node->verts[0][0][1] > upper_bound_h
697  || node->verts[1][0][1] < lower_bound_h
698  || node->verts[1][0][1] > upper_bound_h
699  || node->verts[0][1][1] < lower_bound_h
700  || node->verts[0][1][1] > upper_bound_h
701  || node->verts[1][1][1] < lower_bound_h
702  || node->verts[1][1][1] > upper_bound_h)
703  {
704  noncontinuous = true;
705  // flag nodes on the bottom side.
706  if (node->verts[0][0][1] > y_midpoint)
707  {
708  flags |= vertex_side_flag_start;
709  }
710  if (node->verts[0][1][1] > y_midpoint)
711  {
712  flags |= vertex_side_flag_start * 2;
713  }
714  if (node->verts[1][0][1] > y_midpoint)
715  {
716  flags |= vertex_side_flag_start * 4;
717  }
718  if (node->verts[1][1][1] > y_midpoint)
719  {
720  flags |= vertex_side_flag_start * 8;
721  }
722  }
723  break;
725  break;
726  default:
727  // all other projections, no special handling
728  break;
729  }
730  if (noncontinuous)
731  {
732  // If all the side flags are set, we only have one face on one side:
733  // Remove all of those flags and we have the same face, but we can
734  // use the presence of any flags to detect when we have two.
735  if ((flags / vertex_side_flag_start) % 16 == 15)
736  {
737  flags &= ~(vertex_side_flag_start * 15);
738  }
739  }
740  }
741 
742  node->flags = flags;
743  // check if the faces to the left are subdivided at a higher level
744  if (x && !(flags & split_flag_y) && (depth < max_depth))
745  {
746  // get the potentially more subdivided version
747  double dest_x, dest_y;
748  unsigned int subdiv_node;
749  subdiv_node = tree.GetTransform(x * 2, y * 2 + 1,
750  depth * 2,
751  x * 2, y * 2, dest_x, dest_y);
752  if (subdiv_node > node_id)
753  {
754  // we should have a more subdivided node on the left.
755  // mark it for patching up to line up with it.
756  node->flags |= split_flag_y | patch_flag_y;
757  }
758  }
759  if (y && !(flags & split_flag_x) && (depth < max_depth))
760  {
761  // get the potentially more subdivided version
762  double dest_x, dest_y;
763  unsigned int subdiv_node;
764  subdiv_node = tree.GetTransform(x * 2 + 1, y * 2,
765  depth * 2,
766  x * 2, y * 2, dest_x, dest_y);
767  if (subdiv_node > node_id)
768  {
769  // we should have a more subdivided node on the left.
770  // mark it for patching up to line up with it.
771  node->flags |= split_flag_x | patch_flag_x;
772  }
773  }
774 }
775 
777 {
778  float xdx = node->verts[0][0][0] - node->verts[1][0][0],
779  xdy = node->verts[0][0][1] - node->verts[1][0][1],
780  ydx = node->verts[0][0][0] - node->verts[0][1][0],
781  ydy = node->verts[0][0][1] - node->verts[0][1][1];
782  // this is the length of the edge with y = 0
783  node->length_x = sqrt(sqr(xdx) + sqr(xdy));
784  // this is the length of the edge with x = 0
785  node->length_y = sqrt(sqr(ydx) + sqr(ydy));
786  // find the angle of the top and left edge.
787  node->angle_x = atan2(xdy, xdx);
788  node->angle_y = atan2(ydy, ydx);
789 }
790 
791 unsigned int VertexCoordRemapper::Tree::GetParentId(const unsigned int nodenum)
792 {
793  // get the parent id of a node specifed by its index.
794  unsigned int x, y, row_size, depth;
795  GetPosition(nodenum, x, y, row_size, depth);
796  return GetParentId(x, y, row_size, depth);
797 }
798 
799 unsigned int VertexCoordRemapper::Tree::GetParentId(unsigned int x,
800  unsigned int y,
801  unsigned int row_size,
802  unsigned int depth)
803 {
804  // get the parent id of a node specified by an exact location.
805  // the parent is the one that takes the group of four elements around this
806  // one in the above depth. All the dimensions are halved.
807  x /= 2;
808  y /= 2;
809  row_size /= 2;
810  depth--;
811  return GetIndex(x, y, row_size, depth);
812 }
813 
814 unsigned int VertexCoordRemapper::Tree::GetDepth(const unsigned int node_num)
815 {
816  unsigned int depth = 0, count = 0;
817  while (node_num > count)
818  {
819  depth++;
820  count += 1 << (depth * 2);
821  }
822  return depth;
823 }
824 
825 void VertexCoordRemapper::Tree::GetPosition(const unsigned int node_num,
826  unsigned int &x, unsigned int &y,
827  unsigned int &row_size,
828  unsigned int &depth)
829 {
830  depth = GetDepth(node_num);
831  row_size = 1 << depth;
832  unsigned int sub = 0;
833  if (depth)
834  {
835  for (unsigned int d = 0; d < depth; d++)
836  {
837  sub += (1 << (d * 2));
838  }
839  }
840  unsigned int position_id = node_num - sub;
841  x = position_id % row_size;
842  y = position_id / row_size;
843 }
844 
845 unsigned int VertexCoordRemapper::Tree::GetIndex(const unsigned int x,
846  const unsigned int y,
847  const unsigned int row_size,
848  unsigned int depth)
849 {
850  unsigned int add = 0;
851  while (depth)
852  {
853  depth--;
854  add += 1 << (depth * 2);
855  }
856  return add + x + y * row_size;
857 }
858 
859 void VertexCoordRemapper::Tree::GetInputCoordinates(const unsigned int node_num,
860  double coords[2][2][2])
861 {
862  // find the coordinates of each point at the vertices in the original image.
863  // this is used to look up the remapped coordinates and provide texture
864  // coordinates.
865  // it halves in size several times depending on depth.
866  unsigned int x, y, row_size, depth;
867  GetPosition(node_num, x, y, row_size, depth);
868  // now we can locate the upper right corner
869  double row_spacing = 1.0 / (double) row_size;
870  coords[0][0][0] = row_spacing * (double) x;
871  coords[0][0][1] = row_spacing * (double) y;
872  // the extent is dependent on the direction of the subdivisions.
873  // at least one direction has an extent of row_spacing. It can double up
874  // if the parent did not subdivide in a direction, recursively up the tree.
875  bool scale_x = false;
876  double opp = 1.0;
877  if (node_num != 0)
878  {
879  unsigned int parent_id = GetParentId(x, y, row_size, depth);
880  if (!(nodes[parent_id].flags & split_flag_x))
881  {
882  while (!(nodes[parent_id].flags & split_flag_x))
883  {
884  parent_id = GetParentId(parent_id);
885  opp *= 2.0;
886  }
887  scale_x = true;
888  } else {
889  while (!(nodes[parent_id].flags & split_flag_y))
890  {
891  parent_id = GetParentId(parent_id);
892  opp *= 2.0;
893  }
894  }
895  }
896  opp *= row_spacing;
897  coords[1][0][0] = coords[0][0][0] + (scale_x ? opp : row_spacing);
898  coords[1][0][1] = coords[0][0][1];
899  coords[0][1][0] = coords[0][0][0];
900  coords[0][1][1] = coords[0][0][1] + (scale_x ? row_spacing : opp);
901  coords[1][1][0] = coords[1][0][0];
902  coords[1][1][1] = coords[0][1][1];
903  // now we transform the results so that we map to the cropped region instead
904  // of the whole image.
905  for (unsigned int i = 0; i < 2; i++)
906  {
907  for (unsigned int j = 0; j < 2; j++)
908  {
909  coords[i][j][0] = coords[i][j][0] * x_crop_scale + x_crop_offs;
910  coords[i][j][1] = coords[i][j][1] * y_crop_scale + y_crop_offs;
911  }
912  }
913 }
914 
916 {
917  cur_tree_node = 0;
918 }
919 
921 {
922  // depth first search for leaf nodes with cur_tree_node
923  unsigned int x, y, row_size, depth;
924  GetPosition(cur_tree_node, x, y, row_size, depth);
925  // we want to backtrack until we find an unexplored sub branch. At this
926  // point, we trace down the tree until we get to a leaf.
927  if (cur_tree_node != 0)
928  {
929  bool done = false;
930  while (!done && cur_tree_node != 0)
931  {
932  unsigned int xd = x % 2;
933  unsigned int yd = y % 2;
934  x /= 2;
935  y /= 2;
936  row_size /= 2;
937  depth--;
938  cur_tree_node = GetIndex(x, y, row_size, depth);
939  if (cur_tree_node == 0 && xd == 1 && yd == 1)
940  {
941  // we've expanded all the options and got back to the top
942  return 0; // no more faces
943  }
944  // where does this split?
945  bool sx = ((nodes[cur_tree_node].flags & split_flag_x) != 0);
946  bool sy = ((nodes[cur_tree_node].flags & split_flag_y) != 0);
947  // have we used all the split options?
948  if (!(((sx && xd) || !sx) && ((sy && yd) || !sy)))
949  {
950  // we've found an unexpanded child, take the next one:
951  done = true;
952  x *= 2;
953  y *= 2;
954  row_size *= 2;
955  depth++;
956  if (sx && !xd && !yd) {
957  x++;
958  } else if ((sx && xd && sy && !yd) || (!sx && sy && !yd)) {
959  y++;
960  } else if (sx && sy && !xd && yd) {
961  x++; y++;
962  }
963  cur_tree_node = GetIndex(x, y, row_size, depth);
964  // if we've made our way to the root node, we've run out out
965  // of options.
966  if (cur_tree_node == 0)
967  {
968  return 0;
969  }
970  };
971  }
972  }
973  // find the first leaf on this subtree, taking top left every time.
974  while (nodes[cur_tree_node].flags & (split_flag_x | split_flag_y))
975  {
976  x *= 2;
977  y *= 2;
978  row_size *= 2;
979  depth++;
980  cur_tree_node = GetIndex(x, y, row_size, depth);
981  }
982  return cur_tree_node;
983 }
984 
985 unsigned int VertexCoordRemapper::Tree::GetTransform(unsigned int src_x, unsigned int src_y,
986  unsigned int max_depth,
987  unsigned int stop_x, unsigned int stop_y,
988  double &dest_x, double &dest_y)
989 {
990  // we start at the top and take children, prefering the lowest numbered one,
991  // until we either have no children, or we have found a child that knows the
992  // exact place we are looking for.
993  unsigned int no_x = 0, no_y = 0, row_size = 1, depth = 0,
994  rem_x = src_x, rem_y = src_y,
995  step_x = 1 << max_depth, step_y = 1 << max_depth,
996  node_id = GetIndex(no_x, no_y, row_size, depth);
997  while ( !( (rem_x == 0 || rem_x == step_x)
998  && (rem_y == 0 || rem_y == step_y))
999  && (nodes[node_id].flags & (split_flag_x | split_flag_y)))
1000  {
1001  // split, try and take earliest child node that leads towards goal
1002  depth++;
1003  no_x *= 2;
1004  no_y *= 2;
1005  row_size *= 2;
1006  if (nodes[node_id].flags & split_flag_x)
1007  {
1008  step_x /= 2;
1009  if (rem_x > step_x)
1010  {
1011  no_x ++;
1012  rem_x -= step_x;
1013  }
1014  }
1015  if (nodes[node_id].flags & split_flag_y)
1016  {
1017  step_y /= 2;
1018  if (rem_y > step_y)
1019  {
1020  no_y ++;
1021  rem_y -= step_y;
1022  }
1023  }
1024  // we want to stop if we have got a node at least as high as the
1025  // requested stopping node. Anything at a higher depth is after it.
1026  if (depth > max_depth) return 0;
1027  node_id = GetIndex(no_x, no_y, row_size, depth);
1028  if (depth == max_depth && no_x >= stop_x && no_y >= stop_y) return 0;
1029  }
1030  // if any of the vertices we are want to use are invalid (e.g. behind the
1031  // viewer in a rectilinear projection) we don't want to risk using them:
1032  if (nodes[node_id].flags & (transform_fail_flag * 15)) return 0;
1033  // if this face crosses a discontinuity, we should be using a point off
1034  // screen instead of in the middle. Refuse to use these faces
1035  if (nodes[node_id].flags & (vertex_side_flag_start * 15)) return 0;
1036  // linearly interpolate the node's corners.
1037  // most of the time we only use factors of 0 and 1, we don't want to make
1038  // points up except when trying to connect a point on a highly subdivided
1039  // face to a point that doesn't exist because it is on a less subdivided
1040  // face, in which case it needs to line up with the linear interpolation of
1041  // the less subdivided face. This is along one edge, so the other direction
1042  // should have a blending factor of 0 or 1.
1043  double xf = (double) rem_x / (double) step_x;
1044  double yf = (double) rem_y / (double) step_y;
1045 
1046  double top_x = (1.0 - xf) * nodes[node_id].verts[0][0][0]
1047  + xf * nodes[node_id].verts[1][0][0],
1048  bottom_x = (1-.0 - xf) * nodes[node_id].verts[0][1][0]
1049  + xf * nodes[node_id].verts[1][1][0],
1050  top_y = (1.0 - xf) * nodes[node_id].verts[0][0][1]
1051  + xf * nodes[node_id].verts[1][0][1],
1052  bottom_y = (1.0 - xf) * nodes[node_id].verts[0][1][1]
1053  + xf * nodes[node_id].verts[1][1][1];
1054  dest_x = top_x * (1.0 - yf) + bottom_x * yf;
1055  dest_y = top_y * (1.0 - yf) + bottom_y* yf;
1056  return node_id;
1057 }
1058 
VertexCoordRemapper(HuginBase::Panorama *m_pano, HuginBase::SrcPanoImage *image, VisualizationState *visualization_state)
const double min_length
PanoramaOptions::ProjectionFormat getProjection() const
bool GiveClipFaceResult(Coords *result)
Get a face that was produced by ClipFace.
unsigned int GetDepth(const unsigned int nodenum)
An abstract base class for objects that calculate an approximate remap specified by quadrilatrials...
Definition: MeshRemapper.h:43
const double GetUpperY() const
double crop_x1
Definition: MeshRemapper.h:100
double s_vertex_coords[2][2][2]
double crop_x2
Definition: MeshRemapper.h:100
unsigned int GetIndex(const unsigned int x, const unsigned int y, const unsigned int row_size, unsigned int depth)
double tex_coords[2][2][2]
void SetLengthAndAngle(TreeNode *node)
A class for exchanging pointers to coordinates.
Definition: MeshRemapper.h:60
const unsigned short int split_flag_y
unsigned int getHeight() const
get panorama height
HuginBase::SrcPanoImage * image
Definition: MeshRemapper.h:85
const double GetRadius() const
virtual void UpdateAndResetIndex()
const double GetUpperX() const
void DiscontinuityFlip(double vertex_c[2])
const double min_angle
include file for the hugin project
double(* tex_c)[2][2]
The coordinate in the source image ranging from 0 to 1.
Definition: MeshRemapper.h:64
void RecursiveUpdate(unsigned int node_id, unsigned int stretch_x, unsigned int stretch_y)
bool isInside(vigra::Point2D p, bool ignoreMasks=false) const
check if a coordinate is inside the source image
HuginBase::PanoramaOptions::ProjectionFormat output_projection
const double GetLowerY() const
VisualizationState * visualization_state
Definition: MeshRemapper.h:83
const unsigned short int split_flag_x
const double min_length_difference
const unsigned short int patch_flag_x
Model for a panorama.
Definition: Panorama.h:152
TreeNode nodes[1+4+16+64+256+1024+4096]
void ClipFace(Coords *face)
Crop a face to the source image, return true if there is anything left.
const double GetMiddleY() const
void SetCrop()
Fill the crop values of the MeshRemapper from the source image.
vigra::Rect2D GetVisibleArea()
Definition: ViewState.h:222
void createInvTransform(const vigra::Diff2D &srcSize, VariableMap srcVars, Lens::LensProjectionFormat srcProj, const vigra::Diff2D &destSize, PanoramaOptions::ProjectionFormat destProj, const std::vector< double > &destProjParam, double destHFOV, const vigra::Diff2D &origSrcSize)
create image-&gt;pano transformation
double height
The sizes of the input images in pixels.
Definition: MeshRemapper.h:94
double crop_y1
Definition: MeshRemapper.h:100
unsigned int GetParentId(const unsigned int nodenum)
void GetInputCoordinates(unsigned int node_num, double coords[2][2][2])
float scale
The number number of units between vertex coorinates that gives a pixel in the display.
Definition: MeshRemapper.h:89
const unsigned short int vertex_side_flag_start
const double GetMiddleX() const
T sqr(T val)
virtual OutputProjectionInfo * GetProjectionInfo()
Definition: ViewState.cpp:473
void GetPosition(const unsigned int nodenum, unsigned int &x, unsigned int &y, unsigned int &row_size, unsigned int &depth)
unsigned int GetTransform(unsigned int src_x, unsigned int src_y, unsigned int depth, unsigned int stop_x, unsigned int stop_y, double &dest_x, double &dest_y)
const double GetXAdd360() const
const double GetLowerX() const
HuginBase::PTools::Transform transform
A transform to use to remap the images.
Definition: MeshRemapper.h:96
unsigned int getWidth() const
include file for the hugin project
bool transformImgCoord(double &x_dest, double &y_dest, double x_src, double y_src) const
like transform, but return image coordinates, not cartesian coordinates
const unsigned int min_depth
const unsigned short int transform_fail_flag
const unsigned short int patch_flag_y
virtual HuginBase::PanoramaOptions * GetOptions()
Definition: ViewState.cpp:468
const unsigned int max_depth
double width
Definition: MeshRemapper.h:94
#define DEBUG_DEBUG(msg)
Definition: utils.h:68
virtual bool GetNextFaceCoordinates(Coords *result)
Get the texture and vertex coordinates for the next face.
double crop_y2
Definition: MeshRemapper.h:100
virtual void UpdateAndResetIndex()
static void info(const char *fmt,...)
Definition: svm.cpp:95
unsigned short int discontinuity_flags
const double offscreen_safety_margin
static uint16_t flags
double(* vertex_c)[2][2]
The coordinate in the panorama, in its pixel space.
Definition: MeshRemapper.h:66
All variables of a source image.
Definition: SrcPanoImage.h:194
#define M_PI
Definition: GaborFilter.cpp:34
void TestSubdivide(unsigned int node_id)
const double GetYAdd360() const