ale/d2/trans_multi.h
2022-07-30 14:46:04 -03:00

1002 lines
24 KiB
C++

// Copyright 2002, 2004, 2007 David Hilvert <dhilvert@auricle.dyndns.org>,
// <dhilvert@ugcs.caltech.edu>
/* This file is part of the Anti-Lamenessing Engine.
The Anti-Lamenessing Engine is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
The Anti-Lamenessing Engine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the Anti-Lamenessing Engine; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* trans_multi.h: Represent multiple transformations, affecting different
* regions of a scene.
*/
#ifndef __trans_multi_h__
#define __trans_multi_h__
#include "trans_abstract.h"
#include "trans_single.h"
struct trans_multi : public trans_abstract {
public:
struct multi_coordinate {
int degree;
int x;
int y;
public:
int operator<(const multi_coordinate &mc) const {
if (degree < mc.degree
|| degree == mc.degree && y < mc.y
|| degree == mc.degree && y == mc.y && x < mc.x)
return 1;
return 0;
}
};
private:
static unsigned int _multi;
static ale_pos _multi_decomp;
static ale_real _multi_improvement;
typedef unsigned short index_t;
std::vector<trans_single> trans_stack;
std::vector<multi_coordinate> coord_stack;
std::map<multi_coordinate, index_t> coordinate_map;
int use_multi;
index_t current_element;
index_t orig_ref_height, orig_ref_width;
index_t cur_ref_height, cur_ref_width;
point cur_offset;
point orig_offset;
index_t *spatio_elem_map;
index_t *spatio_elem_map_r;
void push_element() {
assert (trans_stack.size() > 0);
if (++current_element == trans_stack.size())
trans_stack.push_back(trans_stack.back());
}
trans_multi() : trans_stack() {
use_multi = 0;
current_element = 0;
orig_ref_height = 0;
orig_ref_width = 0;
cur_ref_height = 0;
cur_ref_width = 0;
spatio_elem_map = NULL;
spatio_elem_map_r = NULL;
}
public:
static void set_md(double d) {
if (!(d > 1))
d = 1;
_multi_decomp = d;
}
static void set_multi(const char *type) {
if (!strcmp(type, "none")) {
_multi = 0;
} else if (!strcmp(type, "local")) {
_multi = 1;
} else if (!strcmp(type, "fill")) {
_multi = 2;
} else if (!strcmp(type, "llocal")) {
_multi = 3;
} else if (!strcmp(type, "global")) {
_multi = 4;
}
}
static void set_mi(double d) {
_multi_improvement = d;
}
/*
* Calculate euclidean identity transform for a given image.
*/
static struct trans_multi eu_identity(const image *i = NULL, ale_pos scale_factor = 1) {
struct trans_multi r;
multi_coordinate mc;
mc.degree = 0;
mc.x = 0;
mc.y = 0;
r.input_width = i ? i->width() : 2;
r.input_height = i ? i->height() : 2;
r.scale_factor = scale_factor;
r.trans_stack.push_back(trans_single::eu_identity(i, scale_factor));
r.coord_stack.push_back(mc);
r.coordinate_map[mc] = r.trans_stack.size() - 1;
r.current_element = 0;
return r;
}
/*
* Generate an array of identity transformations.
*/
static trans_multi *new_eu_identity_array(unsigned int size) {
trans_multi *result = new trans_multi[size];
for (unsigned int i = 0; i < size; i++)
result[i] = eu_identity();
return result;
}
/*
* Calculate projective transformation parameters from a euclidean
* transformation.
*/
void eu_to_gpt() {
for (unsigned int t = 0; t < trans_stack.size(); t++)
trans_stack[t].eu_to_gpt();
}
/*
* Calculate projective identity transform for a given image.
*/
static trans_multi gpt_identity(const image *i, ale_pos scale_factor) {
struct trans_multi r = eu_identity(i, scale_factor);
r.eu_to_gpt();
return r;
}
trans_multi &operator=(const trans_multi &tm) {
this->trans_abstract::operator=(*((trans_abstract *) &tm));
trans_stack = tm.trans_stack;
coord_stack = tm.coord_stack;
coordinate_map = tm.coordinate_map;
use_multi = tm.use_multi;
current_element = tm.current_element;
orig_ref_height = tm.orig_ref_height;
orig_ref_width = tm.orig_ref_width;
cur_ref_height = tm.cur_ref_height;
cur_ref_width = tm.cur_ref_width;
cur_offset = tm.cur_offset;
orig_offset = tm.orig_offset;
free(spatio_elem_map);
free(spatio_elem_map_r);
spatio_elem_map = NULL;
spatio_elem_map_r = NULL;
size_t cur_size = cur_ref_width * cur_ref_height * sizeof(index_t);
if (cur_size > 0 && tm.spatio_elem_map) {
spatio_elem_map = (index_t *) malloc(cur_size);
assert (spatio_elem_map);
memcpy(spatio_elem_map, tm.spatio_elem_map, cur_size);
}
cur_size = input_height * input_width * sizeof(index_t);
if (cur_size > 0 && tm.spatio_elem_map_r) {
spatio_elem_map_r = (index_t *) malloc(cur_size);
assert (spatio_elem_map_r);
memcpy(spatio_elem_map_r, tm.spatio_elem_map_r, cur_size);
}
return *this;
}
trans_multi(const trans_multi &tm) : trans_stack() {
spatio_elem_map = NULL;
spatio_elem_map_r = NULL;
operator=(tm);
}
~trans_multi() {
free(spatio_elem_map);
free(spatio_elem_map_r);
}
trans_single get_element(index_t index) const {
assert (index < trans_stack.size());
return trans_stack[index];
}
trans_single get_element(multi_coordinate m) {
assert(coordinate_map.count(m));
index_t index = coordinate_map[m];
return get_element(index);
}
index_t get_index(multi_coordinate m) {
assert(coordinate_map.count(m));
return coordinate_map[m];
}
int exists(multi_coordinate m) {
return coordinate_map.count(m);
}
trans_single get_current_element() const {
return get_element(current_element);
}
void set_element(index_t index, trans_single t) {
assert (index < trans_stack.size());
trans_stack[index] = t;
}
void set_current_element(trans_single t) {
set_element(current_element, t);
}
void set_current_element(const trans_multi &t) {
set_element(current_element, t.get_current_element());
}
index_t get_current_index() const {
return current_element;
}
multi_coordinate get_current_coordinate() const {
return coord_stack[current_element];
}
multi_coordinate get_coordinate(index_t i) const {
assert(i < trans_stack.size());
return coord_stack[i];
}
void set_current_index(index_t i) {
assert (i < trans_stack.size());
current_element = i;
}
/*
* Set the bounds of the reference image after incorporation
* of the original frame.
*/
void set_original_bounds(const image *i) {
assert (orig_ref_width == 0);
assert (orig_ref_height == 0);
orig_ref_height = i->height();
orig_ref_width = i->width();
orig_offset = i->offset();
assert (orig_ref_width != 0);
assert (orig_ref_height != 0);
}
static multi_coordinate parent_mc(multi_coordinate mc) {
multi_coordinate result;
assert (mc.degree > 0);
if (mc.degree == 1) {
result.degree = 0;
result.x = 0;
result.y = 0;
return result;
}
result.degree = mc.degree - 1;
result.x = (int) floor((double) mc.x / (double) 2);
result.y = (int) floor((double) mc.y / (double) 2);
return result;
}
index_t parent_index(index_t i) {
multi_coordinate mc = coord_stack[i];
multi_coordinate mcp = parent_mc(mc);
index_t result = coordinate_map[mcp];
return result;
}
/*
* Set the bounds of the reference image after incorporation
* of the most recent frame.
*/
void set_current_bounds(const image *i) {
use_multi = 0;
free(spatio_elem_map);
free(spatio_elem_map_r);
spatio_elem_map = NULL;
spatio_elem_map_r = NULL;
cur_ref_height = i->height();
cur_ref_width = i->width();
cur_offset = i->offset();
int d; ale_pos div;
for (d = 1, div = 2;
orig_ref_height / div >= _multi_decomp
&& orig_ref_width / div >= _multi_decomp
&& _multi > 0;
d++, div *= 2) {
ale_pos height_scale = orig_ref_height / div;
ale_pos width_scale = orig_ref_width / div;
for (int i = floor((cur_offset[0] - orig_offset[0]) / height_scale);
i < ceil((cur_offset[0] - orig_offset[0] + cur_ref_height) / height_scale);
i++)
for (int j = floor((cur_offset[1] - orig_offset[1]) / width_scale);
j < ceil((cur_offset[1] - orig_offset[1] + cur_ref_width) / width_scale);
j++) {
multi_coordinate c;
c.degree = d;
c.x = j;
c.y = i;
if (!coordinate_map.count(c)) {
multi_coordinate parent = parent_mc(c);
assert (coordinate_map.count(parent));
trans_stack.push_back(trans_stack[coordinate_map[parent]]);
coord_stack.push_back(c);
coordinate_map[c] = trans_stack.size() - 1;
}
}
}
}
index_t stack_depth() const {
return trans_stack.size();
}
struct elem_bounds_int_t {
unsigned int imin, imax, jmin, jmax;
int satisfies_min_dim(unsigned int min_dimension) {
if (imax - imin < min_dimension
|| jmax - jmin < min_dimension)
return 0;
return 1;
}
};
struct elem_bounds_t {
ale_pos imin, imax, jmin, jmax;
elem_bounds_int_t scale_to_bounds(unsigned int height, unsigned int width) {
elem_bounds_t e;
elem_bounds_int_t f;
e = *this;
e.imin *= height;
e.imax *= height;
e.jmin *= width;
e.jmax *= width;
if (e.imin > 0)
f.imin = (unsigned int) floor(e.imin);
else
f.imin = 0;
if (e.imax < height)
f.imax = (unsigned int) ceil(e.imax);
else
f.imax = height;
if (e.jmin > 0)
f.jmin = (unsigned int) floor(e.jmin);
else
f.jmin = 0;
if (e.jmax < width)
f.jmax = (unsigned int) ceil(e.jmax);
else
f.jmax = width;
return f;
}
};
elem_bounds_t elem_bounds(int e) const {
elem_bounds_t result;
result.imin = cur_offset[0] - orig_offset[0];
result.imax = result.imin + cur_ref_height;
result.jmin = cur_offset[1] - orig_offset[1];
result.jmax = result.jmin + cur_ref_width;
if (e > 0) {
multi_coordinate mc = coord_stack[e];
ale_pos height_scale = orig_ref_height / pow(2, mc.degree);
ale_pos width_scale = orig_ref_width / pow(2, mc.degree);
if (height_scale * mc.y > result.imin)
result.imin = height_scale * mc.y;
if (height_scale * (mc.y + 1) < result.imax)
result.imax = height_scale * (mc.y + 1);
if (width_scale * mc.x > result.jmin)
result.jmin = width_scale * mc.x;
if (width_scale * (mc.x + 1) < result.jmax)
result.jmax = width_scale * (mc.x + 1);
}
result.imin -= cur_offset[0] - orig_offset[0];
result.imax -= cur_offset[0] - orig_offset[0];
result.jmin -= cur_offset[1] - orig_offset[1];
result.jmax -= cur_offset[1] - orig_offset[1];
result.imin /= cur_ref_height;
result.imax /= cur_ref_height;
result.jmin /= cur_ref_width;
result.jmax /= cur_ref_width;
return result;
}
elem_bounds_t elem_bounds() const {
return elem_bounds(current_element);
}
private:
int check_multi(int i, int j, pixel value, const image *cur_ref, const image *input, index_t check_index) {
int result = 0;
const pixel &rp = value;
index_t index = check_index;
trans_single t = get_element(index);
point p0 = point(cur_offset[0] + i, cur_offset[1] + j);
point p = t.unscaled_inverse_transform(p0);
if (!input->in_bounds(p))
return result;
trans_single s = get_element(spatio_elem_map[cur_ref_width * i + j]);
point q = s.unscaled_inverse_transform(p0);
pixel pt = t.get_tonal_multiplier(p0);
pixel qt = s.get_tonal_multiplier(p0);
if (input->in_bounds(q)) {
pixel ip1 = input->get_bl(p);
pixel ip0 = input->get_bl(q);
ale_real diff1 = (pt * ip1 - rp).norm();
ale_real diff0 = (qt * ip0 - rp).norm();
/*
* 0.99 factor is for cycle avoidance (e.g., in
* filling).
*/
if (diff1 < diff0 * 0.99 /* * (1 - _multi_improvement) */
|| _multi == 3) {
result = 1;
spatio_elem_map[cur_ref_width * i + j] = index;
}
}
int ii = (int) p[0];
int jj = (int) p[1];
if (ii < 0 || (unsigned int) ii >= input_height
|| jj < 0 || (unsigned int) jj >= input_width)
return result;
trans_single u = get_element(spatio_elem_map_r[input_width * ii + jj]);
point r = u.transform_unscaled(p);
pixel ut = u.get_tonal_multiplier(r);
if (cur_ref->in_bounds(r - cur_offset)) {
pixel ip1 = input->get_bl(p);
pixel rp0 = cur_ref->get_bl(r - cur_offset);
ale_real diff1 = (pt * ip1 - rp).norm();
ale_real diff0 = (ut * ip1 - rp0).norm();
/*
* 0.99 factor is probably not necessary, but
* is included for symmetry with cycle-avoidance
* factor.
*/
if (diff1 < diff0 * 0.99 /* * (1 - _multi_improvement) */
|| _multi == 3) {
spatio_elem_map_r[input_width * ii + jj] = index;
}
}
return result;
}
void assign_multi_global_best(const image *cur_ref, const image *input) {
for (unsigned int i = 0; i < cur_ref_height; i++)
for (unsigned int j = 0; j < cur_ref_width; j++) {
pixel rp = cur_ref->get_pixel(i, j);
for (index_t index = 0; index < coordinate_map.size(); index++)
check_multi(i, j, rp, cur_ref, input, index);
}
}
void assign_multi_best(const image *cur_ref, const image *input) {
for (unsigned int i = 0; i < cur_ref_height; i++)
for (unsigned int j = 0; j < cur_ref_width; j++) {
pixel rp = cur_ref->get_pixel(i, j);
int d; ale_pos div;
for (d = 1, div = 2; ; d++, div *= 2) {
ale_pos height_scale = orig_ref_height / div;
ale_pos width_scale = orig_ref_width / div;
multi_coordinate c;
c.degree = d;
c.y = floor((cur_offset[0] - orig_offset[0] + i) / height_scale);
c.x = floor((cur_offset[1] - orig_offset[1] + j) / width_scale);
if (!coordinate_map.count(c))
break;
index_t index = coordinate_map[c];
check_multi(i, j, rp, cur_ref, input, index);
}
}
}
void fill_multi_init(unsigned char *update_map) {
for (unsigned int l = 0; l < coord_stack.size(); l++) {
elem_bounds_int_t b = elem_bounds(l).scale_to_bounds(cur_ref_height, cur_ref_width);
for (unsigned int i = b.imin; i < b.imax; i++) {
update_map[i * cur_ref_width + b.jmin] |= (1 | 2 | 4);
update_map[i * cur_ref_width + (b.jmax - 1)] |= (8 | 16 | 32);
}
for (unsigned int j = b.jmin; j < b.jmax; j++) {
update_map[b.imin * cur_ref_width + j] |= (1 | 64 | 8);
update_map[(b.imax - 1) * cur_ref_width + j] |= (4 | 128 | 32);
}
}
for (unsigned int i = 0; i < cur_ref_height; i++)
update_map[cur_ref_width * cur_ref_height + i] = 1;
for (unsigned int j = 0; j < cur_ref_width; j++)
update_map[cur_ref_width * cur_ref_height + cur_ref_height + j] = 1;
}
int step_fill_multi(unsigned char *update_map, const image *cur_ref, const image *input) {
if (cur_ref_height == 0
|| cur_ref_width == 0)
return 0;
unsigned int i_min, i_max, j_min, j_max;
int result = 0;
i_min = cur_ref_height;
i_max = cur_ref_height;
j_min = cur_ref_width;
j_max = cur_ref_width;
for (unsigned int i = 0; i < cur_ref_height; i++)
if (update_map[cur_ref_width * cur_ref_height + i]) {
i_min = i;
i_max = i + 1;
break;
}
for (unsigned int i = cur_ref_height - 1; i >= i_max; i--)
if (update_map[cur_ref_width * cur_ref_height + i]) {
i_max = i + 1;
break;
}
for (unsigned int j = 0; j < cur_ref_width; j++)
if (update_map[cur_ref_width * cur_ref_height + cur_ref_height + j]) {
j_min = j;
j_max = j + 1;
break;
}
for (unsigned int j = cur_ref_width - 1; j >= j_max; j--)
if (update_map[cur_ref_width * cur_ref_height + cur_ref_height + j]) {
j_max = j + 1;
break;
}
if (!(i_min < i_max) || !(j_min < j_max))
return 0;
for (unsigned int i = i_min; i < i_max; i++)
update_map[cur_ref_width * cur_ref_height + i] = 0;
for (unsigned int j = j_min; j < j_max; j++)
update_map[cur_ref_width * cur_ref_height + cur_ref_height + j] = 0;
for (unsigned int i = i_min; i < i_max; i++)
for (unsigned int j = j_min; j < j_max; j++) {
int o = cur_ref_width * i + j;
if (!update_map[o])
continue;
pixel rp = cur_ref->get_pixel(i, j);
int n = o - cur_ref_width;
int s = o + cur_ref_width;
int e = o + 1;
int w = o - 1;
int ne = n + 1;
int nw = n - 1;
int se = s + 1;
int sw = s - 1;
int dirs[8] = {
nw, w, sw,
ne, e, se,
n, s
};
int comp_dirs[8] = {
5, 4, 3,
2, 1, 0,
7, 6
};
for (int di = 0; di < 8; di++) {
if (!(update_map[o] & (1 << di)))
continue;
int d = dirs[di];
if (d < 0 || (unsigned int) d >= cur_ref_width * cur_ref_height)
continue;
if (spatio_elem_map[d] == spatio_elem_map[o])
continue;
int changed = check_multi(i, j, rp, cur_ref, input, spatio_elem_map[d]);
if (!changed)
continue;
for (int ddi = 0; ddi < 8; ddi++) {
int dd = dirs[ddi];
if (dd < 0 || (unsigned int) dd >= cur_ref_width * cur_ref_height)
continue;
if (spatio_elem_map[dd] == spatio_elem_map[o])
continue;
result |= 1;
update_map[dd] |= (1 << comp_dirs[ddi]);
update_map[cur_ref_height * cur_ref_width
+ dd / cur_ref_width] = 1;
update_map[cur_ref_height * cur_ref_width
+ cur_ref_height + dd % cur_ref_width] = 1;
}
}
update_map[o] = 0;
}
return result;
}
void fill_multi(const image *cur_ref, const image *input) {
unsigned char *update_map = (unsigned char *) calloc(
cur_ref_height * cur_ref_width
+ cur_ref_height + cur_ref_width,
sizeof(unsigned char));
fill_multi_init(update_map);
while (step_fill_multi(update_map, cur_ref, input));
free(update_map);
}
public:
void set_multi(const image *cur_ref, const image *input) {
assert(use_multi == 0);
assert(spatio_elem_map == NULL);
assert(spatio_elem_map_r == NULL);
use_multi = 1;
spatio_elem_map = (index_t *) calloc(
cur_ref_height * cur_ref_width, sizeof(index_t));
assert(spatio_elem_map);
spatio_elem_map_r = (index_t *) calloc(
input_height * input_width, sizeof(index_t));
assert(spatio_elem_map_r);
if (_multi == 4) {
assign_multi_global_best(cur_ref, input);
} else {
assign_multi_best(cur_ref, input);
if (_multi == 2)
fill_multi(cur_ref, input);
}
/*
* All scale factors should be identical.
*/
scale_factor = trans_stack[0].scale();
}
/*
* Returns non-zero if the transformation might be non-Euclidean.
*/
int is_projective() const {
return trans_stack[current_element].is_projective();
}
/*
* Transformation at point in the domain
*/
trans_single t_at_point(struct point p) const {
if (!use_multi)
return trans_stack[current_element];
int ii = (int) p[0];
int jj = (int) p[1];
if (ii < 0 || (unsigned int) ii >= input_height
|| jj < 0 || (unsigned int) jj >= input_width)
return trans_stack[0];
return trans_stack[spatio_elem_map_r[input_width * ii + jj]];
}
/*
* Transformation at point in the co-domain.
*/
trans_single t_at_inv_point(struct point p) const {
if (!use_multi)
return trans_stack[current_element];
int i = (int) (p[0] - cur_offset[0]);
int j = (int) (p[1] - cur_offset[1]);
if (i < 0 || (unsigned int) i >= cur_ref_height
|| j < 0 || (unsigned int) j >= cur_ref_width)
return trans_stack[0];
return trans_stack[spatio_elem_map[cur_ref_width * i + j]];
}
/*
* Projective/Euclidean transformations
*/
struct point pe(struct point p) const {
if (!use_multi)
return trans_stack[current_element].pe(p);
int ii = (int) p[0];
int jj = (int) p[1];
if (ii < 0 || (unsigned int) ii >= input_height
|| jj < 0 || (unsigned int) jj >= input_width)
return trans_stack[0].pe(p);
return trans_stack[spatio_elem_map_r[input_width * ii + jj]].pe(p);
}
/*
* Inverse transformations
*/
struct point pei(struct point p) const {
if (!use_multi)
return trans_stack[current_element].pei(p);
int i = (int) (p[0] - cur_offset[0]);
int j = (int) (p[1] - cur_offset[1]);
if (i < 0 || (unsigned int) i >= cur_ref_height
|| j < 0 || (unsigned int) j >= cur_ref_width)
return trans_stack[0].pei(p);
return trans_stack[spatio_elem_map[cur_ref_width * i + j]].pei(p);
}
pixel get_tonal_multiplier(struct point p) const {
if (!use_multi)
return trans_stack[current_element].get_tonal_multiplier(p);
int i = (int) (p[0] - cur_offset[0]);
int j = (int) (p[1] - cur_offset[1]);
if (i < 0 || (unsigned int) i >= cur_ref_height
|| j < 0 || (unsigned int) j >= cur_ref_width)
return trans_stack[0].get_tonal_multiplier(p);
return trans_stack[spatio_elem_map[cur_ref_width * i + j]].get_tonal_multiplier(p);
}
pixel get_inverse_tonal_multiplier(struct point p) const {
if (!use_multi)
return trans_stack[current_element].get_inverse_tonal_multiplier(p);
int i = (int) p[0];
int j = (int) p[1];
if (i < 0 || (unsigned int) i >= input_height
|| j < 0 || (unsigned int) j >= input_width)
return trans_stack[0].get_inverse_tonal_multiplier(p);
return trans_stack[spatio_elem_map_r[input_width * i + j]].get_inverse_tonal_multiplier(p);
}
void set_tonal_multiplier(pixel p) {
trans_stack[current_element].set_tonal_multiplier(p);
}
/*
* Modify a euclidean transform in the indicated manner.
*/
void eu_modify(int i1, ale_pos diff) {
trans_stack[current_element].eu_modify(i1, diff);
}
/*
* Rotate about a given point in the original reference frame.
*/
void eu_rotate_about_scaled(point center, ale_pos diff) {
trans_stack[current_element].eu_rotate_about_scaled(center, diff);
}
/*
* Modify all euclidean parameters at once.
*/
void eu_set(ale_pos eu[3]) {
trans_stack[current_element].eu_set(eu);
}
/*
* Get the specified euclidean parameter
*/
ale_pos eu_get(int param) const {
return trans_stack[current_element].eu_get(param);
}
/*
* Modify a projective transform in the indicated manner.
*/
void gpt_modify(int i1, int i2, ale_pos diff) {
trans_stack[current_element].gpt_modify(i1, i2, diff);
}
/*
* Modify a projective transform according to the group operation.
*/
void gr_modify(int i1, int i2, ale_pos diff) {
trans_stack[current_element].gr_modify(i1, i2, diff);
}
/*
* Modify all projective parameters at once.
*/
void gpt_set(point x[4]) {
trans_stack[current_element].gpt_set(x);
}
void gpt_set(point x1, point x2, point x3, point x4) {
trans_stack[current_element].gpt_set(x1, x2, x3, x4);
}
void snap(ale_pos interval) {
trans_stack[current_element].snap(interval);
}
/*
* Get the specified projective parameter
*/
point gpt_get(int point) const {
return trans_stack[current_element].gpt_get(point);
}
/*
* Get the specified projective parameter
*/
ale_pos gpt_get(int point, int dim) {
return trans_stack[current_element].gpt_get(point, dim);
}
/*
* Translate by a given amount
*/
void translate(point p) {
trans_stack[current_element].translate(p);
}
/*
* Rotate by a given amount about a given point.
*/
void rotate(point p, ale_pos degrees) {
trans_stack[current_element].rotate(p, degrees);
}
void reset_memos() {
for (unsigned int t = 0; t < trans_stack.size(); t++)
trans_stack[t].reset_memos();
}
/*
* Rescale a transform with a given factor.
*/
void specific_rescale(ale_pos factor) {
/*
* Ensure that no maps exist.
*/
assert (use_multi == 0);
assert (spatio_elem_map == NULL);
assert (spatio_elem_map_r == NULL);
trans_stack[current_element].rescale(factor);
}
/*
* Set the dimensions of the image.
*/
void specific_set_dimensions(const image *im) {
for (unsigned int t = 0; t < trans_stack.size(); t++)
trans_stack[t].set_dimensions(im);
}
void map_area(point p, point *q, ale_pos d[2]) {
t_at_point(p / scale_factor).map_area(p, q, d);
}
void map_area_unscaled(point p, point *q, ale_pos d[2]) {
t_at_point(p).map_area_unscaled(p, q, d);
}
void unscaled_map_area_inverse(point p, point *q, ale_pos d[2]) {
t_at_inv_point(p).unscaled_map_area_inverse(p, q, d);
}
/*
* Modify all projective parameters at once. Accommodate bugs in the
* version 0 transformation file handler (ALE versions 0.4.0p1 and
* earlier). This code is only called when using a transformation data
* file created with an old version of ALE.
*/
void gpt_v0_set(point x[4]) {
trans_stack[current_element].gpt_v0_set(x);
}
/*
* Modify all euclidean parameters at once. Accommodate bugs in the
* version 0 transformation file handler (ALE versions 0.4.0p1 and
* earlier). This code is only called when using a transformation data
* file created with an old version of ALE.
*/
void eu_v0_set(ale_pos eu[3]) {
trans_stack[current_element].eu_v0_set(eu);
}
void debug_output() {
for (unsigned int t = 0; t < trans_stack.size(); t++)
trans_stack[t].debug_output();
}
};
#endif