--- /dev/null
+
+///////////////////////////////////////////////////////////////////////////
+// This program is free software: you can redistribute it and/or modify //
+// it under the terms of the version 3 of the GNU General Public License //
+// as published by the Free Software Foundation. //
+// //
+// This program 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 this program. If not, see <http://www.gnu.org/licenses/>. //
+// //
+// Written by Francois Fleuret, (C) IDIAP //
+// Contact <francois.fleuret@idiap.ch> for comments & bug reports //
+///////////////////////////////////////////////////////////////////////////
+
+#include <string.h>
+
+#include "pose.h"
+
+Pose::Pose() {
+ memset(this, 0, sizeof(*this));
+}
+
+void Pose::horizontal_flip(scalar_t scene_width) {
+ _head_xc = scene_width - 1 - _head_xc;
+ _body_xc = scene_width - 1 - _body_xc;
+}
+
+void Pose::translate(scalar_t dx, scalar_t dy) {
+ _bounding_box_xmin += dx;
+ _bounding_box_ymin += dy;
+ _bounding_box_xmax += dx;
+ _bounding_box_ymax += dy;
+ _head_xc += dx;
+ _head_yc += dy;
+ _body_xc += dx;
+ _body_yc += dy;
+}
+
+void Pose::scale(scalar_t factor) {
+ _bounding_box_xmin *= factor;
+ _bounding_box_ymin *= factor;
+ _bounding_box_xmax *= factor;
+ _bounding_box_ymax *= factor;
+ _head_xc *= factor;
+ _head_yc *= factor;
+ _head_radius *= factor;
+ _body_xc *= factor;
+ _body_yc *= factor;
+}
+
+const scalar_t tolerance_scale_ratio_for_hit = 1.5;
+const scalar_t tolerance_distance_factor_for_hit = 1.0;
+
+bool Pose::hit(int level, Pose *pose) {
+
+ // Head size
+
+ if(_head_radius/pose->_head_radius > tolerance_scale_ratio_for_hit ||
+ pose->_head_radius/_head_radius > tolerance_scale_ratio_for_hit)
+ return false;
+
+ scalar_t sq_delta = _head_radius * pose->_head_radius * sq(tolerance_distance_factor_for_hit);
+
+ // Head location
+
+ if(sq(_head_xc - pose->_head_xc) + sq(_head_yc - pose->_head_yc) > sq_delta)
+ return false;
+
+ if(level == 0) return true;
+
+ // Belly location
+
+ if(sq(_body_xc - pose->_body_xc) + sq(_body_yc - pose->_body_yc) > 4 * sq_delta)
+ return false;
+
+ if(level == 1) return true;
+
+ cerr << "Hit criterion is undefined for level " << level << endl;
+
+ abort();
+}
+
+const scalar_t tolerance_scale_ratio_for_collide = 1.2;
+const scalar_t tolerance_distance_factor_for_collide = 0.25;
+
+bool Pose::collide(int level, Pose *pose) {
+
+ // Head size
+
+ if(_head_radius/pose->_head_radius > tolerance_scale_ratio_for_collide ||
+ pose->_head_radius/_head_radius > tolerance_scale_ratio_for_collide)
+ return false;
+
+ scalar_t sq_delta = _head_radius * pose->_head_radius * sq(tolerance_distance_factor_for_collide);
+
+ // Head location
+
+ if(sq(_head_xc - pose->_head_xc) + sq(_head_yc - pose->_head_yc) <= sq_delta)
+ return true;
+
+ if(level == 0) return false;
+
+ // Belly location
+
+ if(sq(_body_xc - pose->_body_xc) + sq(_body_yc - pose->_body_yc) <= sq_delta)
+ return true;
+
+ if(level == 1) return false;
+
+ cerr << "Colliding criterion is undefined for level " << level << endl;
+
+ abort();
+}
+
+void Pose::draw(int thickness, int r, int g, int b, int level, RGBImage *image) {
+ // Draw the head circle
+
+ image->draw_ellipse(thickness, r, g, b,
+ _head_xc, _head_yc, _head_radius, _head_radius, 0);
+
+ // int vx = int(cos(_head_tilt) * _head_radius);
+ // int vy = int(sin(_head_tilt) * _head_radius);
+ // image->draw_line(thickness, r, g, b, _head_xc, _head_yc, _head_xc + vx, _head_yc + vy);
+
+ if(level == 1) {
+
+ // image->draw_line(thickness, r, g, b,
+ // int(_body_xc) - delta, int(_body_yc),
+ // int(_body_xc) + delta, int(_body_yc));
+
+ // image->draw_line(thickness, r, g, b,
+ // int(_body_xc), int(_body_yc) - delta,
+ // int(_body_xc), int(_body_yc) + delta);
+
+ scalar_t vx = _body_xc - _head_xc, vy = _body_yc - _head_yc;
+ scalar_t l = sqrt(vx * vx + vy * vy);
+ vx /= l;
+ vy /= l;
+
+ scalar_t body_radius = 12 + thickness / 2;
+
+ if(l > _head_radius + thickness + body_radius) {
+ image->draw_line(thickness, r, g, b,
+ _head_xc + vx * (_head_radius + thickness/2),
+ _head_yc + vy * (_head_radius + thickness/2),
+ _body_xc - vx * (body_radius - thickness/2),
+ _body_yc - vy * (body_radius - thickness/2));
+ }
+
+ // An ugly way to make a filled disc
+ for(scalar_t u = 0; u < body_radius; u += thickness / 2) {
+ image->draw_ellipse(thickness, r, g, b, _body_xc, _body_yc, u, u, 0);
+ }
+
+ }
+}
+
+void Pose::print(ostream *out) {
+ (*out) << " _head_xc " << _head_xc << endl;
+ (*out) << " _head_yc " << _head_yc << endl;
+ (*out) << " _head_radius " << _head_radius << endl;
+ (*out) << " _body_xc " << _body_xc << endl;
+ (*out) << " _body_yc " << _body_yc << endl;
+}
+
+void Pose::write(ostream *out) {
+ write_var(out, &_bounding_box_xmin);
+ write_var(out, &_bounding_box_ymin);
+ write_var(out, &_bounding_box_xmax);
+ write_var(out, &_bounding_box_ymax);
+ write_var(out, &_head_xc); write_var(out, &_head_yc);
+ write_var(out, &_head_radius);
+ write_var(out, &_body_xc);
+ write_var(out, &_body_yc);
+}
+
+void Pose::read(istream *in) {
+ read_var(in, &_bounding_box_xmin);
+ read_var(in, &_bounding_box_ymin);
+ read_var(in, &_bounding_box_xmax);
+ read_var(in, &_bounding_box_ymax);
+ read_var(in, &_head_xc); read_var(in, &_head_yc);
+ read_var(in, &_head_radius);
+ read_var(in, &_body_xc);
+ read_var(in, &_body_yc);
+}