static int perturb_type;
/*
- * Alignment state
- *
- * This structure contains alignment state information. The change
- * between the non-default old initial alignment and old final
- * alignment is used to adjust the non-default current initial
- * alignment. If either the old or new initial alignment is a default
- * alignment, the old --follow semantics are preserved.
- */
-
- class astate_t {
- ale_trans old_initial_alignment;
- ale_trans old_final_alignment;
- ale_trans default_initial_alignment;
- int old_is_default;
- std::vector<int> is_default;
- ale_image input_frame;
-
- public:
- astate_t() :
- is_default(1) {
-
- old_initial_alignment = ale_new_trans(accel::context(), NULL);
- old_final_alignment = ale_new_trans(accel::context(), NULL);
- default_initial_alignment = ale_new_trans(accel::context(), NULL);
-
- input_frame = NULL;
- is_default[0] = 1;
- old_is_default = 1;
- }
-
- ale_image get_input_frame() const {
- return input_frame;
- }
-
- void set_is_default(unsigned int index, int value) {
-
- /*
- * Expand the array, if necessary.
- */
- if (index == is_default.size());
- is_default.resize(index + 1);
-
- assert (index < is_default.size());
- is_default[index] = value;
- }
-
- int get_is_default(unsigned int index) {
- assert (index < is_default.size());
- return is_default[index];
- }
-
- ale_trans get_default() {
- return default_initial_alignment;
- }
-
- void set_default(ale_trans t) {
- default_initial_alignment = t;
- }
-
- void default_set_original_bounds(ale_image i) {
- ale_trans_set_original_bounds(default_initial_alignment, i);
- }
-
- void set_final(ale_trans t) {
- old_final_alignment = t;
- }
-
- void set_input_frame(ale_image i) {
- input_frame = i;
- }
-
- /*
- * Implement new delta --follow semantics.
- *
- * If we have a transformation T such that
- *
- * prev_final == T(prev_init)
- *
- * Then we also have
- *
- * current_init_follow == T(current_init)
- *
- * We can calculate T as follows:
- *
- * T == prev_final(prev_init^-1)
- *
- * Where ^-1 is the inverse operator.
- */
- static trans_single follow(trans_single a, trans_single b, trans_single c) {
- trans_single cc = c;
-
- if (alignment_class == 0) {
- /*
- * Translational transformations
- */
-
- ale_pos t0 = -a.eu_get(0) + b.eu_get(0);
- ale_pos t1 = -a.eu_get(1) + b.eu_get(1);
-
- cc.eu_modify(0, t0);
- cc.eu_modify(1, t1);
-
- } else if (alignment_class == 1) {
- /*
- * Euclidean transformations
- */
-
- ale_pos t2 = -a.eu_get(2) + b.eu_get(2);
-
- cc.eu_modify(2, t2);
-
- point p( c.scaled_height()/2 + c.eu_get(0) - a.eu_get(0),
- c.scaled_width()/2 + c.eu_get(1) - a.eu_get(1) );
-
- p = b.transform_scaled(p);
-
- cc.eu_modify(0, p[0] - c.scaled_height()/2 - c.eu_get(0));
- cc.eu_modify(1, p[1] - c.scaled_width()/2 - c.eu_get(1));
-
- } else if (alignment_class == 2) {
- /*
- * Projective transformations
- */
-
- point p[4];
-
- p[0] = b.transform_scaled(a
- . scaled_inverse_transform(c.transform_scaled(point( 0 , 0 ))));
- p[1] = b.transform_scaled(a
- . scaled_inverse_transform(c.transform_scaled(point(c.scaled_height(), 0 ))));
- p[2] = b.transform_scaled(a
- . scaled_inverse_transform(c.transform_scaled(point(c.scaled_height(), c.scaled_width()))));
- p[3] = b.transform_scaled(a
- . scaled_inverse_transform(c.transform_scaled(point( 0 , c.scaled_width()))));
-
- cc.gpt_set(p);
- }
-
- return cc;
- }
-
- /*
- * For multi-alignment following, we use the following approach, not
- * guaranteed to work with large changes in scene or perspective, but
- * which should be somewhat flexible:
- *
- * For
- *
- * t[][] calculated final alignments
- * s[][] alignments as loaded from file
- * previous frame n
- * current frame n+1
- * fundamental (primary) 0
- * non-fundamental (non-primary) m!=0
- * parent element m'
- * follow(a, b, c) applying the (a, b) delta T=b(a^-1) to c
- *
- * following in the case of missing file data might be generated by
- *
- * t[n+1][0] = t[n][0]
- * t[n+1][m!=0] = follow(t[n][m'], t[n+1][m'], t[n][m])
- *
- * cases with all noted file data present might be generated by
- *
- * t[n+1][0] = follow(s[n][0], t[n][0], s[n+1][0])
- * t[n+1][m!=0] = follow(s[n+1][m'], t[n+1][m'], s[n+1][m])
- *
- * For non-following behavior, or where assigning the above is
- * impossible, we assign the following default
- *
- * t[n+1][0] = Identity
- * t[n+1][m!=0] = t[n+1][m']
- */
-
- void init_frame_alignment_primary(transformation *offset, int lod, ale_pos perturb) {
-
- if (perturb > 0 && !old_is_default && !get_is_default(0)
- && default_initial_alignment_type == 1) {
-
- /*
- * Apply following logic for the primary element.
- */
-
- ui::get()->following();
-
- trans_single new_offset = follow(old_initial_alignment.get_element(0),
- old_final_alignment.get_element(0),
- offset->get_element(0));
-
- old_initial_alignment = *offset;
-
- offset->set_element(0, new_offset);
-
- ui::get()->set_offset(new_offset);
- } else {
- old_initial_alignment = *offset;
- }
-
- is_default.resize(old_initial_alignment.stack_depth());
- }
-
- void init_frame_alignment_nonprimary(transformation *offset,
- int lod, ale_pos perturb, unsigned int index) {
-
- assert (index > 0);
-
- unsigned int parent_index = offset->parent_index(index);
-
- if (perturb > 0
- && !get_is_default(parent_index)
- && !get_is_default(index)
- && default_initial_alignment_type == 1) {
-
- /*
- * Apply file-based following logic for the
- * given element.
- */
-
- ui::get()->following();
-
- trans_single new_offset = follow(old_initial_alignment.get_element(parent_index),
- offset->get_element(parent_index),
- offset->get_element(index));
-
- old_initial_alignment.set_element(index, offset->get_element(index));
- offset->set_element(index, new_offset);
-
- ui::get()->set_offset(new_offset);
-
- return;
- }
-
- offset->get_coordinate(parent_index);
-
-
- if (perturb > 0
- && old_final_alignment.exists(offset->get_coordinate(parent_index))
- && old_final_alignment.exists(offset->get_current_coordinate())
- && default_initial_alignment_type == 1) {
-
- /*
- * Apply nonfile-based following logic for
- * the given element.
- */
-
- ui::get()->following();
-
- /*
- * XXX: Although it is different, the below
- * should be equivalent to the comment
- * description.
- */
-
- trans_single a = old_final_alignment.get_element(offset->get_coordinate(parent_index));
- trans_single b = old_final_alignment.get_element(offset->get_current_coordinate());
- trans_single c = offset->get_element(parent_index);
-
- trans_single new_offset = follow(a, b, c);
-
- offset->set_element(index, new_offset);
- ui::get()->set_offset(new_offset);
-
- return;
- }
-
- /*
- * Handle other cases.
- */
-
- if (get_is_default(index)) {
- offset->set_element(index, offset->get_element(parent_index));
- ui::get()->set_offset(offset->get_element(index));
- }
- }
-
- void init_default() {
-
- if (default_initial_alignment_type == 0) {
-
- /*
- * Follow the transformation of the original frame,
- * setting new image dimensions.
- */
-
- // astate->default_initial_alignment = orig_t;
- default_initial_alignment.set_current_element(orig_t.get_element(0));
- default_initial_alignment.set_dimensions(input_frame);
-
- } else if (default_initial_alignment_type == 1)
-
- /*
- * Follow previous transformation, setting new image
- * dimensions.
- */
-
- default_initial_alignment.set_dimensions(input_frame);
-
- else
- assert(0);
-
- old_is_default = get_is_default(0);
- }
- };
-
- /*
* Alignment for failed frames -- default or optimal?
*
* A frame that does not meet the match threshold can be assigned the