/* === S Y N F I G ========================================================= */
/*! \file valuenode_bline.cpp
-** \brief Template File
+** \brief Implementation of the "BLine" valuenode conversion.
**
** $Id$
**
** \legal
** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
-** Copyright (c) 2007 Chris Moore
+** Copyright (c) 2007, 2008 Chris Moore
**
** This package is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License as
#include <ETL/hermite>
#include <ETL/calculus>
#include "segment.h"
+#include "curve_helper.h"
#endif
/* === M A C R O S ========================================================= */
+#define EPSILON 0.0000001f
+
/* === G L O B A L S ======================================================= */
/* === P R O C E D U R E S ================================================= */
affine_combo<Angle,float> ang_combo;
Real mag(mag_combo(a.mag(),b.mag(),c));
- Angle ang(ang_combo(Angle::tan(a[1],a[0]),Angle::tan(b[1],b[0]),c));
+ Angle angle_a(Angle::tan(a[1],a[0]));
+ Angle angle_b(Angle::tan(b[1],b[0]));
+ float diff = Angle::deg(angle_b - angle_a).get();
+ if (diff < -180) angle_b += Angle::deg(360);
+ else if (diff > 180) angle_a += Angle::deg(360);
+ Angle ang(ang_combo(angle_a, angle_b, c));
return Point( mag*Angle::cos(ang).get(),mag*Angle::sin(ang).get() );
}
return ValueBase(ret,bline.get_loop());
}
+Real
+synfig::find_closest_point(const ValueBase &bline, const Point &pos, Real &radius, bool loop, Point *out_point)
+{
+ Real d,step;
+ float time = 0;
+ float best_time = 0;
+ int best_index = -1;
+ synfig::Point best_point;
+
+ if(radius==0)radius=10000000;
+ Real closest(10000000);
+
+ int i=0;
+ std::vector<BLinePoint> list(bline.get_list().begin(),bline.get_list().end());
+ typedef std::vector<BLinePoint>::const_iterator iterT;
+ iterT iter, prev, first;
+ for(iter=list.begin(); iter!=list.end(); ++i, ++iter)
+ {
+ if( first == iterT() )
+ first = iter;
+
+ if( prev != iterT() )
+ {
+ bezier<Point> curve;
+
+ curve[0] = (*prev).get_vertex();
+ curve[1] = curve[0] + (*prev).get_tangent2()/3;
+ curve[3] = (*iter).get_vertex();
+ curve[2] = curve[3] - (*iter).get_tangent1()/3;
+ curve.sync();
+
+ #if 0
+ // I don't know why this doesn't work
+ time=curve.find_closest(pos,6);
+ d=((curve(time)-pos).mag_squared());
+
+ #else
+ //set the step size based on the size of the picture
+ d = (curve[1] - curve[0]).mag() + (curve[2]-curve[1]).mag() + (curve[3]-curve[2]).mag();
+
+ step = d/(2*radius); //want to make the distance between lines happy
+
+ step = max(step,0.01); //100 samples should be plenty
+ step = min(step,0.1); //10 is minimum
+
+ d = find_closest(curve,pos,step,&closest,&time);
+ #endif
+
+ if(d < closest)
+ {
+ closest = d;
+ best_time = time;
+ best_index = i;
+ best_point = curve(best_time);
+ }
+
+ }
+
+ prev = iter;
+ }
+
+ // Loop if necessary
+ if( loop && ( first != iterT() ) && ( prev != iterT() ) )
+ {
+ bezier<Point> curve;
+
+ curve[0] = (*prev).get_vertex();
+ curve[1] = curve[0] + (*prev).get_tangent2()/3;
+ curve[3] = (*first).get_vertex();
+ curve[2] = curve[3] - (*first).get_tangent1()/3;
+ curve.sync();
+
+ #if 0
+ // I don't know why this doesn't work
+ time=curve.find_closest(pos,6);
+ d=((curve(time)-pos).mag_squared());
+
+ #else
+ //set the step size based on the size of the picture
+ d = (curve[1] - curve[0]).mag() + (curve[2]-curve[1]).mag() + (curve[3]-curve[2]).mag();
+
+ step = d/(2*radius); //want to make the distance between lines happy
+
+ step = max(step,0.01); //100 samples should be plenty
+ step = min(step,0.1); //10 is minimum
+
+ d = find_closest(curve,pos,step,&closest,&time);
+ #endif
+
+ if(d < closest)
+ {
+ closest = d;
+ best_time = time;
+ best_index = 0;
+ best_point = curve(best_time);
+ }
+ }
+
+ if(best_index != -1)
+ {
+ if(out_point)
+ *out_point = best_point;
+
+ int loop_adjust(loop ? 0 : -1);
+ int size = list.size();
+ Real amount = (best_index + best_time + loop_adjust) / (size + loop_adjust);
+ return amount;
+ }
+
+ return 0.0;
+
+}
/* === M E T H O D S ======================================================= */
}
}
-
return value_node;
}
{
ValueNode_BLine::ListEntry ret;
-
synfig::BLinePoint prev,next;
int prev_i,next_i;
next_i=index;
prev_i=find_prev_valid_entry(index,time);
- synfig::info("index=%d, next_i=%d, prev_i=%d",index,next_i,prev_i);
+ //synfig::info("index=%d, next_i=%d, prev_i=%d",index,next_i,prev_i);
next=(*list[next_i].value_node)(time);
prev=(*list[prev_i].value_node)(time);
assert(amount<=1.0f);
// it's fully on
- if(amount==1.0f)
+ if (amount > 1.0f - EPSILON)
{
if(first_flag)
{
return etl::strprintf(_("Vertex %03d"),i+1);
}
-ValueNode*
-ValueNode_BLine::clone(const GUID& deriv_guid)const
-{
- { ValueNode* x(find_value_node(get_guid()^deriv_guid).get()); if(x)return x; }
-
- ValueNode_BLine* ret=new ValueNode_BLine();
- ret->set_guid(get_guid()^deriv_guid);
-
- std::vector<ListEntry>::const_iterator iter;
-
- for(iter=list.begin();iter!=list.end();++iter)
- {
- if(iter->value_node->is_exported())
- ret->add(*iter);
- else
- {
- ListEntry list_entry(*iter);
- //list_entry.value_node=find_value_node(iter->value_node->get_guid()^deriv_guid).get();
- //if(!list_entry.value_node)
- list_entry.value_node=iter->value_node->clone(deriv_guid);
- ret->add(list_entry);
- //ret->list.back().value_node=iter->value_node.clone();
- }
- }
- ret->set_loop(get_loop());
-
- return ret;
-}
-
String
ValueNode_BLine::get_name()const
{
LinkableValueNode*
ValueNode_BLine::create_new()const
{
- assert(0);
- return 0;
+ return new ValueNode_BLine();
}
bool