/* === S Y N F I G ========================================================= */
/*! \file bone.cpp
** \brief Bone File
**
** $Id$
**
** \legal
** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
** Copyright (c) 2008 Carlos López & Chirs Moore
**
** This package 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 2 of
** the License, or (at your option) any later version.
**
** This package 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.
** \endlegal
*/
/* ========================================================================= */
/* === H E A D E R S ======================================================= */
#ifdef USING_PCH
# include "pch.h"
#else
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "bone.h"
#include "guid.h"
#include "valuenodes/valuenode_bone.h"
#include <ETL/stringf>
#include <algorithm>
#include <cmath>
#include <inttypes.h>
#endif
/* === U S I N G =========================================================== */
using namespace std;
using namespace etl;
using namespace synfig;
/* === M A C R O S ========================================================= */
/* === G L O B A L S ======================================================= */
/* === P R O C E D U R E S ================================================= */
//! Default constructor
Bone::Bone():
origin_(Point(0,0)),
angle_(Angle::deg(0.0)),
scalelx_(1.0),
scalex_(1.0),
length_(1.0),
width_(0.1),
tipwidth_(0.1),
depth_(0.0),
parent_(0)
{
if (getenv("SYNFIG_DEBUG_NEW_BONES"))
printf("%s:%d new bone\n", __FILE__, __LINE__);
}
//!Constructor by origin and tip
Bone::Bone(const Point &o, const Point &t):
origin_(o),
angle_((t-o).angle()),
scalelx_(1.0),
scalex_(1.0),
length_(1.0),
width_(0.3),
tipwidth_(0.3),
depth_(0.0),
parent_(0)
{
if (getenv("SYNFIG_DEBUG_NEW_BONES"))
printf("%s:%d new bone\n", __FILE__, __LINE__);
}
//!Constructor by origin, angle, length, strength, parent bone (default = no parent)
Bone::Bone(const String &n, const Point &o, const Angle &a, const Real &l, ValueNode_Bone* p):
name_(n),
origin_(o),
angle_(a),
scalelx_(1.0),
scalex_(1.0),
length_(l),
width_(0.3),
tipwidth_(0.3),
depth_(0.0),
parent_(p)
{
if (getenv("SYNFIG_DEBUG_NEW_BONES"))
printf("%s:%d new bone\n", __FILE__, __LINE__);
}
const ValueNode_Bone*
Bone::get_parent()const
{
return parent_;
}
void
Bone::set_parent(const ValueNode_Bone* parent)
{
parent_ = parent;
}
//! get_tip() member function
//!@return The tip Point of the bone (calculated) based on
//! tip=origin+[length,0]*Scalex(scalex*scalelx,0)*Rotate(alpha)
Point
Bone::get_tip()
{
Matrix s, r, sr;
s.set_scale(scalex_*scalelx_,0);
r.set_rotate(angle_);
sr=s*r;
return (Point)sr.get_transformed(Vector(length_,0));
}
//!Get the string of the Bone
//!@return String type. A string representation of the bone
//!components.
synfig::String
Bone::get_string()const
{
return strprintf("N=%s O=(%.4f %.4f) a=%.4f slx=%.4f sx=%.4f l=%.4f w=%.4f tw=%.4f or=%.4f P=%lx",
name_.c_str(),
origin_[0], origin_[1],
Angle::deg(angle_).get(),
scalelx_, scalex_, length_, width_, tipwidth_, depth_, uintptr_t(parent_));
}
bool
Bone::is_root()const
{
return get_parent()->is_root();
}
Bone::Shape
Bone::get_shape() const
{
Matrix matrix = get_animated_matrix();
Vector origin = matrix.get_transformed(Vector(0.0, 0.0));
Vector direction = matrix.get_transformed(Vector(1.0, 0.0), false).norm();
Real length = get_length() * get_scalelx();
if (length < 0) {
length *= -1;
direction *= -1;
}
Shape shape;
shape.p0 = origin;
shape.p1 = origin + direction * length;
shape.r0 = fabs(get_width());
shape.r1 = fabs(get_tipwidth());
return shape;
}
Real
Bone::distance_to_shape_center_percent(const Shape &shape, const Vector &x)
{
static const Real precision = 0.000000001;
const Vector &p0 = shape.p0;
const Vector &p1 = shape.p1;
Real r0 = fabs(shape.r0);
Real r1 = fabs(shape.r1);
Real length = (p1 - p0).mag();
Real percent_p0 = r0 > precision ? 1.0 - (x - p0).mag()/r0 : 0.0;
Real percent_p1 = r1 > precision ? 1.0 - (x - p1).mag()/r1 : 0.0;
// check line
Real percent_line = 0.0;
if (length + precision > fabs(r1 - r0))
{
Real cos0 = (r0 - r1)/length;
Real cos1 = -cos0;
Real sin0 = sqrt(1 + precision - cos0*cos0);
Real sin1 = sin0;
Real ll = length - r0*cos0 - r1*cos1;
Vector direction = (p1 - p0)/length;
Vector pp0(p0 + direction * (r0*cos0));
Vector pp1(p0 + direction * (length - r1*cos1));
Real rr0 = r0*sin0;
Real rr1 = r1*sin1;
Real pos_at_line = (x - pp0)*direction/ll;
if (pos_at_line > 0.0 && pos_at_line < 1.0)
{
Real distance = fabs((x - pp0)*direction.perp());
Real max_distance = rr0*(1.0 - pos_at_line) + rr1*pos_at_line;
if (max_distance > 0.0) percent_line = 1.0 - distance/max_distance;
}
}
Real percent = 0.0;
if (percent_p0 > percent) percent = percent_p0;
if (percent_p1 > percent) percent = percent_p1;
if (percent_line > percent) percent = percent_line;
return percent;
}
Real
Bone::influence_function(Real x)
{
return sin(x*PI/2.0);
}
/* === M E T H O D S ======================================================= */
/* === E N T R Y P O I N T ================================================= */