initial commit
This commit is contained in:
32
d3/align.cc
Normal file
32
d3/align.cc
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2003 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
|
||||
*/
|
||||
|
||||
#include "align.h"
|
||||
|
||||
/*
|
||||
* See align.h for details on these variables.
|
||||
*/
|
||||
|
||||
ale_pos align::_init_angle;
|
||||
et *align::alignment_array = NULL;
|
||||
int align::_vp_adjust = 1;
|
||||
int align::_vo_adjust = 1;
|
||||
tload_t *align::tload = NULL;
|
||||
tsave_t *align::tsave = NULL;
|
||||
643
d3/align.h
Normal file
643
d3/align.h
Normal file
@@ -0,0 +1,643 @@
|
||||
// Copyright 2003 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* d3/align.h: Handle alignment of view pyramids.
|
||||
*
|
||||
* XXX: this class assumes that the view volume is a right rectangular-based
|
||||
* pyramid, which holds for most photographic situations.
|
||||
*
|
||||
* XXX: this class assumes that the horizontal and vertical angles of the view
|
||||
* volume pyramid are proportional to the horizontal and vertical pixel
|
||||
* resolutions.
|
||||
*/
|
||||
|
||||
#ifndef __d3align_h__
|
||||
#define __d3align_h__
|
||||
|
||||
#include "point.h"
|
||||
#include "et.h"
|
||||
#include "pt.h"
|
||||
#include "tfile.h"
|
||||
|
||||
class align {
|
||||
static ale_pos _init_angle;
|
||||
static et *alignment_array;
|
||||
static int _vp_adjust;
|
||||
static int _vo_adjust;
|
||||
static tload_t *tload;
|
||||
static tsave_t *tsave;
|
||||
|
||||
/*
|
||||
* Estimate the point at which the pyramidal axis passes through the
|
||||
* plane, based on the given 2-dimensional transformation and the given
|
||||
* point set indicating the corners of the quadrilateral of
|
||||
* intersection. (Both transformation and point set alone are
|
||||
* sufficient for calculation.)
|
||||
*
|
||||
* Using the point set, the desired point is exactly the point of
|
||||
* intersection between line segments drawn between opposite corners of
|
||||
* the quadrilateral of intersection. The algebraic details of this
|
||||
* calculation are desribed below.
|
||||
*
|
||||
* If we represent the desired point by (e1, e2), and the four corners
|
||||
* of the quadrilateral of intersection by (a1, a2), ..., (d1, d2) in
|
||||
* clockwise (or counter-clockwise) order, then we get the two-equation
|
||||
* vector system (implicitly four equations)
|
||||
*
|
||||
* (e1, e2) = (a1, a2) + x[(c1, c2) - (a1, a2)]
|
||||
* = (b1, b2) + y[(d1, d2) - (b1, b2)]
|
||||
*
|
||||
* Solving for x in terms of y, we get the two-equation system
|
||||
*
|
||||
* x = (b1 - yb1 + yd1 - a1) / (c1 - a1)
|
||||
* = (b2 - yb2 + yd2 - a2) / (c2 - a2)
|
||||
*
|
||||
* And
|
||||
*
|
||||
* y = (c1b2 - c1a2 - a1b2 - c2b1 + c2a1 - a2b1)
|
||||
* /(-c2b1 + c2d1 + a2b1 - a2d1 + c1b2 - c1d2 - a1b2 + a1d2)
|
||||
*
|
||||
* However, it's much easier just to project the center point of the
|
||||
* source image onto the quadrilateral of intersection using the
|
||||
* given 2-dimensional transformation.
|
||||
*/
|
||||
static d2::point axis_intersection(d2::point a, d2::point b, d2::point c, d2::point d, d2::transformation t) {
|
||||
#if 0
|
||||
ale_pos y = (c[0]*b[1] - c[0]*a[1] - a[0]*b[1] - c[1]*b[0]
|
||||
+ c[1]*a[0] - a[1]*b[0])
|
||||
/(-c[1]*b[0] + c[1]*d[0] + a[1]*b[0] - a[1]*d[0]
|
||||
+ c[0]*b[1] - c[0]*d[1] - a[0]*b[1] + a[0]*d[1]);
|
||||
|
||||
return b + y * (d - b);
|
||||
#else
|
||||
return t.transform_scaled(d2::point((t.scaled_height() - 1) / 2, (t.scaled_width() - 1) / 2));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* gd_position is a gradient-descent automatic positioning algorithm
|
||||
* used to determine the location of the view pyramid apex.
|
||||
*
|
||||
* Starting from an initial camera position ESTIMATE, this method
|
||||
* determines the angles between each pair of legs in the view volume
|
||||
* (there are six pairs). The sum of squares of the differences
|
||||
* between the thusly determined angles and the known desired angles is
|
||||
* then used as an error metric, and a kind of gradient descent is used
|
||||
* to find a position for which this metric is minimized.
|
||||
*/
|
||||
static point gd_position(point estimate, d2::point a, d2::point b, d2::point c, d2::point d, d2::transformation t) {
|
||||
ale_pos w = t.scaled_width();
|
||||
ale_pos h = t.scaled_height();
|
||||
|
||||
/*
|
||||
* The desired diagonal angle is given (as init_angle).
|
||||
* Calculate the desired side angles as follows:
|
||||
*
|
||||
* The distance to the apex is
|
||||
*
|
||||
* D = sqrt(h*h + w*w) / (2 * tan(init_angle/2))
|
||||
*
|
||||
* Then
|
||||
*
|
||||
* desired_h_angle = 2 * arctan(h / (2 * sqrt(D*D + w*w/4)))
|
||||
* desired_w_angle = 2 * arctan(w / (2 * sqrt(D*D + h*h/4)))
|
||||
*/
|
||||
|
||||
ale_pos D = (ale_pos) sqrt(h * h + w * w)
|
||||
/ (ale_pos) (2 * tan(_init_angle/2));
|
||||
ale_pos desired_h_angle = (double) (2 * atan((double) ((double) h / (2 * sqrt((double) (D*D) + (double) (w*w)/4)))));
|
||||
ale_pos desired_w_angle = (double) (2 * atan((double) ((double) w / (2 * sqrt((double) (D*D) + (double) (h*h)/4)))));
|
||||
|
||||
ale_pos estimate_h1_angle = estimate.anglebetw(a, b);
|
||||
ale_pos estimate_h2_angle = estimate.anglebetw(c, d);
|
||||
ale_pos estimate_w1_angle = estimate.anglebetw(a, d);
|
||||
ale_pos estimate_w2_angle = estimate.anglebetw(b, c);
|
||||
ale_pos estimate_d1_angle = estimate.anglebetw(a, c);
|
||||
ale_pos estimate_d2_angle = estimate.anglebetw(b, d);
|
||||
|
||||
ale_pos error = sqrt(pow(estimate_h1_angle - desired_h_angle, 2)
|
||||
+ pow(estimate_h2_angle - desired_h_angle, 2)
|
||||
+ pow(estimate_w1_angle - desired_w_angle, 2)
|
||||
+ pow(estimate_w2_angle - desired_w_angle, 2)
|
||||
+ pow(estimate_d1_angle - _init_angle , 2)
|
||||
+ pow(estimate_d2_angle - _init_angle , 2));
|
||||
|
||||
/*
|
||||
* Vary the magnitude by which each coordinate of the position
|
||||
* can be changed at each step.
|
||||
*/
|
||||
|
||||
ale_pos view_angle = _init_angle;
|
||||
|
||||
for (ale_pos magnitude = estimate[2] / 2;
|
||||
magnitude >= 1;
|
||||
magnitude /= 2) {
|
||||
|
||||
/*
|
||||
* Continue searching at this magnitude while error <
|
||||
* old_error. (Initialize old_error accordingly.)
|
||||
*/
|
||||
|
||||
ale_pos old_error = error * 2;
|
||||
|
||||
while(old_error > error) {
|
||||
|
||||
// ale_pos D = sqrt(h * h + w * w)
|
||||
// / (2 * tan(view_angle/2));
|
||||
// ale_pos desired_h_angle = 2 * atan(h / (2 * sqrt(D*D + w*w/4)));
|
||||
// ale_pos desired_w_angle = 2 * atan(w / (2 * sqrt(D*D + h*h/4)));
|
||||
|
||||
// fprintf(stderr, ".");
|
||||
|
||||
|
||||
// fprintf(stderr, "estimate: [%f %f %f %f %f %f]\n",
|
||||
// estimate_h1_angle,
|
||||
// estimate_h2_angle,
|
||||
// estimate_w1_angle,
|
||||
// estimate_w2_angle,
|
||||
// estimate_d1_angle,
|
||||
// estimate_d2_angle);
|
||||
//
|
||||
// fprintf(stderr, "desired : [%f %f %f]\n",
|
||||
// desired_h_angle,
|
||||
// desired_w_angle,
|
||||
// view_angle);
|
||||
|
||||
old_error = error;
|
||||
|
||||
for (ale_pos c0 = -magnitude; c0 <= magnitude; c0 += magnitude)
|
||||
for (ale_pos c1 = -magnitude; c1 <= magnitude; c1 += magnitude)
|
||||
for (ale_pos c2 = -magnitude; c2 <= magnitude; c2 += magnitude)
|
||||
for (ale_pos c3 = -magnitude; c3 <= magnitude; c3 += magnitude) {
|
||||
|
||||
if (c3 > 10)
|
||||
c3 = 10;
|
||||
|
||||
// fprintf(stderr, "[%f %f %f]\n", c0, c1, c2);
|
||||
|
||||
estimate[0] += c0;
|
||||
estimate[1] += c1;
|
||||
estimate[2] += c2;
|
||||
// view_angle += c3 / 30;
|
||||
|
||||
ale_pos D = (ale_pos) sqrt(h * h + w * w)
|
||||
/ (ale_pos) (2 * tan(view_angle/2));
|
||||
ale_pos desired_h_angle = 2 * atan((double) h / (2 * sqrt((double) (D*D) + (double) (w*w)/4)));
|
||||
ale_pos desired_w_angle = 2 * atan((double) w / (2 * sqrt((double) D*D + (double) h*h/4)));
|
||||
|
||||
estimate_h1_angle = estimate.anglebetw(a, b);
|
||||
estimate_h2_angle = estimate.anglebetw(c, d);
|
||||
estimate_w1_angle = estimate.anglebetw(a, d);
|
||||
estimate_w2_angle = estimate.anglebetw(b, c);
|
||||
estimate_d1_angle = estimate.anglebetw(a, c);
|
||||
estimate_d2_angle = estimate.anglebetw(b, d);
|
||||
|
||||
ale_pos perturbed_error =
|
||||
sqrt(pow(estimate_h1_angle - desired_h_angle, 2)
|
||||
+ pow(estimate_h2_angle - desired_h_angle, 2)
|
||||
+ pow(estimate_w1_angle - desired_w_angle, 2)
|
||||
+ pow(estimate_w2_angle - desired_w_angle, 2)
|
||||
+ pow(estimate_d1_angle - view_angle , 2)
|
||||
+ pow(estimate_d2_angle - view_angle , 2));
|
||||
|
||||
if (perturbed_error < error) {
|
||||
error = perturbed_error;
|
||||
} else {
|
||||
estimate[0] -= c0;
|
||||
estimate[1] -= c1;
|
||||
estimate[2] -= c2;
|
||||
// view_angle -= c3 / 30;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fprintf(stderr, "error %f\n", error);
|
||||
|
||||
|
||||
return estimate;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
* Get alignment for frame N.
|
||||
*/
|
||||
static et of(unsigned int n) {
|
||||
assert (n < d2::image_rw::count());
|
||||
assert (alignment_array);
|
||||
|
||||
return alignment_array[n];
|
||||
}
|
||||
|
||||
static double angle_of(unsigned int n) {
|
||||
return _init_angle;
|
||||
}
|
||||
|
||||
static pt projective(unsigned int n) {
|
||||
return pt(d2::align::of(n), of(n), angle_of(n));
|
||||
}
|
||||
|
||||
static void set_tload(tload_t *t) {
|
||||
tload = t;
|
||||
}
|
||||
|
||||
static void set_tsave(tsave_t *t) {
|
||||
tsave = t;
|
||||
}
|
||||
|
||||
static void write_alignments() {
|
||||
int count = d2::image_rw::count();
|
||||
|
||||
if (count > 0)
|
||||
tsave_first(tsave, projective(0));
|
||||
|
||||
for (int i = 1; i < count; i++) {
|
||||
tsave_next(tsave, projective(i));
|
||||
}
|
||||
}
|
||||
|
||||
static void vp_adjust() {
|
||||
_vp_adjust = 1;
|
||||
}
|
||||
|
||||
static void vp_noadjust() {
|
||||
_vp_adjust = 0;
|
||||
}
|
||||
|
||||
static void vo_adjust() {
|
||||
_vo_adjust = 1;
|
||||
}
|
||||
|
||||
static void vo_noadjust() {
|
||||
_vo_adjust = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the initial estimated diagonal viewing angle of the view
|
||||
* pyramid. This is the angle formed, e.g., between the top-left and
|
||||
* bottom-right legs of the view pyramid.
|
||||
*/
|
||||
static void init_angle(ale_pos a) {
|
||||
_init_angle = a;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize d3 transformations from d2 transformations.
|
||||
*
|
||||
* Here are three possible approaches for calculating camera position
|
||||
* based on a known diagonal viewing angle and known area of
|
||||
* intersection of the view volume with a fixed plane:
|
||||
*
|
||||
* (1) divide the rectangular-based pyramidal view volume into two
|
||||
* tetrahedra. A coordinate system is selected so that the triangle of
|
||||
* intersection between one of the tetrahedra and the fixed plane has
|
||||
* coordinates (0, 0, 0), (1, 0, 0), and (a, b, 0), for some (a, b).
|
||||
* The law of cosines is then used to derive three equations
|
||||
* associating the three known angles at the apex with the lengths of
|
||||
* the edges of the tetrahedron. The solution of this system of
|
||||
* equations gives the coordinates of the apex in terms of a, b, and
|
||||
* the known angles. These coordinates are then transformed back to
|
||||
* the original coordinate system.
|
||||
*
|
||||
* (2) The gradient descent approach taken by the method gd_position().
|
||||
*
|
||||
* (3) Assume that the camera is aimed (roughly) perpendicular to the
|
||||
* plane. In this case, the pyramidal axis forms with each adjacent
|
||||
* pyramidal edge, in combination with a segment in the plane, a right
|
||||
* triangle. The distance of the camera from the plane is d/(2 *
|
||||
* tan(theta/2)), where d is the distance between opposite corners of
|
||||
* the quadrilateral of intersection and theta is the angle between
|
||||
* opposite pairs of edges of the view volume.
|
||||
*
|
||||
* As an initial approach to the problem, we use (3) followed by (2).
|
||||
*
|
||||
* After position is estimated, we determine orientation from position.
|
||||
* In order to do this, we determine the point at which the axis of
|
||||
* the view pyramid passes through the plane, as described in the
|
||||
* method axis_intersection().
|
||||
*/
|
||||
|
||||
static void init_from_d2() {
|
||||
assert (alignment_array == NULL);
|
||||
|
||||
/*
|
||||
* Initialize the alignment array.
|
||||
*/
|
||||
|
||||
alignment_array = (et *) malloc (d2::image_rw::count() * sizeof(et));
|
||||
|
||||
assert (alignment_array);
|
||||
|
||||
if (!alignment_array) {
|
||||
fprintf(stderr, "\n\n*** Unable to allocate memory for 3D alignment array. ***\n\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over input frames
|
||||
*/
|
||||
|
||||
for (unsigned int i = 0; i < d2::image_rw::count(); i++) {
|
||||
|
||||
/*
|
||||
* Obtain the four mapped corners of the quadrilateral
|
||||
* of intersection.
|
||||
*/
|
||||
|
||||
d2::transformation t = d2::align::of(i);
|
||||
|
||||
d2::point a = t.transform_scaled(d2::point(0, 0));
|
||||
d2::point b = t.transform_scaled(d2::point(t.scaled_height() - 1, 0));
|
||||
d2::point c = t.transform_scaled(d2::point(t.scaled_height() - 1, t.scaled_width() - 1));
|
||||
d2::point d = t.transform_scaled(d2::point(0, t.scaled_width() - 1));
|
||||
|
||||
/*
|
||||
* Estimate the point at which the pyramidal axis
|
||||
* passes through the plane. We denote the point as
|
||||
* 'e'.
|
||||
*/
|
||||
|
||||
d2::point e = axis_intersection(a, b, c, d, t);
|
||||
|
||||
/*
|
||||
* Determine the average distance between opposite
|
||||
* corners, and calculate the distance to the camera
|
||||
* based on method (3) described above.
|
||||
*/
|
||||
|
||||
ale_pos dist1 = sqrt((a[0] - c[0])
|
||||
* (a[0] - c[0])
|
||||
+ (a[1] - c[1])
|
||||
* (a[1] - c[1]));
|
||||
|
||||
ale_pos dist2 = sqrt((b[0] - d[0])
|
||||
* (b[0] - d[0])
|
||||
+ (b[1] - d[1])
|
||||
* (b[1] - d[1]));
|
||||
|
||||
ale_pos avg_dist = (dist1 + dist2) / 2;
|
||||
|
||||
|
||||
ale_pos tangent = tan(_init_angle / 2);
|
||||
|
||||
ale_pos distance = avg_dist / (2 * tangent);
|
||||
|
||||
/*
|
||||
* Set the position of the camera based on the estimate
|
||||
* from method (3). This is used as the initial
|
||||
* position for method (2). We assume that the camera
|
||||
* is placed so that its 0 and 1 coordinates match those
|
||||
* of e.
|
||||
*/
|
||||
|
||||
point estimate;
|
||||
|
||||
estimate[0] = e[0];
|
||||
estimate[1] = e[1];
|
||||
estimate[2] = distance;
|
||||
|
||||
// fprintf(stderr, "position (n=%d) %f %f %f\n", i, estimate[0], estimate[1], estimate[2]);
|
||||
|
||||
/*
|
||||
* Perform method (2).
|
||||
*/
|
||||
|
||||
estimate = gd_position(estimate, a, b, c, d, t);
|
||||
|
||||
// fprintf(stderr, ".");
|
||||
|
||||
/*
|
||||
* Assign transformation values based on the output of
|
||||
* method (2), by modifying transformation parameters
|
||||
* from the identity transformation.
|
||||
*/
|
||||
|
||||
alignment_array[i] = et::identity();
|
||||
|
||||
// fprintf(stderr, "position (n=%d) %f %f %f\n", i, estimate[0], estimate[1], estimate[2]);
|
||||
|
||||
/*
|
||||
* Modify translation values, if desired.
|
||||
*/
|
||||
|
||||
if (_vp_adjust) {
|
||||
alignment_array[i].modify_translation(0, -estimate[0]);
|
||||
alignment_array[i].modify_translation(1, -estimate[1]);
|
||||
alignment_array[i].modify_translation(2, -estimate[2]);
|
||||
} else {
|
||||
|
||||
/*
|
||||
* Establish a default translation value.
|
||||
*/
|
||||
|
||||
alignment_array[i].modify_translation(2, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Load any transformations.
|
||||
*/
|
||||
|
||||
if (i == 0) {
|
||||
int is_default;
|
||||
pt p = tload_first(tload, projective(i), &is_default);
|
||||
alignment_array[i] = p.e();
|
||||
_init_angle = p.view_angle();
|
||||
} else {
|
||||
int is_default;
|
||||
pt p = tload_next(tload, projective(i), &is_default);
|
||||
alignment_array[i] = p.e();
|
||||
|
||||
if (p.view_angle() != _init_angle) {
|
||||
fprintf(stderr, "Error: variation in view angle is not currently supported.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Assert that the z-axis translation is nonzero. This
|
||||
* is important for determining rotation values.
|
||||
*/
|
||||
|
||||
assert (estimate[2] != 0);
|
||||
|
||||
/*
|
||||
* Check whether rotation adjustment must proceed.
|
||||
*/
|
||||
|
||||
if (!_vo_adjust) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Modify rotation values
|
||||
*
|
||||
* The axis of the view pyramid should be mapped onto
|
||||
* the z-axis. Hence, the point of intersection
|
||||
* between the world-coordinates xy-plane and the axis
|
||||
* of the pyramid should occur at (0, 0) in local x-y
|
||||
* coordinates.
|
||||
*
|
||||
* If we temporarily assume no rotation about the
|
||||
* z-axis (e2 == 0), then the Euler angles (e0, e1, e2)
|
||||
* used to determine rotation give us:
|
||||
*
|
||||
* x' = x cos e1 - (z cos e0 - y sin e0) sin e1
|
||||
* y' = y cos e0 + z sin e0
|
||||
* z' = (z cos e0 - y sin e0) cos e1 + x sin e1
|
||||
*
|
||||
* Setting x' = y' = 0, we get:
|
||||
*
|
||||
* e0 = arctan (-y/z)
|
||||
* e1 = arctan (x/(z cos e0 - y sin e0))
|
||||
* [optionally add pi to achieve z' < 0]
|
||||
*
|
||||
* To set e2, taking T to be the 3D transformation as a
|
||||
* function of e2, we first ensure that
|
||||
*
|
||||
* tan(T(e2, a)[1] / T(e2, a)[0])
|
||||
* ==
|
||||
* tan(width / height)
|
||||
*
|
||||
* by assigning
|
||||
*
|
||||
* e2 += tan(width / height)
|
||||
* - tan(T(e2, a)[1] / T(e2, a)[0])
|
||||
*
|
||||
* Once this condition is satisfied, we conditionally
|
||||
* assign
|
||||
*
|
||||
* e2 += pi
|
||||
*
|
||||
* to ensure that
|
||||
*
|
||||
* T(e2, a)[0] < 0
|
||||
* T(e2, a)[1] < 0
|
||||
*
|
||||
* which places the transformed point in the lower-left
|
||||
* quadrant. This is correct, since point A is mapped
|
||||
* from (0, 0), the most negative point in the image.
|
||||
*/
|
||||
|
||||
point e_translated = alignment_array[i](e);
|
||||
|
||||
// fprintf(stderr, "axis-intersection (n=%d) e1 %f e0 %f e_t1 %f e_t0 %f e_t2 %f\n",
|
||||
// i,
|
||||
// e[1],
|
||||
// e[0],
|
||||
// alignment_array[i](e)[1],
|
||||
// alignment_array[i](e)[0],
|
||||
// alignment_array[i](e)[2]);
|
||||
//
|
||||
// fprintf(stderr, "camera origin (n=%d) o1 %f o0 %f o2 %f o_t1 %f o_t0 %f o_t2 %f\n",
|
||||
// i,
|
||||
// estimate[1],
|
||||
// estimate[0],
|
||||
// estimate[2],
|
||||
// alignment_array[i](estimate)[1],
|
||||
// alignment_array[i](estimate)[0],
|
||||
// alignment_array[i](estimate)[2]);
|
||||
|
||||
ale_pos e0 = atan(-e_translated[1] / e_translated[2]);
|
||||
ale_pos e1 = atan((double) e_translated[0]
|
||||
/ ((double) e_translated[2] * cos(e0)
|
||||
- (double) e_translated[1] * sin(e0)));
|
||||
|
||||
alignment_array[i].modify_rotation(0, e0);
|
||||
alignment_array[i].modify_rotation(1, e1);
|
||||
|
||||
if (alignment_array[i](e)[2] > 0)
|
||||
alignment_array[i].modify_rotation(1, M_PI);
|
||||
|
||||
// fprintf(stderr, "axis-intersection (n=%d) e1 %f e0 %f e_t1 %f e_t0 %f e_t2 %f\n",
|
||||
// i,
|
||||
// e[1],
|
||||
// e[0],
|
||||
// alignment_array[i](e)[1],
|
||||
// alignment_array[i](e)[0],
|
||||
// alignment_array[i](e)[2]);
|
||||
//
|
||||
// fprintf(stderr, "camera origin (n=%d) o_t1 %f o_t0 %f o_t2 %f\n",
|
||||
// i,
|
||||
// alignment_array[i](estimate)[1],
|
||||
// alignment_array[i](estimate)[0],
|
||||
// alignment_array[i](estimate)[2]);
|
||||
|
||||
point a_transformed = alignment_array[i](a);
|
||||
|
||||
ale_pos e2 = atan((t.scaled_width() - 1) / (t.scaled_height() - 1))
|
||||
- atan(a_transformed[1] / a_transformed[0]);
|
||||
|
||||
// fprintf(stderr, "a components (n=%d) a1 %f a0 %f\n", i, a[1], a[0]);
|
||||
// fprintf(stderr, "e2 components (n=%d) tw %f th %f a_t1 %f a_t0 %f\n", i,
|
||||
// t.scaled_width(), t.scaled_height(), a_transformed[1], a_transformed[0]);
|
||||
|
||||
alignment_array[i].modify_rotation(2, e2);
|
||||
|
||||
// fprintf(stderr, "rotation (n=%d) e0 %f e1 %f e2 %f\n", i, e0, e1, e2);
|
||||
|
||||
if (alignment_array[i](a)[0] > 0) {
|
||||
e2 += M_PI;
|
||||
alignment_array[i].modify_rotation(2, M_PI);
|
||||
|
||||
// fprintf(stderr, "adding 2pi to e2.");
|
||||
}
|
||||
|
||||
// fprintf(stderr, "rotation (n=%d) e0 %f e1 %f e2 %f\n", i, e0, e1, e2);
|
||||
|
||||
// fprintf(stderr, "(0, 0) output (n=%d) a1 %f a0 %f a_t1 %f a_t0 %f\n",
|
||||
// i,
|
||||
// a[1],
|
||||
// a[0],
|
||||
// alignment_array[i](a)[1],
|
||||
// alignment_array[i](a)[0]);
|
||||
|
||||
assert (alignment_array[i](a)[0] < 0);
|
||||
assert (alignment_array[i](a)[1] < 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void adjust_translation(unsigned int n, int d, ale_pos x) {
|
||||
alignment_array[n].modify_translation(d, x);
|
||||
}
|
||||
|
||||
static void adjust_rotation(unsigned int n, int d, ale_pos x) {
|
||||
alignment_array[n].modify_rotation(d, x);
|
||||
}
|
||||
|
||||
static void set_translation(unsigned int n, int d, ale_pos x) {
|
||||
alignment_array[n].set_translation(d, x);
|
||||
}
|
||||
|
||||
static void set_rotation(unsigned int n, int d, ale_pos x) {
|
||||
alignment_array[n].set_rotation(d, x);
|
||||
}
|
||||
|
||||
static void adjust_view_angle(ale_pos x) {
|
||||
_init_angle += x;
|
||||
}
|
||||
|
||||
static void set_view_angle(ale_pos x) {
|
||||
_init_angle = x;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
47
d3/cpf.cc
Normal file
47
d3/cpf.cc
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright 2005 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* d3/cpf.cc: Control point file handler static variables.
|
||||
*/
|
||||
|
||||
#include "cpf.h"
|
||||
|
||||
FILE *cpf::load_f = NULL;
|
||||
FILE *cpf::save_f = NULL;
|
||||
int cpf::load_version = -1;
|
||||
|
||||
const char *cpf::load_n = NULL;
|
||||
const char *cpf::save_n = NULL;
|
||||
int cpf::save_version = 0;
|
||||
|
||||
struct cpf::control_point *cpf::cp_array = NULL;
|
||||
unsigned int cpf::cp_array_max = 0;
|
||||
unsigned int cpf::cp_index = 0;
|
||||
|
||||
ale_pos cpf::cpp_lower = 0.125;
|
||||
ale_pos cpf::cpp_upper = 32;
|
||||
ale_pos cpf::va_upper = 32;
|
||||
|
||||
ale_pos cpf::stereo_threshold = 4;
|
||||
|
||||
unsigned int cpf::systems_solved = 0;
|
||||
|
||||
int cpf::total_error_mean = 1;
|
||||
605
d3/cpf.h
Normal file
605
d3/cpf.h
Normal file
@@ -0,0 +1,605 @@
|
||||
// Copyright 2003, 2004, 2005 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* d3/cpf.h: Control point file interface.
|
||||
*/
|
||||
|
||||
#ifndef __cpf_h__
|
||||
#define __cpf_h__
|
||||
|
||||
#include "point.h"
|
||||
|
||||
#define CPF_VERSION 0
|
||||
#define CPF_VERSION_MAX 0
|
||||
|
||||
class cpf {
|
||||
static FILE *load_f;
|
||||
static FILE *save_f;
|
||||
static int load_version;
|
||||
|
||||
static const char *load_n;
|
||||
static const char *save_n;
|
||||
static int save_version;
|
||||
|
||||
static ale_pos cpp_upper;
|
||||
static ale_pos va_upper;
|
||||
static ale_pos cpp_lower;
|
||||
|
||||
static ale_pos stereo_threshold;
|
||||
|
||||
static int total_error_mean;
|
||||
|
||||
/*
|
||||
* TYPE is:
|
||||
* 0 type A
|
||||
* 1 type B
|
||||
* 2 type C
|
||||
*/
|
||||
struct control_point {
|
||||
int type;
|
||||
d2::point *d2;
|
||||
point d3;
|
||||
};
|
||||
|
||||
static struct control_point *cp_array;
|
||||
static unsigned int cp_array_max;
|
||||
static unsigned int cp_index;
|
||||
|
||||
static unsigned int systems_solved;
|
||||
|
||||
static void error(const char *message) {
|
||||
fprintf(stderr, "cpf: Error: %s", message);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void get_integer(int *i) {
|
||||
if(fscanf(load_f, " %d", i) != 1)
|
||||
error("Could not get integer.");
|
||||
}
|
||||
|
||||
static void get_double(double *d) {
|
||||
if (fscanf(load_f, " %lf", d) != 1)
|
||||
error("Could not get double.");
|
||||
}
|
||||
|
||||
static void get_new_line() {
|
||||
int next_character = 0;
|
||||
|
||||
while (next_character != EOF
|
||||
&& next_character != '\n')
|
||||
next_character = fgetc(load_f);
|
||||
}
|
||||
|
||||
static void check_version(int v) {
|
||||
if (v > CPF_VERSION_MAX)
|
||||
error("Incompatible version number.");
|
||||
}
|
||||
|
||||
/*
|
||||
* Type A control point record
|
||||
*
|
||||
* A <frame 0 coord 1> <frame 0 coord 0> ... <frame n coord 0>
|
||||
*/
|
||||
static void get_type_a() {
|
||||
|
||||
/*
|
||||
* Get the number of frames.
|
||||
*/
|
||||
int n = d2::image_rw::count();
|
||||
|
||||
/*
|
||||
* Allocate storage for N frames.
|
||||
*/
|
||||
d2::point *coords = new d2::point[n];
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
for (int j = 0; j < 2; j++) {
|
||||
double dp;
|
||||
get_double(&dp);
|
||||
coords[i][1 - j] = dp;
|
||||
}
|
||||
|
||||
cp_array[cp_array_max - 1].d2 = coords;
|
||||
cp_array[cp_array_max - 1].d3 = point::undefined();
|
||||
cp_array[cp_array_max - 1].type = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Type B control point record
|
||||
*
|
||||
* B <coord 1> <coord 0> <coord 2>
|
||||
*/
|
||||
static void get_type_b() {
|
||||
double d[3];
|
||||
|
||||
get_double(&d[1]);
|
||||
get_double(&d[0]);
|
||||
get_double(&d[2]);
|
||||
|
||||
cp_array[cp_array_max - 1].d3 = point(d[0], d[1], d[2]);
|
||||
cp_array[cp_array_max - 1].type = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Type C control point record
|
||||
*
|
||||
* C <type A data> <type B data>
|
||||
*/
|
||||
static void get_type_c() {
|
||||
get_type_a();
|
||||
get_type_b();
|
||||
cp_array[cp_array_max - 1].type = 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a control point file.
|
||||
*/
|
||||
static void read_file() {
|
||||
while (load_f && !feof(load_f)) {
|
||||
int command_char;
|
||||
|
||||
command_char = fgetc(load_f);
|
||||
|
||||
switch (command_char) {
|
||||
case EOF:
|
||||
return;
|
||||
case '#':
|
||||
case ' ':
|
||||
case '\t':
|
||||
get_new_line();
|
||||
break;
|
||||
case '\r':
|
||||
case '\n':
|
||||
break;
|
||||
case 'V':
|
||||
get_integer(&load_version);
|
||||
check_version(load_version);
|
||||
get_new_line();
|
||||
break;
|
||||
case 'A':
|
||||
cp_array = (control_point *) realloc(cp_array, ++cp_array_max * sizeof(control_point));
|
||||
assert(cp_array);
|
||||
get_type_a();
|
||||
get_new_line();
|
||||
break;
|
||||
case 'B':
|
||||
cp_array = (control_point *) realloc(cp_array, ++cp_array_max * sizeof(control_point));
|
||||
assert(cp_array);
|
||||
get_type_b();
|
||||
get_new_line();
|
||||
break;
|
||||
case 'C':
|
||||
cp_array = (control_point *) realloc(cp_array, ++cp_array_max * sizeof(control_point));
|
||||
assert(cp_array);
|
||||
get_type_c();
|
||||
get_new_line();
|
||||
break;
|
||||
default:
|
||||
error("Unrecognized command");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the centroid of a set of points.
|
||||
*/
|
||||
static point calculate_centroid(point *points, int n) {
|
||||
point sum(0, 0, 0);
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (!points[i].defined())
|
||||
continue;
|
||||
sum += points[i];
|
||||
count++;
|
||||
}
|
||||
|
||||
return sum / count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Measure the error between a projected system and a solved coordinate.
|
||||
*/
|
||||
static ale_real measure_projected_error(point solved, const d2::point coords[], int n) {
|
||||
ale_accum error = 0;
|
||||
ale_accum divisor = 0;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (!coords[i].defined())
|
||||
continue;
|
||||
|
||||
pt t = align::projective(i);
|
||||
|
||||
point sp = t.wp_unscaled(solved);
|
||||
|
||||
error += (sp.xy() - coords[i]).normsq();
|
||||
divisor += 1;
|
||||
}
|
||||
|
||||
return sqrt(error / divisor);
|
||||
}
|
||||
|
||||
static ale_accum measure_total_error() {
|
||||
|
||||
if (cp_array_max == 0)
|
||||
return 0;
|
||||
|
||||
if (total_error_mean) {
|
||||
/*
|
||||
* Use mean error.
|
||||
*/
|
||||
|
||||
ale_accum result = 0;
|
||||
ale_accum divisor = 0;
|
||||
|
||||
for (unsigned int i = 0; i < cp_array_max; i++) {
|
||||
ale_accum e = measure_projected_error(cp_array[i].d3, cp_array[i].d2, d2::image_rw::count());
|
||||
if (!finite(e))
|
||||
continue;
|
||||
|
||||
result += e * e;
|
||||
divisor += 1;
|
||||
}
|
||||
|
||||
return sqrt(result / divisor);
|
||||
} else {
|
||||
/*
|
||||
* Use median error
|
||||
*/
|
||||
|
||||
std::vector<ale_accum> v;
|
||||
|
||||
for (unsigned int i = 0; i < cp_array_max; i++) {
|
||||
ale_accum e = measure_projected_error(cp_array[i].d3, cp_array[i].d2, d2::image_rw::count());
|
||||
if (!finite(e))
|
||||
continue;
|
||||
|
||||
v.push_back(fabs(e));
|
||||
}
|
||||
|
||||
std::sort(v.begin(), v.end());
|
||||
|
||||
if (v.size() % 2) {
|
||||
return v[v.size() / 2];
|
||||
} else {
|
||||
return 0.5 * (v[v.size() / 2 - 1]
|
||||
+ v[v.size() / 2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Solve for a 3D point from a system of projected coordinates.
|
||||
*
|
||||
* The algorithm is this:
|
||||
*
|
||||
* First, convert all 2D points to 3D points by projecting them onto a
|
||||
* plane perpendicular to the view axis of the corresponding camera,
|
||||
* and passing through the origin of the world coordinate system.
|
||||
* Then, for each point, move it along the view ray to the point
|
||||
* closest to the centroid of all of the points. Repeat this last loop
|
||||
* until the largest adjustment is smaller than some specified lower
|
||||
* bound.
|
||||
*/
|
||||
static point solve_projected_system(const d2::point points[], int n) {
|
||||
|
||||
/*
|
||||
* Copy the passed array.
|
||||
*/
|
||||
point *points_copy = new point[n];
|
||||
for (int i = 0; i < n; i++)
|
||||
points_copy[i] = point(points[i][0], points[i][1], 0);
|
||||
|
||||
/*
|
||||
* Set an initial depth for each point, and convert it to world
|
||||
* coordinates.
|
||||
*/
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
pt t = align::projective(i);
|
||||
|
||||
point p = t.wc(point(0, 0, 0));
|
||||
ale_pos plane_depth = p[2];
|
||||
|
||||
points_copy[i][2] = plane_depth;
|
||||
|
||||
points_copy[i] = t.pw_unscaled(points_copy[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* For each point, adjust the depth along the view ray to
|
||||
* minimize the distance from the centroid of the points_copy.
|
||||
*/
|
||||
|
||||
ale_pos max_diff = 0;
|
||||
ale_pos prev_max_diff = 0;
|
||||
ale_pos diff_bound = 0.99999;
|
||||
|
||||
while (!(max_diff / prev_max_diff > diff_bound) || !finite(max_diff / prev_max_diff)) {
|
||||
|
||||
/*
|
||||
* Calculate the centroid of all points_copy.
|
||||
*/
|
||||
|
||||
point centroid = calculate_centroid(points_copy, n);
|
||||
|
||||
// fprintf(stderr, "md %f pmd %f ratio %f ", max_diff, prev_max_diff, max_diff / prev_max_diff);
|
||||
// fprintf(stderr, "centroid %f %f %f ", centroid[0], centroid[1], centroid[2]);
|
||||
// fprintf(stderr, "%f ", measure_projected_error(centroid, points, n));
|
||||
|
||||
prev_max_diff = max_diff;
|
||||
max_diff = 0;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
// fprintf(stderr, "points_copy[%d] %f %f %f ", i, points_copy[i][0], points_copy[i][1], points_copy[i][2]);
|
||||
|
||||
if (!points_copy[i].defined())
|
||||
continue;
|
||||
|
||||
pt t = align::projective(i);
|
||||
point camera_origin = t.cw(point(0, 0, 0));
|
||||
|
||||
point v = points_copy[i] - camera_origin;
|
||||
ale_pos l = (centroid - camera_origin).norm();
|
||||
ale_pos alpha = camera_origin.anglebetw(points_copy[i], centroid);
|
||||
|
||||
point new_point = camera_origin + v / v.norm() * l * cos(alpha);
|
||||
|
||||
ale_pos diff = points_copy[i].lengthto(new_point);
|
||||
|
||||
if (diff > max_diff)
|
||||
max_diff = diff;
|
||||
|
||||
points_copy[i] = new_point;
|
||||
}
|
||||
|
||||
}
|
||||
// fprintf(stderr, "%f\n", measure_projected_error(calculate_centroid(points_copy, n), points, n));
|
||||
// fprintf(stderr, "md %f pmd %f ratio %f ", max_diff, prev_max_diff, max_diff / prev_max_diff);
|
||||
|
||||
point result = calculate_centroid(points_copy, n);
|
||||
|
||||
delete[] points_copy;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void solve_total_system() {
|
||||
for (unsigned i = 0; i < cp_array_max; i++) {
|
||||
if (cp_array[i].type == 0)
|
||||
cp_array[i].d3 = solve_projected_system(cp_array[i].d2, d2::image_rw::count());
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static void err_median() {
|
||||
total_error_mean = 0;
|
||||
}
|
||||
|
||||
static void err_mean() {
|
||||
total_error_mean = 1;
|
||||
}
|
||||
|
||||
static void set_cpp_upper(ale_pos cu) {
|
||||
cpp_upper = cu;
|
||||
}
|
||||
|
||||
static void set_cpp_lower(ale_pos cl) {
|
||||
cpp_lower = cl;
|
||||
}
|
||||
|
||||
static void set_va_upper(ale_pos vau_degrees) {
|
||||
va_upper = (double) vau_degrees * M_PI / 180;
|
||||
}
|
||||
|
||||
static void init_loadfile(const char *filename) {
|
||||
load_n = filename;
|
||||
load_f = fopen(load_n, "r");
|
||||
|
||||
if (!load_f) {
|
||||
fprintf(stderr, "cpf: Error: could not open control point file '%s'.", load_n);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_savefile(const char *filename) {
|
||||
save_n = filename;
|
||||
save_f = fopen(save_n, "w");
|
||||
|
||||
if (!save_f) {
|
||||
fprintf(stderr, "cpf: Error: could not open control point file '%s'.", save_n);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(save_f, "# created by ALE control point file handler version %d\n", CPF_VERSION);
|
||||
|
||||
fclose(save_f);
|
||||
}
|
||||
|
||||
static void adjust_cameras() {
|
||||
ale_accum current_error = measure_total_error();
|
||||
unsigned int n = d2::image_rw::count();
|
||||
|
||||
/*
|
||||
* Perturbation measured in pixels or degrees
|
||||
*
|
||||
* XXX: should probably be pixel arclength instead of degrees.
|
||||
*/
|
||||
|
||||
ale_pos max_perturbation = pow(2, floor(log(cpp_upper) / log(2)));
|
||||
ale_pos min_perturbation = cpp_lower;
|
||||
ale_pos perturbation = max_perturbation;
|
||||
|
||||
ui::get()->d3_control_point_data(max_perturbation, min_perturbation, perturbation, current_error);
|
||||
|
||||
/*
|
||||
* XXX: Does this ever execute?
|
||||
*/
|
||||
if (cp_array_max == 0) {
|
||||
fprintf(stderr, " (no points specified)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (perturbation < min_perturbation || cp_array_max == 0) {
|
||||
// fprintf(stderr, " (skipping adjustment)");
|
||||
return;
|
||||
}
|
||||
|
||||
while (perturbation >= min_perturbation) {
|
||||
|
||||
ale_accum previous_error;
|
||||
ale_pos angular_p = (double) perturbation / 180 * M_PI;
|
||||
|
||||
// fprintf(stderr, "P %f AP %f ", perturbation, angular_p);
|
||||
|
||||
do {
|
||||
|
||||
/*
|
||||
* Minimum frame to adjust
|
||||
*/
|
||||
int M = 1;
|
||||
|
||||
previous_error = current_error;
|
||||
|
||||
ale_accum test_error;
|
||||
|
||||
/*
|
||||
* Try adjusting camera positions
|
||||
*/
|
||||
|
||||
for (unsigned int i = M; i < n; i++)
|
||||
for (unsigned int d = 0; d < 3; d++)
|
||||
for ( int s = -1; s <= 1; s+=2) {
|
||||
align::adjust_translation(i, d, s * perturbation);
|
||||
solve_total_system();
|
||||
test_error = measure_total_error();
|
||||
if (test_error < current_error) {
|
||||
current_error = test_error;
|
||||
} else {
|
||||
align::adjust_translation(i, d, -s * perturbation);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Try adjusting camera orientations
|
||||
*/
|
||||
|
||||
for (unsigned int i = M; i < n; i++)
|
||||
for (unsigned int d = 0; d < 3; d++)
|
||||
for ( int s = -1; s <= 1; s+=2) {
|
||||
align::adjust_rotation(i, d, s * angular_p);
|
||||
solve_total_system();
|
||||
test_error = measure_total_error();
|
||||
if (test_error < current_error) {
|
||||
current_error = test_error;
|
||||
} else {
|
||||
align::adjust_rotation(i, d, -s * angular_p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Try adjusting view angle
|
||||
*/
|
||||
if (angular_p <= va_upper)
|
||||
for (int s = -1; s <= 1; s+=2) {
|
||||
align::adjust_view_angle(s * angular_p);
|
||||
solve_total_system();
|
||||
test_error = measure_total_error();
|
||||
if (test_error < current_error) {
|
||||
current_error = test_error;
|
||||
} else {
|
||||
align::adjust_view_angle(-s * angular_p);
|
||||
}
|
||||
}
|
||||
} while (current_error < previous_error);
|
||||
|
||||
// fprintf(stderr, "E %f\n", current_error);
|
||||
|
||||
perturbation /= 2;
|
||||
|
||||
ui::get()->d3_control_point_data(max_perturbation, min_perturbation, perturbation, current_error);
|
||||
ui::get()->d3_control_point_step();
|
||||
}
|
||||
|
||||
solve_total_system();
|
||||
}
|
||||
|
||||
static void st(ale_pos _st) {
|
||||
stereo_threshold = _st;
|
||||
}
|
||||
|
||||
static void solve_3d() {
|
||||
if (systems_solved)
|
||||
return;
|
||||
|
||||
solve_total_system();
|
||||
adjust_cameras();
|
||||
systems_solved = 1;
|
||||
}
|
||||
|
||||
static unsigned int count() {
|
||||
|
||||
if (cp_array_max == 0)
|
||||
read_file();
|
||||
|
||||
return cp_array_max;
|
||||
}
|
||||
|
||||
static const d2::point *get_2d(unsigned int index) {
|
||||
assert (index < cp_array_max);
|
||||
assert (cp_array != NULL);
|
||||
|
||||
if (cp_array[index].type == 1)
|
||||
return NULL;
|
||||
|
||||
return cp_array[index].d2;
|
||||
}
|
||||
|
||||
static point get(unsigned int index) {
|
||||
|
||||
assert (index < cp_array_max);
|
||||
assert (cp_array != NULL);
|
||||
|
||||
if (!systems_solved)
|
||||
solve_3d();
|
||||
|
||||
if (stereo_threshold < (ale_pos) measure_projected_error(cp_array[index].d3,
|
||||
cp_array[index].d2,
|
||||
d2::image_rw::count()))
|
||||
return point::undefined();
|
||||
|
||||
|
||||
return cp_array[index].d3;
|
||||
}
|
||||
|
||||
static void set(point p) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
static void finish_loadfile() {
|
||||
}
|
||||
|
||||
static void finish_savefile() {
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
383
d3/et.h
Normal file
383
d3/et.h
Normal file
@@ -0,0 +1,383 @@
|
||||
// Copyright 2003 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* d3/et.h: Represent three-dimensional Euclidean transformations.
|
||||
*/
|
||||
|
||||
#ifndef __et_h__
|
||||
#define __et_h__
|
||||
|
||||
#include "point.h"
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Structure to describe a three-dimensional euclidean transformation.
|
||||
*
|
||||
* We consider points to be transformed as homogeneous coordinate vectors
|
||||
* multiplied on the right of the transformation matrix. The transformations
|
||||
* are assumed to be small, so xyz Euler angles are used to specify rotation.
|
||||
* The order of transformations is (starting with a point representation in the
|
||||
* original coordinate system):
|
||||
*
|
||||
* i) translation of the point
|
||||
* ii) x-rotation about the origin
|
||||
* iii) y-rotation about the origin
|
||||
* iv) z-rotation about the origin
|
||||
*
|
||||
* For more information on Euler angles, see:
|
||||
*
|
||||
* http://mathworld.wolfram.com/EulerAngles.html
|
||||
*
|
||||
* For more information on rotation matrices, see:
|
||||
*
|
||||
* http://mathworld.wolfram.com/RotationMatrix.html
|
||||
*
|
||||
* XXX: inconsistently with the 2D class, this class uses radians to represent
|
||||
* rotation values.
|
||||
*
|
||||
*/
|
||||
|
||||
struct et {
|
||||
private:
|
||||
ale_pos translation[3];
|
||||
ale_pos rotation[3];
|
||||
mutable ale_pos matrix[4][4];
|
||||
mutable ale_pos matrix_inverse[4][4];
|
||||
mutable int resultant_memo;
|
||||
mutable int resultant_inverse_memo;
|
||||
|
||||
|
||||
/*
|
||||
* Create an identity matrix
|
||||
*/
|
||||
void mident(ale_pos m1[4][4]) const {
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
m1[i][j] = (i == j) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a rotation matrix
|
||||
*/
|
||||
void mrot(ale_pos m1[4][4], ale_pos angle, int index) const {
|
||||
mident(m1);
|
||||
m1[(index+1)%3][(index+1)%3] = cos(angle);
|
||||
m1[(index+2)%3][(index+2)%3] = cos(angle);
|
||||
m1[(index+1)%3][(index+2)%3] = sin(angle);
|
||||
m1[(index+2)%3][(index+1)%3] = -sin(angle);
|
||||
}
|
||||
|
||||
/*
|
||||
* Multiply matrices M1 and M2; return result M3.
|
||||
*/
|
||||
void mmult(ale_pos m3[4][4], ale_pos m1[4][4], ale_pos m2[4][4]) const {
|
||||
int k;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
for (m3[i][j] = 0, k = 0; k < 4; k++)
|
||||
m3[i][j] += m1[i][k] * m2[k][j];
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate resultant matrix values.
|
||||
*/
|
||||
void resultant() const {
|
||||
|
||||
/*
|
||||
* If we already know the answers, don't bother calculating
|
||||
* them again.
|
||||
*/
|
||||
|
||||
if (resultant_memo)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Multiply matrices.
|
||||
*/
|
||||
|
||||
ale_pos m1[4][4], m2[4][4], m3[4][4];
|
||||
|
||||
/*
|
||||
* Translation
|
||||
*/
|
||||
|
||||
mident(m1);
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
m1[i][3] = translation[i];
|
||||
|
||||
/*
|
||||
* Rotation about x
|
||||
*/
|
||||
|
||||
mrot(m2, rotation[0], 0);
|
||||
mmult(m3, m2, m1);
|
||||
|
||||
/*
|
||||
* Rotation about y
|
||||
*/
|
||||
|
||||
mrot(m1, rotation[1], 1);
|
||||
mmult(m2, m1, m3);
|
||||
|
||||
/*
|
||||
* Rotation about z
|
||||
*/
|
||||
|
||||
mrot(m3, rotation[2], 2);
|
||||
mmult(matrix, m3, m2);
|
||||
|
||||
resultant_memo = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the inverse transform matrix values.
|
||||
*/
|
||||
void resultant_inverse () const {
|
||||
|
||||
/*
|
||||
* If we already know the answers, don't bother calculating
|
||||
* them again.
|
||||
*/
|
||||
|
||||
if (resultant_inverse_memo)
|
||||
return;
|
||||
|
||||
/*
|
||||
* The inverse can be explicitly calculated from the rotation
|
||||
* and translation parameters. We invert the individual
|
||||
* matrices and reverse the order of multiplication.
|
||||
*/
|
||||
|
||||
ale_pos m1[4][4], m2[4][4], m3[4][4];
|
||||
|
||||
/*
|
||||
* Translation
|
||||
*/
|
||||
|
||||
mident(m1);
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
m1[i][3] = -translation[i];
|
||||
|
||||
/*
|
||||
* Rotation about x
|
||||
*/
|
||||
|
||||
mrot(m2, -rotation[0], 0);
|
||||
mmult(m3, m1, m2);
|
||||
|
||||
/*
|
||||
* Rotation about y
|
||||
*/
|
||||
|
||||
mrot(m1, -rotation[1], 1);
|
||||
mmult(m2, m3, m1);
|
||||
|
||||
/*
|
||||
* Rotation about z
|
||||
*/
|
||||
|
||||
mrot(m3, -rotation[2], 2);
|
||||
mmult(matrix_inverse, m2, m3);
|
||||
|
||||
resultant_inverse_memo = 1;
|
||||
}
|
||||
|
||||
public:
|
||||
/*
|
||||
* Transform point p.
|
||||
*/
|
||||
struct point transform(struct point p) const {
|
||||
struct point result;
|
||||
|
||||
resultant();
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int k = 0; k < 3; k++)
|
||||
result[i] += matrix[i][k] * p[k];
|
||||
result[i] += matrix[i][3];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* operator() is the transformation operator.
|
||||
*/
|
||||
struct point operator()(struct point p) const {
|
||||
return transform(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Map point p using the inverse of the transform.
|
||||
*/
|
||||
struct point inverse_transform(struct point p) const {
|
||||
struct point result;
|
||||
|
||||
resultant_inverse();
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int k = 0; k < 3; k++)
|
||||
result[i] += matrix_inverse[i][k] * p[k];
|
||||
result[i] += matrix_inverse[i][3];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Default constructor
|
||||
*
|
||||
* Returns the identity transformation.
|
||||
*
|
||||
* Note: identity() depends on this.
|
||||
*/
|
||||
et() {
|
||||
resultant_memo = 0;
|
||||
resultant_inverse_memo = 0;
|
||||
|
||||
translation[0] = 0;
|
||||
translation[1] = 0;
|
||||
translation[2] = 0;
|
||||
|
||||
rotation[0] = 0;
|
||||
rotation[1] = 0;
|
||||
rotation[2] = 0;
|
||||
}
|
||||
|
||||
et(ale_pos x, ale_pos y, ale_pos z, ale_pos P, ale_pos Y, ale_pos R) {
|
||||
resultant_memo = 0;
|
||||
resultant_inverse_memo = 0;
|
||||
|
||||
translation[0] = x;
|
||||
translation[1] = y;
|
||||
translation[2] = z;
|
||||
|
||||
rotation[0] = P;
|
||||
rotation[1] = Y;
|
||||
rotation[2] = R;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return identity transformation.
|
||||
*/
|
||||
static struct et identity() {
|
||||
struct et r;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set Euclidean parameters (x, y, z, P, Y, R).
|
||||
*/
|
||||
void set(double values[6]) {
|
||||
for (int i = 0; i < 3; i++)
|
||||
translation[i] = values[i];
|
||||
for (int i = 0; i < 3; i++)
|
||||
rotation[i] = values[i + 3];
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust translation in the indicated manner.
|
||||
*/
|
||||
void modify_translation(int i1, ale_pos diff) {
|
||||
assert (i1 >= 0);
|
||||
assert (i1 < 3);
|
||||
|
||||
resultant_memo = 0;
|
||||
resultant_inverse_memo = 0;
|
||||
|
||||
translation[i1] += diff;
|
||||
}
|
||||
|
||||
void set_translation(int i1, ale_pos new_value) {
|
||||
assert (i1 >= 0);
|
||||
assert (i1 < 3);
|
||||
|
||||
resultant_memo = 0;
|
||||
resultant_inverse_memo = 0;
|
||||
|
||||
translation[i1] = new_value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust rotation in the indicated manner.
|
||||
*/
|
||||
void modify_rotation(int i1, ale_pos diff) {
|
||||
assert (i1 >= 0);
|
||||
assert (i1 < 3);
|
||||
|
||||
resultant_memo = 0;
|
||||
resultant_inverse_memo = 0;
|
||||
|
||||
rotation[i1] += diff;
|
||||
}
|
||||
|
||||
void set_rotation(int i1, ale_pos new_value) {
|
||||
assert (i1 >= 0);
|
||||
assert (i1 < 3);
|
||||
|
||||
resultant_memo = 0;
|
||||
resultant_inverse_memo = 0;
|
||||
|
||||
rotation[i1] = new_value;
|
||||
}
|
||||
|
||||
ale_pos get_rotation(int i1) {
|
||||
assert (i1 >= 0);
|
||||
assert (i1 < 3);
|
||||
|
||||
return rotation[i1];
|
||||
}
|
||||
|
||||
ale_pos get_translation(int i1) {
|
||||
assert (i1 >= 0);
|
||||
assert (i1 < 3);
|
||||
|
||||
return translation[i1];
|
||||
}
|
||||
|
||||
|
||||
void debug_output() {
|
||||
fprintf(stderr, "[et.do t=[%f %f %f] r=[%f %f %f]\n"
|
||||
" m=[[%f %f %f %f] [%f %f %f %f] [%f %f %f %f] [%f %f %f %f]]\n"
|
||||
" mi=[[%f %f %f %f] [%f %f %f %f] [%f %f %f %f] [%f %f %f %f]]\n"
|
||||
" rm=%d rim=%d]\n",
|
||||
(double) translation[0], (double) translation[1], (double) translation[2],
|
||||
(double) rotation[0], (double) rotation[1], (double) rotation[2],
|
||||
(double) matrix[0][0], (double) matrix[0][1], (double) matrix[0][2], (double) matrix[0][3],
|
||||
(double) matrix[1][0], (double) matrix[1][1], (double) matrix[1][2], (double) matrix[1][3],
|
||||
(double) matrix[2][0], (double) matrix[2][1], (double) matrix[2][2], (double) matrix[2][3],
|
||||
(double) matrix[3][0], (double) matrix[3][1], (double) matrix[3][2], (double) matrix[3][3],
|
||||
(double) matrix_inverse[0][0], (double) matrix_inverse[0][1], (double) matrix_inverse[0][2], (double) matrix_inverse[0][3],
|
||||
(double) matrix_inverse[1][0], (double) matrix_inverse[1][1], (double) matrix_inverse[1][2], (double) matrix_inverse[1][3],
|
||||
(double) matrix_inverse[2][0], (double) matrix_inverse[2][1], (double) matrix_inverse[2][2], (double) matrix_inverse[2][3],
|
||||
(double) matrix_inverse[3][0], (double) matrix_inverse[3][1], (double) matrix_inverse[3][2], (double) matrix_inverse[3][3],
|
||||
resultant_memo, resultant_inverse_memo);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
31
d3/focus.cc
Normal file
31
d3/focus.cc
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright 2003, 2004, 2005 David Hilvert <dhilvert@gmail.com>,
|
||||
// <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
|
||||
*/
|
||||
|
||||
#include "focus.h"
|
||||
|
||||
/*
|
||||
* See focus.h for details regarding these variables.
|
||||
*/
|
||||
|
||||
unsigned int focus::camera_index;
|
||||
std::vector<std::vector<focus::entry> > focus::focus_list;
|
||||
unsigned int focus::_uses_medians = 0;
|
||||
unsigned int focus::_max_samples = 0;
|
||||
178
d3/focus.h
Normal file
178
d3/focus.h
Normal file
@@ -0,0 +1,178 @@
|
||||
// Copyright 2006 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* d3/focus.h: Implementation of defocusing logic.
|
||||
*/
|
||||
|
||||
#ifndef __focus_h__
|
||||
#define __focus_h__
|
||||
|
||||
class focus {
|
||||
private:
|
||||
struct entry {
|
||||
int type;
|
||||
double distance;
|
||||
double px, py;
|
||||
double focal_range;
|
||||
double vertical_gradient;
|
||||
double horizontal_gradient;
|
||||
double start_depth;
|
||||
double end_depth;
|
||||
double start_x;
|
||||
double end_x;
|
||||
double start_y;
|
||||
double end_y;
|
||||
double aperture;
|
||||
unsigned int sample_count;
|
||||
unsigned int focal_statistic;
|
||||
unsigned int sample_randomization;
|
||||
};
|
||||
|
||||
static unsigned int _uses_medians;
|
||||
static unsigned int _max_samples;
|
||||
static unsigned int camera_index;
|
||||
static std::vector<std::vector<entry> > focus_list;
|
||||
|
||||
public:
|
||||
|
||||
struct result {
|
||||
double focal_distance;
|
||||
double aperture;
|
||||
unsigned int sample_count;
|
||||
unsigned int statistic;
|
||||
unsigned int randomization;
|
||||
};
|
||||
|
||||
static void add_region(unsigned int type, double distance, double px, double py,
|
||||
unsigned int ci, double fr, double ht, double vt, double sd, double ed,
|
||||
double sx, double ex, double sy, double ey, double ap, unsigned int sc, unsigned int fs,
|
||||
unsigned int sr) {
|
||||
|
||||
if (fs)
|
||||
_uses_medians = 1;
|
||||
|
||||
if (sc > _max_samples)
|
||||
_max_samples = sc;
|
||||
|
||||
if (focus_list.size() <= ci)
|
||||
focus_list.resize(ci + 1);
|
||||
|
||||
entry e = { type, distance, px, py, fr, vt, ht, sd, ed, sx, ex, sy, ey, ap, sc, fs, sr };
|
||||
|
||||
focus_list[ci].push_back(e);
|
||||
}
|
||||
|
||||
static int is_trivial() {
|
||||
return (focus_list.size() == 0);
|
||||
}
|
||||
|
||||
static int uses_medians() {
|
||||
return _uses_medians;
|
||||
}
|
||||
|
||||
static unsigned int max_samples() {
|
||||
return _max_samples;
|
||||
}
|
||||
|
||||
static result get(const d2::image *depth, int i, int j) {
|
||||
|
||||
ale_pos d = (double) depth->get_pixel(i, j)[0];
|
||||
|
||||
std::vector<entry> *l = &(focus_list[camera_index]);
|
||||
|
||||
/*
|
||||
* Initialize default focus result.
|
||||
*/
|
||||
|
||||
result r = { d, 0, 1, 0, 0 };
|
||||
|
||||
/*
|
||||
* Check for relevant focus regions.
|
||||
*/
|
||||
|
||||
for (unsigned int n = 0; n < l->size(); n++) {
|
||||
entry *e = &((*l)[n]);
|
||||
|
||||
if (i >= e->start_y
|
||||
&& i <= e->end_y
|
||||
&& j >= e->start_x
|
||||
&& j <= e->end_x
|
||||
&& ((d >= -e->end_depth
|
||||
&& d <= -e->start_depth)
|
||||
|| (isnan(d) && (isnan(e->end_depth)
|
||||
|| isnan(e->start_depth))))) {
|
||||
d2::point focus_origin;
|
||||
ale_pos distance_at_focus_origin;
|
||||
|
||||
if (e->type == 0) {
|
||||
/*
|
||||
* Distance at frame center.
|
||||
*/
|
||||
focus_origin = d2::point(depth->height() / 2, depth->width() / 2);
|
||||
distance_at_focus_origin = -e->distance;
|
||||
} else if (e->type == 1) {
|
||||
/*
|
||||
* Distance at a given point.
|
||||
*/
|
||||
focus_origin = d2::point(e->py, e->px);
|
||||
distance_at_focus_origin = (double) depth->get_bl(d2::point(e->py, e->px))[0];
|
||||
} else {
|
||||
fprintf(stderr, "Bad entry type.\n");
|
||||
assert(0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
r.focal_distance = distance_at_focus_origin + (d2::point(i, j) - focus_origin)
|
||||
.dproduct(d2::point(-e->vertical_gradient,
|
||||
-e->horizontal_gradient));
|
||||
|
||||
/*
|
||||
* Adjust according to focal_range.
|
||||
*/
|
||||
|
||||
ale_pos rel_dist = (double) d - r.focal_distance;
|
||||
|
||||
if (fabs(rel_dist) < e->focal_range / 2) {
|
||||
r.focal_distance = d;
|
||||
} else if (rel_dist > 0) {
|
||||
r.focal_distance += e->focal_range / 2;
|
||||
} else if (rel_dist < 0) {
|
||||
r.focal_distance -= e->focal_range / 2;
|
||||
}
|
||||
|
||||
r.aperture = e->aperture;
|
||||
r.sample_count = e->sample_count;
|
||||
r.statistic = e->focal_statistic;
|
||||
r.randomization = e->sample_randomization;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void set_camera(unsigned int c) {
|
||||
camera_index = c;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
295
d3/point.h
Normal file
295
d3/point.h
Normal file
@@ -0,0 +1,295 @@
|
||||
// Copyright 2002, 2004 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
|
||||
*/
|
||||
|
||||
#ifndef __d3point_h__
|
||||
#define __d3point_h__
|
||||
|
||||
/*
|
||||
* Structure to describe a point in three dimensions.
|
||||
*/
|
||||
class point {
|
||||
private:
|
||||
ale_pos x[3];
|
||||
|
||||
public:
|
||||
point() {
|
||||
x[0] = 0;
|
||||
x[1] = 0;
|
||||
x[2] = 0;
|
||||
}
|
||||
|
||||
point(ale_pos x0, ale_pos x1, ale_pos x2) {
|
||||
x[0] = x0;
|
||||
x[1] = x1;
|
||||
x[2] = x2;
|
||||
}
|
||||
|
||||
point(const point &p) {
|
||||
x[0] = p[0];
|
||||
x[1] = p[1];
|
||||
x[2] = p[2];
|
||||
}
|
||||
|
||||
static point unit(int dimension) {
|
||||
if (dimension == 0)
|
||||
return point(1, 0, 0);
|
||||
if (dimension == 1)
|
||||
return point(0, 1, 0);
|
||||
if (dimension == 2)
|
||||
return point(0, 0, 1);
|
||||
|
||||
assert(0);
|
||||
}
|
||||
|
||||
static point undefined() {
|
||||
double a = 0;
|
||||
|
||||
point p(0, 0, 0);
|
||||
|
||||
return p / a;
|
||||
}
|
||||
|
||||
static point posinf() {
|
||||
double a = +1;
|
||||
double z = +0;
|
||||
|
||||
a = a / z;
|
||||
|
||||
assert (isinf(a) && a > 0);
|
||||
|
||||
return point(a, a, a);
|
||||
}
|
||||
|
||||
static point neginf() {
|
||||
point n = -posinf();
|
||||
|
||||
assert (isinf(n[0]) && n[0] < 0);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void accumulate_max(point p) {
|
||||
for (int d = 0; d < 3; d++)
|
||||
if (p[d] > x[d])
|
||||
x[d] = p[d];
|
||||
}
|
||||
|
||||
void accumulate_min(point p) {
|
||||
for (int d = 0; d < 3; d++)
|
||||
if (p[d] < x[d])
|
||||
x[d] = p[d];
|
||||
}
|
||||
|
||||
int defined() const {
|
||||
return (!isnan(x[0])
|
||||
&& !isnan(x[1])
|
||||
&& !isnan(x[2]));
|
||||
}
|
||||
|
||||
int finite() const {
|
||||
return (::finite(x[0])
|
||||
&& ::finite(x[1])
|
||||
&& ::finite(x[2]));
|
||||
}
|
||||
|
||||
static int defined(const point &p) {
|
||||
return p.defined();
|
||||
}
|
||||
|
||||
/*
|
||||
* Z-values of zero are almost never the right thing to do ...
|
||||
*/
|
||||
point(d2::point p, ale_pos z = 0) {
|
||||
x[0] = p[0];
|
||||
x[1] = p[1];
|
||||
x[2] = z;
|
||||
}
|
||||
|
||||
const ale_pos &operator[](int i) const {
|
||||
assert (i >= 0);
|
||||
assert (i < 3);
|
||||
|
||||
return x[i];
|
||||
}
|
||||
|
||||
ale_pos &operator[](int i) {
|
||||
assert (i >= 0);
|
||||
assert (i < 3);
|
||||
|
||||
return x[i];
|
||||
}
|
||||
|
||||
d2::point xy() const {
|
||||
d2::point result;
|
||||
|
||||
result[0] = x[0];
|
||||
result[1] = x[1];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
point operator+(point p) const {
|
||||
return point(x[0] + p[0], x[1] + p[1], x[2] + p[2]);
|
||||
}
|
||||
|
||||
point operator-(point p) const {
|
||||
return point(x[0] - p[0], x[1] - p[1], x[2] - p[2]);
|
||||
}
|
||||
|
||||
point operator-() const {
|
||||
return point(-x[0], -x[1], -x[2]);
|
||||
}
|
||||
|
||||
point operator/(ale_pos r) const {
|
||||
return point(x[0] / r, x[1] / r, x[2] / r);
|
||||
}
|
||||
|
||||
point operator /=(ale_pos r) {
|
||||
x[0] /= r;
|
||||
x[1] /= r;
|
||||
x[2] /= r;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
point operator *=(ale_pos r) {
|
||||
x[0] *= r;
|
||||
x[1] *= r;
|
||||
x[2] *= r;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
point operator +=(point p) {
|
||||
x[0] += p[0];
|
||||
x[1] += p[1];
|
||||
x[2] += p[2];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
point operator -=(point p) {
|
||||
x[0] -= p[0];
|
||||
x[1] -= p[1];
|
||||
x[2] -= p[2];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
int operator !=(point p) {
|
||||
return (x[0] != p[0]
|
||||
|| x[1] != p[1]
|
||||
|| x[2] != p[2]);
|
||||
}
|
||||
|
||||
point mult(ale_pos d) const {
|
||||
return point(x[0] * d, x[1] * d, x[2] * d);
|
||||
}
|
||||
|
||||
point operator*(point p) const {
|
||||
return point(x[0] * p[0], x[1] * p[1], x[2] * p[2]);
|
||||
}
|
||||
|
||||
ale_pos normsq() const {
|
||||
return x[0] * x[0] + x[1] * x[1] + x[2] * x[2];
|
||||
}
|
||||
|
||||
ale_pos norm() const {
|
||||
return sqrt(normsq());
|
||||
}
|
||||
|
||||
point normalize() const {
|
||||
return operator/(norm());
|
||||
}
|
||||
|
||||
ale_pos lengthtosq(point p) const {
|
||||
point diff = operator-(p);
|
||||
return diff.normsq();
|
||||
}
|
||||
|
||||
ale_pos lengthto(point p) const {
|
||||
return sqrt(lengthtosq(p));
|
||||
}
|
||||
|
||||
ale_pos anglebetw(point p, point q) {
|
||||
/*
|
||||
* by the law of cosines, the cosine is equal to:
|
||||
*
|
||||
* (lengthtosq(p) + lengthtosq(q) - p.lengthtosq(q))
|
||||
* / (2 * lengthto(p) * lengthto(q))
|
||||
*/
|
||||
|
||||
ale_pos to_p = lengthtosq(p);
|
||||
ale_pos to_q = lengthtosq(q);
|
||||
|
||||
ale_pos cos_of = (double) (to_p + to_q - p.lengthtosq(q))
|
||||
/ (double) (2 * sqrt(to_p) * sqrt(to_q));
|
||||
|
||||
/*
|
||||
* XXX: is the fabs() required?
|
||||
*/
|
||||
|
||||
return fabs(acos(cos_of));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Determine the cross product
|
||||
*/
|
||||
point xproduct(point p, point q) {
|
||||
point pp = p;
|
||||
point qq = q;
|
||||
|
||||
pp -= *this;
|
||||
qq -= *this;
|
||||
|
||||
return point(pp[1] * qq[2] - pp[2] * qq[1],
|
||||
pp[2] * qq[0] - pp[0] * qq[2],
|
||||
pp[0] * qq[1] - pp[1] * qq[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the dot product
|
||||
*/
|
||||
ale_pos dproduct(const point &p) {
|
||||
return x[0] * p[0] + x[1] * p[1] + x[2] * p[2];
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether the point is inside a given volume
|
||||
*/
|
||||
int inside(const point &min, const point &max) {
|
||||
for (int d = 0; d < 3; d++) {
|
||||
if (min[d] > x[d])
|
||||
return 0;
|
||||
if (max[d] < x[d])
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
inline point operator*(const point &p, double d) {
|
||||
return p.mult(d);
|
||||
}
|
||||
inline point operator*(double d, const point &p) {
|
||||
return p.mult(d);
|
||||
}
|
||||
#endif
|
||||
545
d3/pt.h
Normal file
545
d3/pt.h
Normal file
@@ -0,0 +1,545 @@
|
||||
// Copyright 2005 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* d3/et.h: Represent 3D->2D projective transformations.
|
||||
*/
|
||||
|
||||
#ifndef __pt_h__
|
||||
#define __pt_h__
|
||||
|
||||
#include "space.h"
|
||||
#include "et.h"
|
||||
|
||||
/*
|
||||
* Structure to describe a 3D->2D projective transformation. 3D information is
|
||||
* preserved by adding a depth element to the result.
|
||||
*
|
||||
* The following coordinate systems are considered:
|
||||
*
|
||||
* P: projective
|
||||
* C: local cartesian
|
||||
* W: world
|
||||
*/
|
||||
|
||||
struct pt {
|
||||
private:
|
||||
d2::transformation t;
|
||||
et euclidean;
|
||||
ale_pos _view_angle;
|
||||
ale_pos scale_factor;
|
||||
mutable ale_pos diag_per_depth;
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
|
||||
pt() : t(d2::transformation::eu_identity()) {
|
||||
_view_angle = M_PI / 4;
|
||||
scale_factor = 1;
|
||||
diag_per_depth = 0;
|
||||
}
|
||||
|
||||
pt(d2::transformation t, et e, ale_pos va, ale_pos sf = 1) : t(t) {
|
||||
this->t = t;
|
||||
euclidean = e;
|
||||
_view_angle = va;
|
||||
scale_factor = sf;
|
||||
diag_per_depth = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Output function
|
||||
*/
|
||||
|
||||
void debug_output() {
|
||||
t.debug_output();
|
||||
euclidean.debug_output();
|
||||
fprintf(stderr, "[pt.do va=%f sf=%f dpd=%f\n]",
|
||||
(double) _view_angle, (double) scale_factor, (double) diag_per_depth);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get euclidean transformation reference.
|
||||
*/
|
||||
|
||||
et &e() {
|
||||
return euclidean;
|
||||
}
|
||||
|
||||
/*
|
||||
* Modify scale factor
|
||||
*/
|
||||
void scale(ale_pos sf) {
|
||||
scale_factor = sf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Modify or get view angle
|
||||
*/
|
||||
void view_angle(ale_pos va) {
|
||||
diag_per_depth = 0;
|
||||
_view_angle = va;
|
||||
}
|
||||
|
||||
ale_pos view_angle() {
|
||||
return _view_angle;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the 2D scale factor
|
||||
*/
|
||||
ale_pos scale_2d() const {
|
||||
return t.scale();
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform W to C.
|
||||
*/
|
||||
point wc(point p) const {
|
||||
return euclidean(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform C to P for given width and height.
|
||||
*/
|
||||
point cp_generic(point p, ale_pos w, ale_pos h) const {
|
||||
/*
|
||||
* Divide x and y by negative z
|
||||
*/
|
||||
|
||||
p[0] /= -p[2];
|
||||
p[1] /= -p[2];
|
||||
|
||||
/*
|
||||
* Scale x and y
|
||||
*/
|
||||
|
||||
ale_pos scaling_factor = (ale_pos) sqrt(w*w + h*h)
|
||||
/ (ale_pos) (2 * tan(_view_angle / 2));
|
||||
p[0] *= scaling_factor;
|
||||
p[1] *= scaling_factor;
|
||||
|
||||
/*
|
||||
* Add an offset so that the upper-left corner is the origin.
|
||||
*/
|
||||
|
||||
p[0] += h / 2;
|
||||
p[1] += w / 2;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform point p.
|
||||
*/
|
||||
struct point wp_generic(struct point p, ale_pos w, ale_pos h) const {
|
||||
return cp_generic(wc(p), w, h);
|
||||
}
|
||||
|
||||
/*
|
||||
* Width and height
|
||||
*/
|
||||
|
||||
ale_pos scaled_width() const {
|
||||
return t.scaled_width() * scale_factor;
|
||||
}
|
||||
|
||||
ale_pos scaled_height() const {
|
||||
return t.scaled_height() * scale_factor;
|
||||
}
|
||||
|
||||
int scaled_in_bounds(point p) const {
|
||||
return (p[0] >= 0 && p[0] <= scaled_height() - 1
|
||||
&& p[1] >= 0 && p[1] <= scaled_width() - 1);
|
||||
}
|
||||
|
||||
int unscaled_in_bounds(point p) const {
|
||||
return (p[0] >= 0 && p[0] <= unscaled_height() - 1
|
||||
&& p[1] >= 0 && p[1] <= unscaled_width() - 1);
|
||||
}
|
||||
|
||||
ale_pos unscaled_width() const {
|
||||
return t.unscaled_width() * scale_factor;
|
||||
}
|
||||
|
||||
ale_pos unscaled_height() const {
|
||||
return t.unscaled_height() * scale_factor;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scaled transforms
|
||||
*/
|
||||
|
||||
point cp_scaled(point p) const {
|
||||
return cp_generic(p, scaled_width(), scaled_height());
|
||||
}
|
||||
|
||||
point wp_scaled(point p) const {
|
||||
return wp_generic(p, scaled_width(), scaled_height());
|
||||
}
|
||||
|
||||
/*
|
||||
* Unscaled transforms
|
||||
*/
|
||||
|
||||
point cp_unscaled(point p) const {
|
||||
return cp_generic(p, unscaled_width(), unscaled_height());
|
||||
}
|
||||
|
||||
point wp_unscaled(point p) const {
|
||||
return wp_generic(p, unscaled_width(), unscaled_height());
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform P to C.
|
||||
*/
|
||||
point pc_generic(point p, ale_pos w, ale_pos h) const {
|
||||
/*
|
||||
* Subtract offset
|
||||
*/
|
||||
|
||||
p[0] -= h / 2;
|
||||
p[1] -= w / 2;
|
||||
|
||||
/*
|
||||
* Scale x and y
|
||||
*/
|
||||
|
||||
ale_pos scaling_factor = (ale_pos) sqrt(w*w + h*h)
|
||||
/ (ale_pos) (2 * tan(_view_angle / 2));
|
||||
p[0] /= scaling_factor;
|
||||
p[1] /= scaling_factor;
|
||||
|
||||
/*
|
||||
* Multiply x and y by negative z
|
||||
*/
|
||||
|
||||
p[0] *= -p[2];
|
||||
p[1] *= -p[2];
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform C to W
|
||||
*/
|
||||
point cw(point p) const {
|
||||
return euclidean.inverse_transform(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform P to W
|
||||
*/
|
||||
point pw_generic(point p, ale_pos w, ale_pos h) const {
|
||||
return cw(pc_generic(p, w, h));
|
||||
}
|
||||
|
||||
/*
|
||||
* Inverse transforms for scaled points.
|
||||
*/
|
||||
|
||||
point pc_scaled(point p) const {
|
||||
return pc_generic(p, scaled_width(), scaled_height());
|
||||
}
|
||||
|
||||
point pw_scaled(point p) const {
|
||||
return pw_generic(p, scaled_width(), scaled_height());
|
||||
}
|
||||
|
||||
/*
|
||||
* Inverse transforms for unscaled points.
|
||||
*/
|
||||
|
||||
point pc_unscaled(point p) const {
|
||||
return pc_generic(p, unscaled_width(), unscaled_height());
|
||||
}
|
||||
|
||||
point pw_unscaled(point p) const {
|
||||
return pw_generic(p, unscaled_width(), unscaled_height());
|
||||
}
|
||||
|
||||
/*
|
||||
* Density calculation
|
||||
*/
|
||||
|
||||
ale_pos c_density_scaled(point p) const {
|
||||
ale_pos one_density = 1 / (pc_scaled(point(0, 0, -1)).lengthto(pc_scaled(point(0, 1, -1)))
|
||||
* pc_scaled(point(0, 0, -1)).lengthto(pc_scaled(point(1, 0, -1))));
|
||||
|
||||
return one_density / (p[2] * p[2]);
|
||||
}
|
||||
|
||||
ale_pos w_density_scaled(point p) const {
|
||||
return c_density_scaled(wc(p));
|
||||
}
|
||||
|
||||
ale_pos w_density_scaled_max(point w0, point w1, point w2) {
|
||||
point c0 = wc(w0);
|
||||
point c1 = wc(w1);
|
||||
point c2 = wc(w2);
|
||||
|
||||
/*
|
||||
* Select the point closest to the camera.
|
||||
*/
|
||||
|
||||
if (c0[2] > c1[2] && c0[2] > c2[2])
|
||||
return c_density_scaled(c0);
|
||||
else if (c1[2] > c2[2])
|
||||
return c_density_scaled(c1);
|
||||
else
|
||||
return c_density_scaled(c2);
|
||||
}
|
||||
|
||||
private:
|
||||
void calculate_diag_per_depth() const {
|
||||
if (diag_per_depth != 0)
|
||||
return;
|
||||
ale_pos w = unscaled_width();
|
||||
ale_pos h = unscaled_height();
|
||||
|
||||
diag_per_depth = sqrt(2) * (2 * tan(_view_angle / 2)) / sqrt(w*w + h*h);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
* Get a trilinear coordinate for a given depth.
|
||||
*/
|
||||
ale_pos trilinear_coordinate(ale_pos depth, ale_pos diagonal) {
|
||||
calculate_diag_per_depth();
|
||||
|
||||
return log(diagonal / (fabs(depth) * diag_per_depth)) / log(2);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a trilinear coordinate for a given position in the world and
|
||||
* a given 2D diagonal distance.
|
||||
*/
|
||||
ale_pos trilinear_coordinate(point w, ale_pos diagonal) {
|
||||
return trilinear_coordinate(wc(w)[2], diagonal);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a trilinear coordinate for a given subspace.
|
||||
*/
|
||||
ale_pos trilinear_coordinate(const space::traverse &st) {
|
||||
point min = st.get_min();
|
||||
point max = st.get_max();
|
||||
point avg = (min + max) / (ale_pos) 2;
|
||||
|
||||
ale_pos diagonal = min.lengthto(max) * (ale_pos) (sqrt(2) / sqrt(3));
|
||||
|
||||
return trilinear_coordinate(avg, diagonal);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a diagonal distance for a given position in the world
|
||||
* and a given trilinear coordinate.
|
||||
*/
|
||||
ale_pos diagonal_distance(point w, ale_pos coordinate) const {
|
||||
calculate_diag_per_depth();
|
||||
|
||||
ale_pos depth = fabs(wc(w)[2]);
|
||||
ale_pos diagonal = pow(2, coordinate) * depth * diag_per_depth;
|
||||
|
||||
return diagonal;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the 3D diagonal for a given depth and trilinear coordinate.
|
||||
*/
|
||||
ale_pos diagonal_distance_3d(ale_pos depth, ale_pos coordinate) const {
|
||||
calculate_diag_per_depth();
|
||||
return pow(2, coordinate) * fabs(depth) * diag_per_depth * (ale_pos) (sqrt(3) / sqrt(2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the 1D distance for a given depth and trilinear coordinate.
|
||||
*/
|
||||
ale_pos distance_1d(ale_pos depth, ale_pos coordinate) const {
|
||||
calculate_diag_per_depth();
|
||||
return pow(2, coordinate) * fabs(depth) * diag_per_depth / (ale_pos) (sqrt(2));
|
||||
}
|
||||
|
||||
ale_pos distance_1d(point iw, ale_pos coordinate) const {
|
||||
if (wc(iw)[2] >= 0)
|
||||
return point::undefined()[0];
|
||||
return distance_1d(-wc(iw)[2], coordinate);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for inclusion of a point in the bounding box of projected
|
||||
* vertices. This function returns non-zero when a point is included,
|
||||
* when one of the vertices is infinite or undefined, or when a vertex
|
||||
* is behind the point of projection.
|
||||
*
|
||||
* WBB is assumed to contain {volume_min, volume_max}.
|
||||
*/
|
||||
|
||||
int check_inclusion(const point *wbb, const d2::point &pc_min, const d2::point &pc_max, int scaled) const {
|
||||
|
||||
assert(pc_min[0] <= pc_max[0]);
|
||||
assert(pc_min[1] <= pc_max[1]);
|
||||
|
||||
int test[2][2] = {{0, 0}, {0, 0}};
|
||||
|
||||
for (int x = 0; x < 2; x++)
|
||||
for (int y = 0; y < 2; y++)
|
||||
for (int z = 0; z < 2; z++) {
|
||||
|
||||
point p = scaled ? wp_scaled(point(wbb[x][0], wbb[y][1], wbb[z][2]))
|
||||
: wp_unscaled(point(wbb[x][0], wbb[y][1], wbb[z][2]));
|
||||
|
||||
if (!p.finite())
|
||||
return 1;
|
||||
|
||||
if (p[2] > 0)
|
||||
return 1;
|
||||
|
||||
for (int d = 0; d < 2; d++) {
|
||||
if (p[d] <= pc_max[d])
|
||||
test[d][0] = 1;
|
||||
if (p[d] >= pc_min[d])
|
||||
test[d][1] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (int d = 0; d < 2; d++)
|
||||
for (int c = 0; c < 2; c++)
|
||||
if (test[d][c] == 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int check_inclusion_scaled(const point *wbb, d2::point pc_min, d2::point pc_max) const {
|
||||
return check_inclusion(wbb, pc_min, pc_max, 1);
|
||||
}
|
||||
|
||||
int check_inclusion_scaled(const space::traverse &st, d2::point pc_min, d2::point pc_max) const {
|
||||
return check_inclusion_scaled(st.get_bounds(), pc_min, pc_max);
|
||||
}
|
||||
|
||||
int check_inclusion_scaled(const space::traverse &st, d2::point pc) {
|
||||
return check_inclusion_scaled(st, pc, pc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get bounding box for projection of a subspace.
|
||||
*/
|
||||
|
||||
void get_view_local_bb(point volume_min, point volume_max, point bb[2], int scaled) const {
|
||||
|
||||
point min = point::posinf();
|
||||
point max = point::neginf();
|
||||
|
||||
point wbb[2] = { volume_min, volume_max };
|
||||
|
||||
for (int x = 0; x < 2; x++)
|
||||
for (int y = 0; y < 2; y++)
|
||||
for (int z = 0; z < 2; z++) {
|
||||
point p = scaled ? wp_scaled(point(wbb[x][0], wbb[y][1], wbb[z][2]))
|
||||
: wp_unscaled(point(wbb[x][0], wbb[y][1], wbb[z][2]));
|
||||
|
||||
for (int d = 0; d < 3; d++) {
|
||||
if (p[d] < min[d])
|
||||
min[d] = p[d];
|
||||
if (p[d] > max[d])
|
||||
max[d] = p[d];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Clip bounding box to image extents.
|
||||
*/
|
||||
|
||||
if (min[0] < 0)
|
||||
min[0] = 0;
|
||||
if (min[1] < 0)
|
||||
min[1] = 0;
|
||||
if (max[0] > scaled_height() - 1)
|
||||
max[0] = scaled_height() - 1;
|
||||
if (max[1] > scaled_width() - 1)
|
||||
max[1] = scaled_width() - 1;
|
||||
|
||||
bb[0] = min;
|
||||
bb[1] = max;
|
||||
}
|
||||
|
||||
void get_view_local_bb_unscaled(point volume_min, point volume_max, point bb[2]) const {
|
||||
get_view_local_bb(volume_min, volume_max, bb, 0);
|
||||
}
|
||||
|
||||
void get_view_local_bb_scaled(point volume_min, point volume_max, point bb[2]) const {
|
||||
get_view_local_bb(volume_min, volume_max, bb, 1);
|
||||
}
|
||||
|
||||
void get_view_local_bb_scaled(const space::traverse &st, point bb[2]) const {
|
||||
get_view_local_bb_scaled(st.get_min(), st.get_max(), bb);
|
||||
}
|
||||
|
||||
void get_view_local_bb_unscaled(const space::traverse &t, point bb[2]) const {
|
||||
get_view_local_bb_unscaled(t.get_min(), t.get_max(), bb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the in-bounds centroid for a subspace, if one exists.
|
||||
*/
|
||||
|
||||
point centroid(point volume_min, point volume_max) const {
|
||||
|
||||
point bb[2];
|
||||
|
||||
get_view_local_bb_unscaled(volume_min, volume_max, bb);
|
||||
|
||||
point min = bb[0];
|
||||
point max = bb[1];
|
||||
|
||||
for (int d = 0; d < 2; d++)
|
||||
if (min[d] > max[d])
|
||||
return point::undefined();
|
||||
|
||||
if (min[2] >= 0)
|
||||
return point::undefined();
|
||||
|
||||
if (max[2] > 0)
|
||||
max[2] = 0;
|
||||
|
||||
return (max + min) / 2;
|
||||
}
|
||||
|
||||
point centroid(const space::traverse &t) {
|
||||
return centroid(t.get_min(), t.get_max());
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the local space origin in world space.
|
||||
*/
|
||||
|
||||
point origin() {
|
||||
return cw(point(0, 0, 0));
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
51
d3/render.h
Normal file
51
d3/render.h
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright 2004 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* render.h: A superclass for all rendering classes.
|
||||
*/
|
||||
|
||||
#ifndef __3drender_h__
|
||||
#define __3drender_h__
|
||||
|
||||
#include "point.h"
|
||||
|
||||
/*
|
||||
* Class render accepts descriptions of scenes. Subclasses may produce various
|
||||
* types of output.
|
||||
*/
|
||||
|
||||
class render {
|
||||
public:
|
||||
|
||||
/*
|
||||
* Describe a sphere at position p with radius r. Non-negative 'frame'
|
||||
* less than the total number of frames indicates that the position is
|
||||
* specified in the local space of that frame number. Otherwise, the
|
||||
* position is specified in world coordinates.
|
||||
*/
|
||||
|
||||
virtual void describe(int frame, point p, ale_real r) = 0;
|
||||
|
||||
virtual ~render() {
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
81
d3/scene.cc
Normal file
81
d3/scene.cc
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright 2003, 2004, 2005 David Hilvert <dhilvert@gmail.com>,
|
||||
// <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
|
||||
*/
|
||||
|
||||
#include "scene.h"
|
||||
|
||||
/*
|
||||
* See scene.h for details on these variables.
|
||||
*/
|
||||
|
||||
scene::lod_images *scene::al;
|
||||
ale_pos scene::front_clip = 0;
|
||||
int scene::input_decimation_lower = 0;
|
||||
int scene::output_decimation_preferred = 0;
|
||||
int scene::primary_decimation_upper = 0;
|
||||
int scene::output_clip = 0;
|
||||
ale_pos scene::rear_clip = 0;
|
||||
const char *scene::load_model_name = NULL;
|
||||
const char *scene::save_model_name = NULL;
|
||||
const ale_real scene::nearness = 0.01;
|
||||
|
||||
scene::spatial_info_map_t scene::spatial_info_map;
|
||||
|
||||
// scene::spatial_info *scene::tracked_space = NULL;
|
||||
|
||||
unsigned long scene::total_ambiguity = 0;
|
||||
unsigned long scene::total_pixels = 0;
|
||||
unsigned long scene::total_divisions = 0;
|
||||
unsigned long scene::total_tsteps = 0;
|
||||
|
||||
double scene::occ_att = 0.50;
|
||||
|
||||
int scene::normalize_weights = 1;
|
||||
int scene::use_filter = 1;
|
||||
const char *scene::d3chain_type = "";
|
||||
|
||||
ale_real scene::falloff_exponent = 1;
|
||||
double scene::tc_multiplier = 0;
|
||||
unsigned int scene::ou_iterations = 10;
|
||||
unsigned int scene::pairwise_ambiguity = 3;
|
||||
const char *scene::pairwise_comparisons = "auto";
|
||||
int scene::d3px_count;
|
||||
double *scene::d3px_parameters;
|
||||
double scene::encounter_threshold = 0;
|
||||
double scene::depth_median_radius = 0;
|
||||
double scene::diff_median_radius = 0;
|
||||
int scene::subspace_traverse = 0;
|
||||
|
||||
/*
|
||||
* Precision discriminator
|
||||
*
|
||||
* For some reason, colors that should be identical are calculated differently
|
||||
* along different computational pathways, either due to a compiler idiosyncrasy,
|
||||
* or due to an as-of-yet undiscovered bug in the code. We use the following
|
||||
* constant in an effort to winnow out these discrepancies, which can sometimes
|
||||
* cause cycles in the adjustment preference function.
|
||||
*/
|
||||
|
||||
#define DISCRIMINATOR 1e-5
|
||||
|
||||
/*
|
||||
* Functions.
|
||||
*/
|
||||
|
||||
4933
d3/scene.h
Normal file
4933
d3/scene.h
Normal file
File diff suppressed because it is too large
Load Diff
28
d3/space.cc
Normal file
28
d3/space.cc
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2003, 2004, 2005 David Hilvert <dhilvert@gmail.com>,
|
||||
// <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
|
||||
*/
|
||||
|
||||
#include "space.h"
|
||||
|
||||
/*
|
||||
* See space.h for details on these variables.
|
||||
*/
|
||||
|
||||
space::node *space::root_node = NULL;
|
||||
333
d3/space.h
Normal file
333
d3/space.h
Normal file
@@ -0,0 +1,333 @@
|
||||
// Copyright 2003, 2004, 2005 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* d3/space.h: Representation of 3D space.
|
||||
*/
|
||||
|
||||
#ifndef __space_h__
|
||||
#define __space_h__
|
||||
|
||||
#include "point.h"
|
||||
|
||||
class space {
|
||||
public:
|
||||
|
||||
/*
|
||||
* Structure to hold a subdivisible region of space.
|
||||
*/
|
||||
struct node {
|
||||
struct node *positive;
|
||||
struct node *negative;
|
||||
|
||||
node() {
|
||||
positive = NULL;
|
||||
negative = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
/*
|
||||
* Space root pointer
|
||||
*/
|
||||
static node *root_node;
|
||||
|
||||
public:
|
||||
|
||||
static void init_root() {
|
||||
root_node = new node;
|
||||
}
|
||||
|
||||
/*
|
||||
* Space traversal and navigation class.
|
||||
*/
|
||||
|
||||
class traverse {
|
||||
node *current;
|
||||
point bounds[2];
|
||||
|
||||
public:
|
||||
|
||||
static int get_next_split(point min, point max) {
|
||||
assert(min[0] < max[0]);
|
||||
assert(min[1] < max[1]);
|
||||
assert(min[2] < max[2]);
|
||||
|
||||
/*
|
||||
* Double-infinite case.
|
||||
*/
|
||||
|
||||
for (int d = 0; d < 3; d++)
|
||||
if (isinf(max[d]) && isinf(min[d]))
|
||||
return d;
|
||||
|
||||
/*
|
||||
* Finite or single-infinite case
|
||||
*/
|
||||
|
||||
if (max[0] - min[0] >= max[1] - min[1]
|
||||
&& (max[0] >= max[1] || !isinf(min[1]))
|
||||
&& (min[0] <= min[1] || !isinf(max[1]))
|
||||
&& max[0] - min[0] >= max[2] - min[2]
|
||||
&& (max[0] >= max[2] || !isinf(min[2]))
|
||||
&& (min[0] <= min[2] || !isinf(max[2])))
|
||||
return 0;
|
||||
|
||||
if (max[1] - min[1] > max[2] - min[2]
|
||||
&& (max[1] >= max[2] || !isinf(min[2]))
|
||||
&& (min[1] <= min[2] || !isinf(max[2])))
|
||||
return 1;
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
static ale_pos split_coordinate(int d, point min, point max) {
|
||||
if (isinf(max[d]) && isinf(min[d]))
|
||||
return 0;
|
||||
|
||||
if (isinf(max[d]))
|
||||
return tan((atan(min[d]) + M_PI/2) / 2);
|
||||
|
||||
if (isinf(min[d]))
|
||||
return tan((atan(max[d]) - M_PI/2) / 2);
|
||||
|
||||
return (min[d] + max[d]) / 2;
|
||||
}
|
||||
|
||||
static int get_next_cells(int d, point min, point max, point cells[2][2]) {
|
||||
cells[0][0] = min;
|
||||
cells[0][1] = max;
|
||||
cells[1][0] = min;
|
||||
cells[1][1] = max;
|
||||
|
||||
ale_pos split_point = split_coordinate(d, min, max);
|
||||
|
||||
if (split_point == min[d]
|
||||
|| split_point == max[d]
|
||||
|| !finite(split_point))
|
||||
return 0;
|
||||
|
||||
cells[0][1][d] = split_point;
|
||||
cells[1][0][d] = split_point;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_next_split() {
|
||||
return get_next_split(bounds[0], bounds[1]);
|
||||
}
|
||||
|
||||
ale_pos split_coordinate(int d) {
|
||||
return split_coordinate(d, bounds[0], bounds[1]);
|
||||
}
|
||||
|
||||
ale_pos split_coordinate() {
|
||||
int next_split = get_next_split();
|
||||
return split_coordinate(next_split);
|
||||
}
|
||||
|
||||
static traverse root() {
|
||||
|
||||
traverse result;
|
||||
|
||||
result.current = root_node;
|
||||
result.bounds[0] = point::neginf();
|
||||
result.bounds[1] = point::posinf();
|
||||
|
||||
assert(result.current);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int precision_wall() {
|
||||
int next_split = get_next_split();
|
||||
ale_pos split_point = split_coordinate(next_split);
|
||||
|
||||
point &min = bounds[0];
|
||||
point &max = bounds[1];
|
||||
|
||||
assert(split_point <= max[next_split]);
|
||||
assert(split_point >= min[next_split]);
|
||||
|
||||
if (split_point == min[next_split] || split_point == max[next_split])
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
traverse positive() {
|
||||
|
||||
assert(current);
|
||||
|
||||
int next_split = get_next_split();
|
||||
|
||||
if (current->positive == NULL) {
|
||||
current->positive = new node;
|
||||
}
|
||||
|
||||
traverse result;
|
||||
|
||||
result.current = current->positive;
|
||||
result.bounds[0] = bounds[0];
|
||||
result.bounds[1] = bounds[1];
|
||||
|
||||
result.bounds[0][next_split] = split_coordinate(next_split);
|
||||
|
||||
assert(result.current);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
traverse negative() {
|
||||
|
||||
assert(current);
|
||||
|
||||
int next_split = get_next_split();
|
||||
|
||||
if (current->negative == NULL) {
|
||||
current->negative = new node;
|
||||
}
|
||||
|
||||
traverse result;
|
||||
|
||||
result.current = current->negative;
|
||||
result.bounds[0] = bounds[0];
|
||||
result.bounds[1] = bounds[1];
|
||||
|
||||
result.bounds[1][next_split] = split_coordinate(next_split);
|
||||
|
||||
assert(result.current);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
point get_min() const {
|
||||
return bounds[0];
|
||||
}
|
||||
|
||||
point get_max() const {
|
||||
return bounds[1];
|
||||
}
|
||||
|
||||
const point *get_bounds() const {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
point get_centroid() const {
|
||||
return (bounds[0] + bounds[1]) / 2;
|
||||
}
|
||||
|
||||
int includes(point p) {
|
||||
|
||||
for (int d = 0; d < 3; d++) {
|
||||
if (p[d] > bounds[1][d])
|
||||
return 0;
|
||||
if (p[d] < bounds[0][d])
|
||||
return 0;
|
||||
if (isnan(p[d]))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
node *get_node() {
|
||||
assert(current);
|
||||
return current;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Class to iterate through subspaces based on proximity to a camera.
|
||||
*/
|
||||
|
||||
class iterate {
|
||||
std::stack<traverse> node_stack;
|
||||
point camera_origin;
|
||||
|
||||
public:
|
||||
iterate(point co, traverse top = traverse::root()) {
|
||||
camera_origin = co;
|
||||
node_stack.push(top);
|
||||
}
|
||||
|
||||
int next() {
|
||||
if (node_stack.empty())
|
||||
return 0;
|
||||
|
||||
traverse st = node_stack.top();
|
||||
|
||||
int d = st.get_next_split();
|
||||
|
||||
ale_pos split_coordinate = st.split_coordinate();
|
||||
|
||||
node *n = st.get_node()->negative;
|
||||
node *p = st.get_node()->positive;
|
||||
|
||||
if (camera_origin[d] > split_coordinate) {
|
||||
if (n) {
|
||||
node_stack.top() = st.negative();
|
||||
if (p)
|
||||
node_stack.push(st.positive());
|
||||
} else {
|
||||
if (p)
|
||||
node_stack.top() = st.positive();
|
||||
else
|
||||
node_stack.pop();
|
||||
}
|
||||
} else {
|
||||
if (p) {
|
||||
node_stack.top() = st.positive();
|
||||
if (n)
|
||||
node_stack.push(st.negative());
|
||||
} else {
|
||||
if (n)
|
||||
node_stack.top() = st.negative();
|
||||
else
|
||||
node_stack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
return (!node_stack.empty());
|
||||
}
|
||||
|
||||
iterate cleave() {
|
||||
assert (!node_stack.empty());
|
||||
|
||||
iterate result(camera_origin, node_stack.top());
|
||||
|
||||
node_stack.pop();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int done() {
|
||||
return node_stack.empty();
|
||||
}
|
||||
|
||||
traverse get() {
|
||||
assert (!node_stack.empty());
|
||||
return node_stack.top();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
28
d3/tfile.cc
Normal file
28
d3/tfile.cc
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2002 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
|
||||
*/
|
||||
|
||||
#include "tfile.h"
|
||||
|
||||
/*
|
||||
* See tfile.h for details on these variables.
|
||||
*/
|
||||
|
||||
int tfile_input_version = 0;
|
||||
int tfile_output_version = 0;
|
||||
584
d3/tfile.h
Normal file
584
d3/tfile.h
Normal file
@@ -0,0 +1,584 @@
|
||||
// Copyright 2002, 2003, 2005 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* d3/tfile.h: Read and write 3D transformation data files.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This version of ALE reads and writes version 0 3D transformation data files.
|
||||
*/
|
||||
|
||||
#ifndef __d3tfile_h__
|
||||
#define __d3tfile_h__
|
||||
|
||||
#include "pt.h"
|
||||
|
||||
#define D3_TFILE_VERSION 0
|
||||
#define D3_TFILE_VERSION_MAX 0
|
||||
|
||||
extern int tfile_input_version;
|
||||
extern int tfile_output_version;
|
||||
|
||||
/*
|
||||
* Structure to describe a transformation data file to load data from.
|
||||
*/
|
||||
|
||||
struct tload_t {
|
||||
const char *filename;
|
||||
FILE *file;
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure to describe a transformation data file to write data to.
|
||||
*/
|
||||
|
||||
struct tsave_t {
|
||||
const char *filename;
|
||||
const char *target;
|
||||
const char *orig;
|
||||
FILE *file;
|
||||
};
|
||||
|
||||
/*
|
||||
* Create a new tload_t transformation data file structure, used for
|
||||
* reading data from transformation data files.
|
||||
*/
|
||||
|
||||
static inline struct tload_t *tload_new(const char *filename) {
|
||||
FILE *file = fopen (filename, "r");
|
||||
struct tload_t *result = NULL;
|
||||
|
||||
if (!file) {
|
||||
fprintf(stderr, "tload: Error: could not open transformation data file '%s'.", filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
result = (struct tload_t *)
|
||||
malloc(sizeof(struct tload_t));
|
||||
result->filename = filename;
|
||||
result->file = file;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load the first transformation from a transformation data file associated with
|
||||
* transformation data file structure T, or return the default transformation
|
||||
* if no transformation is available.
|
||||
*
|
||||
* T is a pointer to the tload_t transformation data file structure.
|
||||
*
|
||||
* DEFAULT_TRANSFORM is the default transformation result.
|
||||
*
|
||||
* IS_DEFAULT is used to signal a non-default transformation result.
|
||||
*/
|
||||
|
||||
static inline pt tload_first(struct tload_t *t,
|
||||
pt default_transform, int *is_default) {
|
||||
|
||||
pt result = default_transform;
|
||||
|
||||
*is_default = 1;
|
||||
|
||||
/*
|
||||
* If there is no file, return the default.
|
||||
*/
|
||||
|
||||
if (t == NULL)
|
||||
return result;
|
||||
|
||||
/*
|
||||
* Search through the initial part of the file to determine
|
||||
* its version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Skip comments
|
||||
*/
|
||||
|
||||
int first_character;
|
||||
|
||||
first_character = fgetc(t->file);
|
||||
|
||||
while (first_character == ' '
|
||||
|| first_character == 0xa
|
||||
|| first_character == 0xd
|
||||
|| first_character == '\t'
|
||||
|| first_character == '#') {
|
||||
ungetc(first_character, t->file);
|
||||
char line[1024];
|
||||
fgets(line, 1024, t->file);
|
||||
if (strlen(line) >= 1023) {
|
||||
fprintf(stderr,
|
||||
"\n3d-trans-load: Error: line too long in input file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
first_character = fgetc(t->file);
|
||||
}
|
||||
|
||||
if (first_character != EOF)
|
||||
ungetc(first_character, t->file);
|
||||
|
||||
if (first_character != 'W') {
|
||||
fprintf(stderr, "\n3d-trans-load: First command must be a version number.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtain version from version command string.
|
||||
*/
|
||||
|
||||
char line[1024];
|
||||
fgets(line, 1024, t->file);
|
||||
if (strlen(line) >= 1023) {
|
||||
fprintf(stderr,
|
||||
"\n3d-trans-load: Error: line too long in input file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int count = sscanf(line, "W %d", &tfile_input_version);
|
||||
|
||||
if (count < 1) {
|
||||
fprintf(stderr, "Error in 3d transformation "
|
||||
"file version command.\n");
|
||||
exit(1);
|
||||
} else if (tfile_input_version > D3_TFILE_VERSION_MAX) {
|
||||
fprintf(stderr, "Unsupported 3D transformation "
|
||||
"file version %d\n",
|
||||
tfile_input_version);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read each line of the file until we find a transformation
|
||||
* or EOF.
|
||||
*/
|
||||
|
||||
while (!feof(t->file)) {
|
||||
char line[1024];
|
||||
|
||||
fgets(line, 1024, t->file);
|
||||
|
||||
if (feof(t->file))
|
||||
return result;
|
||||
|
||||
if (strlen(line) >= 1023) {
|
||||
fprintf(stderr,
|
||||
"\ntrans-load: Error: line too long in input file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const double rtod_multiplier = 180 / M_PI;
|
||||
|
||||
switch (line[0]) {
|
||||
case ' ':
|
||||
case 0xa:
|
||||
case 0xd:
|
||||
case '\t':
|
||||
case '#':
|
||||
/* Comment or whitespace */
|
||||
break;
|
||||
case 'D':
|
||||
case 'd':
|
||||
/* Default transformation */
|
||||
return result;
|
||||
case 'V':
|
||||
case 'v':
|
||||
unsigned int count;
|
||||
double view_angle;
|
||||
|
||||
count = sscanf(line, "V %lf", &view_angle);
|
||||
|
||||
if (count < 1) {
|
||||
fprintf(stderr, "\n3d-trans-load: Error: "
|
||||
"Malformed 'V' command.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
result.view_angle(view_angle / rtod_multiplier);
|
||||
|
||||
break;
|
||||
case 'E':
|
||||
case 'e':
|
||||
/* Euclidean transformation data */
|
||||
*is_default = 0;
|
||||
{
|
||||
double width, height;
|
||||
double values[6] = {0, 0, -1, 0, 0, 0};
|
||||
int count;
|
||||
|
||||
count = sscanf(line, "E %lf%lf%lf%lf%lf%lf%lf%lf",
|
||||
&width, &height,
|
||||
&values[1], &values[0], &values[2],
|
||||
&values[4], &values[3], &values[5]);
|
||||
|
||||
if (count < 8)
|
||||
fprintf(stderr, "\n3d-trans-load: warning: "
|
||||
"Missing args for 'E'\n");
|
||||
|
||||
if (width != result.scaled_width()
|
||||
|| height != result.scaled_height()) {
|
||||
fprintf(stderr, "\n3d-trans-load: Error: "
|
||||
"Scaled image width and/or height mismatch.");
|
||||
}
|
||||
|
||||
for (int i = 3; i < 6; i++) {
|
||||
values [i] /= rtod_multiplier;
|
||||
}
|
||||
|
||||
result.e().set(values);
|
||||
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"\ntrans-load: Error in tload_first: unrecognized command '%s'\n",
|
||||
line);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* EOF reached: return default transformation.
|
||||
*/
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load the next transformation from a transformation data file associated with
|
||||
* transformation data file structure T, or return the default transformation
|
||||
* if no transformation is available.
|
||||
*
|
||||
* T is a pointer to the tload_t transformation data file structure.
|
||||
*
|
||||
* IS_P is nonzero if a projective transformation is expected.
|
||||
*
|
||||
* DEFAULT_TRANSFORM is the default transformation result.
|
||||
*
|
||||
* IS_DEFAULT is used to signal a non-default transformation result.
|
||||
*/
|
||||
|
||||
static inline pt tload_next(struct tload_t *t,
|
||||
pt default_transform, int *is_default) {
|
||||
|
||||
pt result = default_transform;
|
||||
|
||||
*is_default = 1;
|
||||
|
||||
/*
|
||||
* Read each line of the file until we find a transformation.
|
||||
*/
|
||||
|
||||
while (t && !feof(t->file)) {
|
||||
char line[1024];
|
||||
|
||||
fgets(line, 1024, t->file);
|
||||
|
||||
if (feof(t->file))
|
||||
return result;
|
||||
|
||||
if (strlen(line) >= 1023) {
|
||||
fprintf(stderr,
|
||||
"\ntrans-load: warning: line too long in input file\n");
|
||||
}
|
||||
|
||||
const double rtod_multiplier = 180 / M_PI;
|
||||
|
||||
switch (line[0]) {
|
||||
case ' ':
|
||||
case 0xa:
|
||||
case 0xd:
|
||||
case '\t':
|
||||
case '#':
|
||||
/* Comment or whitespace */
|
||||
break;
|
||||
case 'D':
|
||||
case 'd':
|
||||
/* Default transformation */
|
||||
return result;
|
||||
case 'V':
|
||||
case 'v':
|
||||
unsigned int count;
|
||||
double view_angle;
|
||||
|
||||
count = sscanf(line, "V %lf", &view_angle);
|
||||
|
||||
if (count < 1) {
|
||||
fprintf(stderr, "\n3d-trans-load: Error: "
|
||||
"Malformed 'V' command.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
result.view_angle(view_angle / rtod_multiplier);
|
||||
|
||||
break;
|
||||
case 'E':
|
||||
case 'e':
|
||||
/* Euclidean transformation data */
|
||||
*is_default = 0;
|
||||
{
|
||||
double width, height;
|
||||
double values[6] = {0, 0, -1, 0, 0, 0};
|
||||
int count;
|
||||
|
||||
count = sscanf(line, "E %lf%lf%lf%lf%lf%lf%lf%lf",
|
||||
&width, &height,
|
||||
&values[1], &values[0], &values[2],
|
||||
&values[4], &values[3], &values[5]);
|
||||
|
||||
if (count < 8)
|
||||
fprintf(stderr, "\n3d-trans-load: warning: "
|
||||
"Missing args for 'E'\n");
|
||||
|
||||
if (width != result.scaled_width()
|
||||
|| height != result.scaled_height()) {
|
||||
fprintf(stderr, "\n3d-trans-load: Error: "
|
||||
"Scaled image width and/or height mismatch.");
|
||||
}
|
||||
|
||||
for (int i = 3; i < 6; i++) {
|
||||
values [i] /= rtod_multiplier;
|
||||
}
|
||||
|
||||
result.e().set(values);
|
||||
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"\ntrans-load: Error in tload_next: unrecognized command '%s'\n",
|
||||
line);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new tsave_t transformation data file structure, used for
|
||||
* writing data to transformation data files.
|
||||
*/
|
||||
|
||||
static inline struct tsave_t *tsave_new(const char *filename) {
|
||||
FILE *file = fopen (filename, "w");
|
||||
struct tsave_t *result = NULL;
|
||||
|
||||
if (!file) {
|
||||
fprintf(stderr, "tsave: Error: could not open transformation data file '%s'.", filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
result = (struct tsave_t *)
|
||||
malloc(sizeof(struct tsave_t));
|
||||
result->filename = filename;
|
||||
result->file = file;
|
||||
result->orig = "unknown";
|
||||
result->target = "unknown";
|
||||
|
||||
fprintf(file, "# created by ALE 3D transformation file handler version %d\n",
|
||||
D3_TFILE_VERSION);
|
||||
|
||||
fclose(file);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the first transformation to a transformation data file associated with
|
||||
* transformation data file structure T, or do nothing if T is NULL. This
|
||||
* function also establishes the output file version.
|
||||
*
|
||||
* OFFSET is the transformation to be saved.
|
||||
*
|
||||
* IS_PROJECTIVE indicates whether to write a projective transformation.
|
||||
*
|
||||
*/
|
||||
|
||||
static inline void tsave_first(struct tsave_t *t, pt offset) {
|
||||
|
||||
if (t == NULL)
|
||||
return;
|
||||
|
||||
t->file = fopen(t->filename, "a");
|
||||
|
||||
tfile_output_version = 0;
|
||||
|
||||
fprintf(t->file, "# producing 3D transformation file syntax version %d\n", tfile_output_version);
|
||||
fprintf(t->file, "W %d\n", tfile_output_version);
|
||||
|
||||
// fprintf(t->file, "# Comment: Target output file is %s\n", t->target);
|
||||
// fprintf(t->file, "# Comment: Original frame is %s\n", t->orig);
|
||||
|
||||
const double rtod_multiplier = 180 / M_PI;
|
||||
|
||||
fprintf(t->file, "V %lf\n", (double) offset.view_angle() * rtod_multiplier);
|
||||
|
||||
fprintf(t->file, "E ");
|
||||
fprintf(t->file, "%f %f ", (double) offset.scaled_width(), (double) offset.scaled_height());
|
||||
fprintf(t->file, "%f ", (double) offset.e().get_translation(1));
|
||||
fprintf(t->file, "%f ", (double) offset.e().get_translation(0));
|
||||
fprintf(t->file, "%f ", (double) offset.e().get_translation(2));
|
||||
fprintf(t->file, "%f ", (double) offset.e().get_rotation(1) * rtod_multiplier);
|
||||
fprintf(t->file, "%f ", (double) offset.e().get_rotation(0) * rtod_multiplier);
|
||||
fprintf(t->file, "%f ", (double) offset.e().get_rotation(2) * rtod_multiplier);
|
||||
|
||||
fprintf(t->file, "\n");
|
||||
|
||||
fclose(t->file);
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the next transformation to a transformation data file associated with
|
||||
* transformation data file structure T, or do nothing if T is NULL.
|
||||
*
|
||||
* OFFSET is the transformation to be saved.
|
||||
*
|
||||
* IS_PROJECTIVE indicates whether to write a projective transformation.
|
||||
*
|
||||
*/
|
||||
|
||||
static inline void tsave_next(struct tsave_t *t, pt offset) {
|
||||
|
||||
if (t == NULL)
|
||||
return;
|
||||
|
||||
t->file = fopen(t->filename, "a");
|
||||
|
||||
const double rtod_multiplier = 180 / M_PI;
|
||||
|
||||
fprintf(t->file, "V %lf\n", (double) offset.view_angle() * rtod_multiplier);
|
||||
|
||||
fprintf(t->file, "E ");
|
||||
fprintf(t->file, "%f %f ", (double) offset.scaled_width(), (double) offset.scaled_height());
|
||||
fprintf(t->file, "%f ", (double) offset.e().get_translation(1));
|
||||
fprintf(t->file, "%f ", (double) offset.e().get_translation(0));
|
||||
fprintf(t->file, "%f ", (double) offset.e().get_translation(2));
|
||||
fprintf(t->file, "%f ", (double) offset.e().get_rotation(1) * rtod_multiplier);
|
||||
fprintf(t->file, "%f ", (double) offset.e().get_rotation(0) * rtod_multiplier);
|
||||
fprintf(t->file, "%f ", (double) offset.e().get_rotation(2) * rtod_multiplier);
|
||||
|
||||
fprintf(t->file, "\n");
|
||||
|
||||
fclose(t->file);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write information to a transformation file indicating the target output
|
||||
* file.
|
||||
*/
|
||||
|
||||
static inline void tsave_target(struct tsave_t *t, const char *filename) {
|
||||
if (t == NULL)
|
||||
return;
|
||||
|
||||
t->target = filename;
|
||||
if (t != NULL) {
|
||||
t->file = fopen(t->filename, "a");
|
||||
|
||||
|
||||
fclose(t->file);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write information to a transformation data file indicating the filename
|
||||
* of the original frame (i.e. the first frame in the sequence of input
|
||||
* frames).
|
||||
*/
|
||||
|
||||
static inline void tsave_orig(struct tsave_t *t, const char *filename) {
|
||||
if (t == NULL)
|
||||
return;
|
||||
|
||||
t->orig = filename;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write information to a transformation data file indicating the filename
|
||||
* of a supplemental frame (i.e. a frame in the sequence of input frames
|
||||
* that is not the first frame).
|
||||
*/
|
||||
|
||||
static inline void tsave_info(struct tsave_t *t, const char *filename) {
|
||||
if (t != NULL) {
|
||||
t->file = fopen(t->filename, "a");
|
||||
|
||||
fprintf(t->file, "# Comment: Supplemental frame %s\n", filename);
|
||||
|
||||
fclose(t->file);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write information to a transformation data file indicating the tonal
|
||||
* registration multiplier.
|
||||
*/
|
||||
|
||||
static inline void tsave_trm(struct tsave_t *t, ale_real r, ale_real g, ale_real b) {
|
||||
if (t != NULL) {
|
||||
t->file = fopen(t->filename, "a");
|
||||
|
||||
fprintf(t->file, "# Comment: Exposure [r=%f g=%f b=%f]\n", (double) r, (double) g, (double) b);
|
||||
|
||||
fclose(t->file);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write information to a transformation data file indicating the average
|
||||
* pixel magnitude.
|
||||
*/
|
||||
|
||||
static inline void tsave_apm(struct tsave_t *t, ale_real r, ale_real g, ale_real b) {
|
||||
if (t != NULL) {
|
||||
t->file = fopen(t->filename, "a");
|
||||
|
||||
fprintf(t->file, "# Comment: Avg magnitude [r=%f g=%f b=%f]\n", (double) r, (double) g, (double) b);
|
||||
|
||||
fclose(t->file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Destroy a tload_t transformation data file structure.
|
||||
*/
|
||||
|
||||
static inline void tload_delete(struct tload_t *victim) {
|
||||
if (victim)
|
||||
fclose(victim->file);
|
||||
free(victim);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy a tsave_t transformation data file structure.
|
||||
*/
|
||||
|
||||
static inline void tsave_delete(struct tsave_t *victim) {
|
||||
free(victim);
|
||||
}
|
||||
|
||||
#endif
|
||||
58
d3/view.h
Normal file
58
d3/view.h
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright 2004 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* view.h: A render subclass implementing views
|
||||
*/
|
||||
|
||||
#ifndef __view_h__
|
||||
#define __view_h__
|
||||
|
||||
#include "render.h"
|
||||
|
||||
class view : public render {
|
||||
|
||||
/*
|
||||
* Z-buffer rendering data
|
||||
*
|
||||
* XXX: there is no immediately obvious reason for depth to use RGB
|
||||
* triples.
|
||||
*/
|
||||
|
||||
d2::image *result;
|
||||
d2::image *depth;
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
* Describe a sphere at position p with radius r. Non-negative 'frame'
|
||||
* less than the total number of frames indicates that the position is
|
||||
* specified in the local space of that frame number. Otherwise, the
|
||||
* position is specified in world coordinates.
|
||||
*/
|
||||
|
||||
virtual void describe(int frame, point p, ale_real r) {
|
||||
}
|
||||
|
||||
d2::image *output() {
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user