X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=synfig-core%2Ftrunk%2Fsrc%2Fsynfig%2Fvaluenode_bline.cpp;h=8365b4131ee2e7e1fee35b4b07573ba48a327952;hb=756c0d29ac1742f231e6615f9a577e574e35a4af;hp=912c4a764344f69ce80aa3ec131273d3efda568c;hpb=ff60dac53c84aa7924d894732832bd4a514848d4;p=synfig.git diff --git a/synfig-core/trunk/src/synfig/valuenode_bline.cpp b/synfig-core/trunk/src/synfig/valuenode_bline.cpp index 912c4a7..8365b41 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 @@ -52,10 +53,16 @@ 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 ================================================= */ +inline float +linear_interpolation(const float& a, const float& b, float c) +{ return (b-a)*c+a; } + inline Vector linear_interpolation(const Vector& a, const Vector& b, float c) { return (b-a)*c+a; } @@ -76,7 +83,21 @@ radial_interpolation(const Vector& a, const Vector& b, float c) return Point( mag*Angle::cos(ang).get(),mag*Angle::sin(ang).get() ); } +inline void +transform_coords(Vector in, Vector& out, const Point& coord_origin, const Point *coord_sys) +{ + in -= coord_origin; + out[0] = in * coord_sys[0]; + out[1] = in * coord_sys[1]; +} +inline void +untransform_coords(const Vector& in, Vector& out, const Point& coord_origin, const Point *coord_sys) +{ + out[0] = in * coord_sys[0]; + out[1] = in * coord_sys[1]; + out += coord_origin; +} ValueBase synfig::convert_bline_to_segment_list(const ValueBase& bline) @@ -322,14 +343,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) { @@ -359,13 +383,12 @@ ValueNode_BLine::operator()(Time t)const else { ret_list.push_back(curr); - } prev=curr; } - else - if(amount>0.0f) + // it's partly on + else if(amount>0.0f) { std::vector::const_iterator begin_iter,end_iter; @@ -373,66 +396,58 @@ ValueNode_BLine::operator()(Time t)const // We need to seek forward in the list to see what the next // active point is - BLinePoint curr; - BLinePoint begin; // begin of dynamic group - BLinePoint end; // End of dynamic group - Time blend_time; - int dist_from_begin(0), dist_from_end(0); - BLinePoint ret; + BLinePoint blp_here_on; // the current vertex, when fully on + BLinePoint blp_here_off; // the current vertex, when fully off + BLinePoint blp_here_now; // the current vertex, right now (between on and off) + BLinePoint blp_prev_off; // the beginning of dynamic group when fully off + BLinePoint blp_next_off; // the end of the dynamic group when fully off - Time begin_time; - Time end_time; + int dist_from_begin(0), dist_from_end(0); + Time off_time, on_time; - if(!rising) + if(!rising) // if not rising, then we were fully on in the past, and will be fully off in the future { - try{ end_time=iter->find_prev(t)->get_time(); } - catch(...) { end_time=Time::begin(); } - try{ begin_time=iter->find_next(t)->get_time(); } - catch(...) { begin_time=Time::end(); } + try{ on_time=iter->find_prev(t)->get_time(); } + catch(...) { on_time=Time::begin(); } + try{ off_time=iter->find_next(t)->get_time(); } + catch(...) { off_time=Time::end(); } } - else + else // otherwise we were fully off in the past, and will be fully on in the future { - try{ begin_time=iter->find_prev(t)->get_time(); } - catch(...) { begin_time=Time::begin(); } - try{ end_time=iter->find_next(t)->get_time(); } - catch(...) { end_time=Time::end(); } + try{ off_time=iter->find_prev(t)->get_time(); } + catch(...) { off_time=Time::begin(); } + try{ on_time=iter->find_next(t)->get_time(); } + catch(...) { on_time=Time::end(); } } - blend_time=begin_time; - curr=(*iter->value_node)(end_time).get(curr); -// curr=(*iter->value_node)(t).get(curr); + 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) - { - end=(*end_iter->value_node)(blend_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; - end=(*end_iter->value_node)(blend_time).get(prev); -// end=first; - } else - { - // Writeme! - end_iter=first_iter; - end=(*end_iter->value_node)(blend_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; - begin.set_origin(100.0f); // set the origin to 100 (which is crazy) so that we can check to see if it was found + 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 do { if(begin_iter==list.begin()) @@ -446,43 +461,40 @@ 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; if(begin_iter->amount_at_time(t)>amount) { - begin=(*begin_iter->value_node)(blend_time).get(prev); + 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(begin.get_origin()==100.0f) + if(blp_prev_off.get_origin()==100.0f) { - if(get_loop()) - { - begin_iter=first_iter; - begin=(*begin_iter->value_node)(blend_time).get(prev); -// begin=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; - begin=(*begin_iter->value_node)(blend_time).get(prev); -// begin=first; - } + blp_prev_off=(*begin_iter->value_node)(off_time).get(prev); } - etl::hermite curve(begin.get_vertex(),end.get_vertex(),begin.get_tangent2(),end.get_tangent1()); + // this is how the curve looks when we have completely vanished + etl::hermite curve(blp_prev_off.get_vertex(), blp_next_off.get_vertex(), + blp_prev_off.get_tangent2(), blp_next_off.get_tangent1()); etl::derivative< etl::hermite > deriv(curve); - ret.set_vertex(curve(curr.get_origin())); - - ret.set_width((end.get_width()-begin.get_width())*curr.get_origin()+begin.get_width()); - - ret.set_tangent1(deriv(curr.get_origin())); - ret.set_tangent2(deriv(curr.get_origin())); + // where would we be on this curve, how wide will we be, and + // where will our tangents point (all assuming that we hadn't vanished) + blp_here_off.set_vertex(curve(blp_here_on.get_origin())); + blp_here_off.set_width((blp_next_off.get_width()-blp_prev_off.get_width())*blp_here_on.get_origin()+blp_prev_off.get_width()); + blp_here_off.set_tangent1(deriv(blp_here_on.get_origin())); + blp_here_off.set_tangent2(deriv(blp_here_on.get_origin())); float prev_tangent_scalar(1.0f); float next_tangent_scalar(1.0f); @@ -492,231 +504,161 @@ ValueNode_BLine::operator()(Time t)const // If we are the next to the begin if(begin_iter==--std::vector::const_iterator(iter) || dist_from_begin==1) - { - prev_tangent_scalar=(1.0f-curr.get_origin())*amount+curr.get_origin(); - } + prev_tangent_scalar=linear_interpolation(blp_here_on.get_origin(), 1.0f, amount); else - { - float origin=curr.get_origin()-prev.get_origin(); - prev_tangent_scalar=(1.0f-origin)*amount+origin; - } + prev_tangent_scalar=linear_interpolation(blp_here_on.get_origin()-prev.get_origin(), 1.0f, amount); // If we are the next to the end if(end_iter==++std::vector::const_iterator(iter) || dist_from_end==1) - { - float origin=1.0-curr.get_origin(); - next_tangent_scalar=(1.0f-origin)*amount+origin; - } - else - if(list.end()!=++std::vector::const_iterator(iter)) + next_tangent_scalar=linear_interpolation(1.0-blp_here_on.get_origin(), 1.0f, amount); + else if(list.end()!=++std::vector::const_iterator(iter)) { BLinePoint next; next=((*(++std::vector::const_iterator(iter))->value_node)(t).get(prev)); - float origin=next.get_origin()-curr.get_origin(); - next_tangent_scalar=(1.0f-origin)*amount+origin; + next_tangent_scalar=linear_interpolation(next.get_origin()-blp_here_on.get_origin(), 1.0f, amount); } else - { //! \todo this isn't quite right; we should handle looped blines identically no matter where the loop happens //! and we currently don't. this at least makes it a lot better than it was before - float origin=end.get_origin()-curr.get_origin(); - next_tangent_scalar=(1.0f-origin)*amount+origin; - } + next_tangent_scalar=linear_interpolation(blp_next_off.get_origin()-blp_here_on.get_origin(), 1.0f, amount); next_scale=next_tangent_scalar; - //ret.set_vertex((curr.get_vertex()-ret.get_vertex())*amount+ret.get_vertex()); - if(false) - { - // My first try - Point ref_point_begin( - ( - (*begin_iter->value_node)(begin_time).get(prev).get_vertex() + - (*end_iter->value_node)(begin_time).get(prev).get_vertex() - ) * 0.5 - ); - Point ref_point_end( - ( - (*begin_iter->value_node)(end_time).get(prev).get_vertex() + - (*end_iter->value_node)(end_time).get(prev).get_vertex() - ) * 0.5 - ); - Point ref_point_now( - ( - (*begin_iter->value_node)(t).get(prev).get_vertex() + - (*end_iter->value_node)(t).get(prev).get_vertex() - ) * 0.5 - ); - Point ref_point_linear((ref_point_end-ref_point_begin)*amount+ref_point_begin); - - ret.set_vertex( - (curr.get_vertex()-ret.get_vertex())*amount+ret.get_vertex() + - (ref_point_now-ref_point_linear) - ); - ret.set_tangent1((curr.get_tangent1()-ret.get_tangent1())*amount+ret.get_tangent1()); - ret.set_split_tangent_flag(curr.get_split_tangent_flag()); - if(ret.get_split_tangent_flag()) - ret.set_tangent2((curr.get_tangent2()-ret.get_tangent2())*amount+ret.get_tangent2()); - } - else + //blp_here_now.set_vertex(linear_interpolation(blp_here_off.get_vertex(), blp_here_on.get_vertex(), amount)); + // if(false) + // { + // // My first try + // Point ref_point_begin(((*begin_iter->value_node)(off_time).get(prev).get_vertex() + + // (*end_iter->value_node)(off_time).get(prev).get_vertex()) * 0.5); + // Point ref_point_end(((*begin_iter->value_node)(on_time).get(prev).get_vertex() + + // (*end_iter->value_node)(on_time).get(prev).get_vertex()) * 0.5); + // Point ref_point_now(((*begin_iter->value_node)(t).get(prev).get_vertex() + + // (*end_iter->value_node)(t).get(prev).get_vertex()) * 0.5); + // Point ref_point_linear(linear_interpolation(ref_point_begin, ref_point_end, amount)); + // + // blp_here_now.set_vertex(linear_interpolation(blp_here_off.get_vertex(), blp_here_on.get_vertex(), amount) + + // (ref_point_now-ref_point_linear)); + // blp_here_now.set_tangent1(linear_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(linear_interpolation(blp_here_off.get_tangent2(), blp_here_on.get_tangent2(), amount)); + // } + // else { // My second try - Point begin_cord_sys[2], begin_cord_origin; - Point end_cord_sys[2], end_cord_origin; - Point curr_cord_sys[2], curr_cord_origin; + // define 3 coordinate systems: + Point off_coord_sys[2], off_coord_origin; // when the current vertex is completely off + Point on_coord_sys[2] , on_coord_origin; // when the current vertex is completely on + Point curr_coord_sys[2], curr_coord_origin; // the current state - somewhere in between + + // for each of the 3 systems, the origin is half way between the previous and next active point + // and the axes are based on a vector from the next active point to the previous { - const Point a((*end_iter->value_node)(begin_time).get(prev).get_vertex()); - const Point b((*begin_iter->value_node)(begin_time).get(prev).get_vertex()); - begin_cord_origin=(a+b)/2; - begin_cord_sys[0]=( b - a ).norm(); - begin_cord_sys[1]=begin_cord_sys[0].perp(); - } - { - const Point a((*end_iter->value_node)(end_time).get(prev).get_vertex()); - const Point b((*begin_iter->value_node)(end_time).get(prev).get_vertex()); - end_cord_origin=(a+b)/2; - end_cord_sys[0]=( b - a ).norm(); - end_cord_sys[1]=end_cord_sys[0].perp(); - } - { - const Point a((*end_iter->value_node)(t).get(prev).get_vertex()); - const Point b((*begin_iter->value_node)(t).get(prev).get_vertex()); - curr_cord_origin=(a+b)/2; - curr_cord_sys[0]=( b - a ).norm(); - curr_cord_sys[1]=curr_cord_sys[0].perp(); + const Point end_pos_at_off_time(( *end_iter->value_node)(off_time).get(prev).get_vertex()); + const Point begin_pos_at_off_time((*begin_iter->value_node)(off_time).get(prev).get_vertex()); + off_coord_origin=(begin_pos_at_off_time + end_pos_at_off_time)/2; + off_coord_sys[0]=(begin_pos_at_off_time - end_pos_at_off_time).norm(); + off_coord_sys[1]=off_coord_sys[0].perp(); + + const Point end_pos_at_on_time(( *end_iter->value_node)(on_time).get(prev).get_vertex()); + const Point begin_pos_at_on_time((*begin_iter->value_node)(on_time).get(prev).get_vertex()); + on_coord_origin=(begin_pos_at_on_time + end_pos_at_on_time)/2; + on_coord_sys[0]=(begin_pos_at_on_time - end_pos_at_on_time).norm(); + on_coord_sys[1]=on_coord_sys[0].perp(); + + const Point end_pos_at_current_time(( *end_iter->value_node)(t).get(prev).get_vertex()); + const Point begin_pos_at_current_time((*begin_iter->value_node)(t).get(prev).get_vertex()); + 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]); } - /* - end_cord_origin=(*end_iter->value_node)(end_time).get(prev).get_vertex(); - end_cord_sys[0]=( - (*begin_iter->value_node)(end_time).get(prev).get_vertex() - - end_cord_origin - ).norm(); - end_cord_sys[1]=end_cord_sys[0].perp(); - - curr_cord_origin=(*end_iter->value_node)(t).get(prev).get_vertex(); - curr_cord_sys[0]=( - (*begin_iter->value_node)(t).get(prev).get_vertex() - - curr_cord_origin - ).norm(); - curr_cord_sys[1]=curr_cord_sys[0].perp(); - */ - - // Convert start point - Point a; - Vector at1,at2; - { - Point tmp(ret.get_vertex()-begin_cord_origin); - a[0]=tmp*begin_cord_sys[0]; - a[1]=tmp*begin_cord_sys[1]; -#define COORD_SYS_RADIAL_TAN_INTERP 1 + /* The code that was here before used just end_iter as the origin, rather than the mid-point */ -#ifdef COORD_SYS_RADIAL_TAN_INTERP - tmp=ret.get_tangent1()+ret.get_vertex()-begin_cord_origin; - at1[0]=tmp*begin_cord_sys[0]; - at1[1]=tmp*begin_cord_sys[1]; + // 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; - if(curr.get_split_tangent_flag()) - { - tmp=ret.get_tangent2()+ret.get_vertex()-begin_cord_origin; - at2[0]=tmp*begin_cord_sys[0]; - at2[1]=tmp*begin_cord_sys[1]; - } -#endif - } + 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); - // Convert finish point - Point b; - Vector bt1,bt2; - { - Point tmp(curr.get_vertex()-end_cord_origin); - b[0]=tmp*end_cord_sys[0]; - b[1]=tmp*end_cord_sys[1]; +#define COORD_SYS_RADIAL_TAN_INTERP 1 #ifdef COORD_SYS_RADIAL_TAN_INTERP - tmp=curr.get_tangent1()+curr.get_vertex()-end_cord_origin; - bt1[0]=tmp*end_cord_sys[0]; - bt1[1]=tmp*end_cord_sys[1]; + 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(curr.get_split_tangent_flag()) - { - tmp=curr.get_tangent2()+curr.get_vertex()-end_cord_origin; - bt2[0]=tmp*end_cord_sys[0]; - bt2[1]=tmp*end_cord_sys[1]; - } -#endif + if(blp_here_on.get_split_tangent_flag()) + { + 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 - Point c; - Vector ct1,ct2; { - // Transpose (invert) - swap(curr_cord_sys[0][1],curr_cord_sys[1][0]); - - Point tmp((b-a)*amount+a); - c[0]=tmp*curr_cord_sys[0]; - c[1]=tmp*curr_cord_sys[1]; - c+=curr_cord_origin; + // 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 +//#define INTERP_FUNCTION linear_interpolation #ifdef COORD_SYS_RADIAL_TAN_INTERP - tmp=INTERP_FUNCTION(at1,bt1,amount); - ct1[0]=tmp*curr_cord_sys[0]; - ct1[1]=tmp*curr_cord_sys[1]; - ct1+=curr_cord_origin; - ct1-=c; + { + 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 - if(curr.get_split_tangent_flag()) + if (blp_here_on.get_split_tangent_flag()) + { + blp_here_now.set_split_tangent_flag(true); +#ifdef COORD_SYS_RADIAL_TAN_INTERP { - tmp=INTERP_FUNCTION(at2,bt2,amount); - ct2[0]=tmp*curr_cord_sys[0]; - ct2[1]=tmp*curr_cord_sys[1]; - ct2+=curr_cord_origin; - ct2-=c; + 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); } -#endif - } - - ret.set_vertex(c); -#ifndef COORD_SYS_RADIAL_TAN_INTERP - ret.set_tangent1(radial_interpolation(ret.get_tangent1(),curr.get_tangent1(),amount)); - ret.set_split_tangent_flag(curr.get_split_tangent_flag()); - if(ret.get_split_tangent_flag()) - ret.set_tangent2(radial_interpolation(ret.get_tangent2(),curr.get_tangent2(),amount)); #else - ret.set_tangent1(ct1); - ret.set_split_tangent_flag(curr.get_split_tangent_flag()); - if(ret.get_split_tangent_flag()) - ret.set_tangent2(ct2); + 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); } - ret.set_origin(curr.get_origin()); - ret.set_width((curr.get_width()-ret.get_width())*amount+ret.get_width()); - + 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) { - ret.set_tangent1(ret.get_tangent1()*prev_tangent_scalar); + blp_here_now.set_tangent1(blp_here_now.get_tangent1()*prev_tangent_scalar); first_iter=iter; - first=prev=ret; + first=prev=blp_here_now; first_flag=false; - ret_list.push_back(ret); + ret_list.push_back(blp_here_now); continue; } ret_list.back().set_split_tangent_flag(true); ret_list.back().set_tangent2(prev.get_tangent2()*prev_tangent_scalar); - ret_list.push_back(ret); + ret_list.push_back(blp_here_now); ret_list.back().set_split_tangent_flag(true); - //ret_list.back().set_tangent2(ret.get_tangent1()); - ret_list.back().set_tangent1(ret.get_tangent1()*prev_tangent_scalar); + //ret_list.back().set_tangent2(blp_here_now.get_tangent1()); + ret_list.back().set_tangent1(blp_here_now.get_tangent1()*prev_tangent_scalar); - prev=ret; + prev=blp_here_now; } }