X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=synfig-core%2Ftrunk%2Fsrc%2Fsynfig%2Fvaluenode_bline.cpp;h=83eb419cc0a6f477e24d3250a42fd6bc4ca2a62e;hb=4ba22fb51d97f1ecce04dcc5e40569a4354c1bae;hp=243581492efa8583a3208e70814561f68de78a3f;hpb=18e8729e1b85b6e2d18de54720ec8c3e0f12d0df;p=synfig.git diff --git a/synfig-core/trunk/src/synfig/valuenode_bline.cpp b/synfig-core/trunk/src/synfig/valuenode_bline.cpp index 2435814..83eb419 100644 --- a/synfig-core/trunk/src/synfig/valuenode_bline.cpp +++ b/synfig-core/trunk/src/synfig/valuenode_bline.cpp @@ -1,11 +1,12 @@ /* === 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, 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 @@ -41,6 +42,7 @@ #include #include #include "segment.h" +#include "curve_helper.h" #endif @@ -52,6 +54,8 @@ using namespace synfig; /* === 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 ================================================= */ @@ -75,7 +79,12 @@ radial_interpolation(const Vector& a, const Vector& b, float c) affine_combo 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() ); } @@ -160,6 +169,118 @@ synfig::convert_bline_to_width_list(const ValueBase& bline) 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 list(bline.get_list().begin(),bline.get_list().end()); + typedef std::vector::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 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 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 ======================================================= */ @@ -279,7 +400,6 @@ ValueNode_BLine::create(const ValueBase &value) } } - return value_node; } @@ -288,7 +408,6 @@ ValueNode_BLine::create_list_entry(int index, Time time, Real origin) { ValueNode_BLine::ListEntry ret; - synfig::BLinePoint prev,next; int prev_i,next_i; @@ -305,7 +424,7 @@ ValueNode_BLine::create_list_entry(int index, Time time, Real origin) 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); @@ -340,14 +459,17 @@ ValueNode_BLine::operator()(Time t)const BLinePoint prev,first; first.set_origin(100.0f); + // loop through all the list's entries for(iter=list.begin();iter!=list.end();++iter,index++) { + // how 'on' is this vertex? float amount(iter->amount_at_time(t,&rising)); assert(amount>=0.0f); assert(amount<=1.0f); - if(amount==1.0f) + // it's fully on + if (amount > 1.0f - EPSILON) { if(first_flag) { @@ -381,8 +503,8 @@ ValueNode_BLine::operator()(Time t)const prev=curr; } - else - if(amount>0.0f) + // it's partly on + else if(amount>0.0f) { std::vector::const_iterator begin_iter,end_iter; @@ -417,34 +539,28 @@ ValueNode_BLine::operator()(Time t)const blp_here_on=(*iter->value_node)(on_time).get(blp_here_on); // blp_here_on=(*iter->value_node)(t).get(blp_here_on); - // Find "end" of dynamic group + // Find "end" of dynamic group - ie. search forward along + // the bline from the current point until we find a point + // which is more 'on' than the current one end_iter=iter; // for(++end_iter;begin_iter!=list.end();++end_iter) for(++end_iter;end_iter!=list.end();++end_iter) if(end_iter->amount_at_time(t)>amount) - { - blp_next_off=(*end_iter->value_node)(off_time).get(prev); break; - } // If we did not find an end of the dynamic group... + // Writeme! at least now it doesn't crash if first_iter + // isn't set yet if(end_iter==list.end()) { - if(get_loop()) - { + if(get_loop() && !first_flag) end_iter=first_iter; - blp_next_off=(*end_iter->value_node)(off_time).get(prev); -// end=first; - } else - { - // Writeme! - end_iter=first_iter; - blp_next_off=(*end_iter->value_node)(off_time).get(prev); -// end=first; - } + end_iter=--list.end(); } + blp_next_off=(*end_iter->value_node)(off_time).get(prev); + // Find "begin" of dynamic group begin_iter=iter; blp_prev_off.set_origin(100.0f); // set the origin to 100 (which is crazy) so that we can check to see if it was found @@ -461,6 +577,7 @@ ValueNode_BLine::operator()(Time t)const --begin_iter; dist_from_begin++; + // if we've gone all around the loop, give up if(begin_iter==iter) break; @@ -469,24 +586,18 @@ ValueNode_BLine::operator()(Time t)const blp_prev_off=(*begin_iter->value_node)(off_time).get(prev); break; } - }while(begin_iter!=iter); + }while(true); // If we did not find a begin if(blp_prev_off.get_origin()==100.0f) { - if(get_loop()) - { - begin_iter=first_iter; - blp_prev_off=(*begin_iter->value_node)(off_time).get(prev); -// blp_prev_off=first; - } + // Writeme! - this needs work, but at least now it + // doesn't crash + if(first_flag) + begin_iter=list.begin(); else - { - // Writeme! begin_iter=first_iter; - blp_prev_off=(*begin_iter->value_node)(off_time).get(prev); -// blp_prev_off=first; - } + blp_prev_off=(*begin_iter->value_node)(off_time).get(prev); } // this is how the curve looks when we have completely vanished @@ -576,73 +687,75 @@ ValueNode_BLine::operator()(Time t)const curr_coord_origin=(begin_pos_at_current_time + end_pos_at_current_time)/2; curr_coord_sys[0]=(begin_pos_at_current_time - end_pos_at_current_time).norm(); curr_coord_sys[1]=curr_coord_sys[0].perp(); + + // Invert (transpose) the last of these matrices, since we use it for transform back + swap(curr_coord_sys[0][1],curr_coord_sys[1][0]); } /* The code that was here before used just end_iter as the origin, rather than the mid-point */ - // For each of the 3 coordinate systems we've just defined, we convert a point and tangent(s) into that system - Point trans_on_point, trans_off_point, untrans_curr_point; - Vector trans_on_t1, trans_on_t2, trans_off_t1, trans_off_t2, untrans_curr_t1, untrans_curr_t2; + // We know our location and tangent(s) when fully on and fully off + // Transform each of these into their corresponding coordinate system + Point trans_on_point, trans_off_point; + Vector trans_on_t1, trans_on_t2, trans_off_t1, trans_off_t2; - // Convert points where vertex is fully on and fully off transform_coords(blp_here_on.get_vertex(), trans_on_point, on_coord_origin, on_coord_sys); transform_coords(blp_here_off.get_vertex(), trans_off_point, off_coord_origin, off_coord_sys); #define COORD_SYS_RADIAL_TAN_INTERP 1 #ifdef COORD_SYS_RADIAL_TAN_INTERP - // this I don't understand. why add on this bit ---v - transform_coords(blp_here_on.get_tangent1() + blp_here_on.get_vertex(), trans_on_t1, on_coord_origin, on_coord_sys); - transform_coords(blp_here_off.get_tangent1() + blp_here_off.get_vertex(), trans_off_t1, off_coord_origin, off_coord_sys); + transform_coords(blp_here_on.get_tangent1(), trans_on_t1, Point::zero(), on_coord_sys); + transform_coords(blp_here_off.get_tangent1(), trans_off_t1, Point::zero(), off_coord_sys); if(blp_here_on.get_split_tangent_flag()) { - transform_coords(blp_here_on.get_tangent2() + blp_here_on.get_vertex(), trans_on_t2, on_coord_origin, on_coord_sys); - transform_coords(blp_here_off.get_tangent2() + blp_here_off.get_vertex(), trans_off_t2, off_coord_origin, off_coord_sys); + transform_coords(blp_here_on.get_tangent2(), trans_on_t2, Point::zero(), on_coord_sys); + transform_coords(blp_here_off.get_tangent2(), trans_off_t2, Point::zero(), off_coord_sys); } #endif - // Convert current point - // Transpose (invert) - swap(curr_coord_sys[0][1],curr_coord_sys[1][0]); - // interpolate between the 'on' point and the 'off' point and untransform to get our point's location - untransform_coords(linear_interpolation(trans_off_point, trans_on_point, amount), - untrans_curr_point, curr_coord_origin, curr_coord_sys); + { + // Interpolate between the 'on' point and the 'off' point and untransform to get our point's location + Point tmp; + untransform_coords(linear_interpolation(trans_off_point, trans_on_point, amount), + tmp, curr_coord_origin, curr_coord_sys); + blp_here_now.set_vertex(tmp); + } #define INTERP_FUNCTION radial_interpolation //#define INTERP_FUNCTION linear_interpolation #ifdef COORD_SYS_RADIAL_TAN_INTERP - untransform_coords(INTERP_FUNCTION(trans_off_t1,trans_on_t1,amount), - untrans_curr_t1, curr_coord_origin, curr_coord_sys); - untrans_curr_t1 -= untrans_curr_point; - - if(blp_here_on.get_split_tangent_flag()) { - untransform_coords(INTERP_FUNCTION(trans_off_t2,trans_on_t2,amount), - untrans_curr_t2, curr_coord_origin, curr_coord_sys); - untrans_curr_t2 -= untrans_curr_point; + Vector tmp; + untransform_coords(INTERP_FUNCTION(trans_off_t1,trans_on_t1,amount), tmp, Point::zero(), curr_coord_sys); + blp_here_now.set_tangent1(tmp); } +#else + blp_here_now.set_tangent1(radial_interpolation(blp_here_off.get_tangent1(),blp_here_on.get_tangent1(),amount)); #endif - blp_here_now.set_vertex(untrans_curr_point); -#ifndef COORD_SYS_RADIAL_TAN_INTERP - blp_here_now.set_tangent1(radial_interpolation(blp_here_off.get_tangent1(),blp_here_on.get_tangent1(),amount)); - blp_here_now.set_split_tangent_flag(blp_here_on.get_split_tangent_flag()); - if(blp_here_now.get_split_tangent_flag()) - blp_here_now.set_tangent2(radial_interpolation(blp_here_off.get_tangent2(),blp_here_on.get_tangent2(),amount)); + if (blp_here_on.get_split_tangent_flag()) + { + blp_here_now.set_split_tangent_flag(true); +#ifdef COORD_SYS_RADIAL_TAN_INTERP + { + Vector tmp; + untransform_coords(INTERP_FUNCTION(trans_off_t2,trans_on_t2,amount), tmp, Point::zero(), curr_coord_sys); + blp_here_now.set_tangent2(tmp); + } #else - blp_here_now.set_tangent1(untrans_curr_t1); - blp_here_now.set_split_tangent_flag(blp_here_on.get_split_tangent_flag()); - if(blp_here_now.get_split_tangent_flag()) - blp_here_now.set_tangent2(untrans_curr_t2); + blp_here_now.set_tangent2(radial_interpolation(blp_here_off.get_tangent2(),blp_here_on.get_tangent2(),amount)); #endif + } + else + blp_here_now.set_split_tangent_flag(false); } blp_here_now.set_origin(blp_here_on.get_origin()); blp_here_now.set_width(linear_interpolation(blp_here_off.get_width(), blp_here_on.get_width(), amount)); - // Handle the case where we are the first vertex if(first_flag) { @@ -701,35 +814,6 @@ ValueNode_BLine::link_local_name(int i)const 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::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 { @@ -745,8 +829,7 @@ ValueNode_BLine::get_local_name()const LinkableValueNode* ValueNode_BLine::create_new()const { - assert(0); - return 0; + return new ValueNode_BLine(); } bool