ValueBase ValueNode_WPList::operator()(Time t)const { if (getenv("SYNFIG_DEBUG_VALUENODE_OPERATORS")) printf("%s:%d operator()\n", __FILE__, __LINE__); std::vector<WidthPoint> ret_list; std::vector<ListEntry>::const_iterator iter; bool rising; WidthPoint curr; // go through all the list's entries for(iter=list.begin();iter!=list.end();++iter) { // how 'on' is this widthpoint? float amount(iter->amount_at_time(t,&rising)); assert(amount>=0.0f); assert(amount<=1.0f); // we store the current width point curr=(*iter->value_node)(t).get(curr); // it's fully on if (amount > 1.0f - 0.0000001f) { // push back to the returning list ret_list.push_back(curr); } // it's partly on else if(amount>0.0f) { // This is where the interesting stuff happens Time off_time, on_time; if(!rising) // if not rising, then we were fully 'on' in the past, and will be fully 'off' in the future { 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 // otherwise we were fully 'off' in the past, and will be fully 'on' in the future { 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(); } } // i_width is the interpolated width at current time given by fully 'on' surrounding width points Real i_width(interpolated_width(curr.get_norm_position(get_loop()), t)); Real curr_width(curr.get_width()); // linear interpolation by amount curr.set_width(i_width*(1.0-amount)+(curr_width)*amount); // now insert the calculated width point into the widht list ret_list.push_back(curr); } } if(list.empty()) synfig::warning(string("ValueNode_WPList::operator()():")+_("No entries in list")); else if(ret_list.empty()) synfig::warning(string("ValueNode_WPList::operator()():")+_("No entries in ret_list")); return ValueBase(ret_list,get_loop()); }
ValueBase synfig::ValueNode_Composite::operator()(Time t)const { if (getenv("SYNFIG_DEBUG_VALUENODE_OPERATORS")) printf("%s:%d operator()\n", __FILE__, __LINE__); Type &type(get_type()); if (type == type_vector) { Vector vect; assert(components[0] && components[1]); vect[0]=(*components[0])(t).get(Vector::value_type()); vect[1]=(*components[1])(t).get(Vector::value_type()); return vect; } else if (type == type_color) { Color color; assert(components[0] && components[1] && components[2] && components[3]); color.set_r((*components[0])(t).get(Vector::value_type())); color.set_g((*components[1])(t).get(Vector::value_type())); color.set_b((*components[2])(t).get(Vector::value_type())); color.set_a((*components[3])(t).get(Vector::value_type())); return color; } else if (type == type_segment) { Segment seg; assert(components[0] && components[1] && components[2] && components[3]); seg.p1=(*components[0])(t).get(Point()); seg.t1=(*components[1])(t).get(Vector()); seg.p2=(*components[2])(t).get(Point()); seg.t2=(*components[3])(t).get(Vector()); return seg; } else if (type == type_bline_point) { BLinePoint ret; assert(components[0] && components[1] && components[2] && components[3] && components[4] && components[5] && components[6] && components[7]); ret.set_vertex((*components[0])(t).get(Point())); ret.set_width((*components[1])(t).get(Real())); ret.set_origin((*components[2])(t).get(Real())); ret.set_split_tangent_both((*components[3])(t).get(bool())); ret.set_split_tangent_radius((*components[6])(t).get(bool())); ret.set_split_tangent_angle((*components[7])(t).get(bool())); ret.set_tangent1((*components[4])(t).get(Vector())); ret.set_tangent2((*components[5])(t).get(Vector())); return ret; } else if (type == type_width_point) { WidthPoint ret; assert(components[0] && components[1] && components[2] && components[3] && components[4] && components[5]); ret.set_position((*components[0])(t).get(Real())); ret.set_width((*components[1])(t).get(Real())); ret.set_side_type_before((*components[2])(t).get(int())); ret.set_side_type_after((*components[3])(t).get(int())); ret.set_lower_bound((*components[4])(t).get(Real())); ret.set_upper_bound((*components[5])(t).get(Real())); return ret; } else if (type == type_dash_item) { DashItem ret; assert(components[0] && components[1] && components[2] && components[3]); Real offset((*components[0])(t).get(Real())); if(offset < 0.0) offset=0.0; Real length((*components[1])(t).get(Real())); if(length < 0.0) length=0.0; ret.set_offset(offset); ret.set_length(length); ret.set_side_type_before((*components[2])(t).get(int())); ret.set_side_type_after((*components[3])(t).get(int())); return ret; } else if (type == type_transformation) { Transformation ret; assert(components[0] && components[1] && components[2] && components[3]); ret.offset = (*components[0])(t).get(Vector()); ret.angle = (*components[1])(t).get(Angle()); ret.skew_angle = (*components[2])(t).get(Angle()); ret.scale = (*components[3])(t).get(Vector()); return ret; } else if (dynamic_cast<types_namespace::TypeWeightedValueBase*>(&type) != NULL) { types_namespace::TypeWeightedValueBase *tp = dynamic_cast<types_namespace::TypeWeightedValueBase*>(&type); assert(components[0] && components[1]); return tp->create_weighted_value((*components[0])(t).get(Real()), (*components[1])(t)); } else if (dynamic_cast<types_namespace::TypePairBase*>(&type) != NULL) { types_namespace::TypePairBase *tp = dynamic_cast<types_namespace::TypePairBase*>(&type); assert(components[0] && components[1]); return tp->create_value((*components[0])(t), (*components[1])(t)); } synfig::error(string("ValueNode_Composite::operator():")+_("Bad type for composite")); assert(components[0]); return (*components[0])(t); }
/*! * @param prev previous withpoint * @param next next withpoint * @param p position to calculate the new width between previous position and next position * @param smoothness [0,1] how much linear (0) or smooth (1) the interpolation is * @return the interpolated width */ Real synfig::widthpoint_interpolate(const WidthPoint& prev, const WidthPoint& next, const Real p, const Real smoothness) { // Smoothness gives linear interpolation between // the result of the linear interpolation between the withpoints // and the interpolation based on a 5th degree polynomial that matches // following rules: // q [0,1] // p(0)= 0 p(1)= 1 // p'(0)= 0 p'(1)= 0 // p''(0)= 0 p''(1)= 0 // It is: p(q) = 6*q^5-15*q^4+10*q^3 = q*q*q*(10+q*(6*q-15) WidthPoint::SideType side_int(WidthPoint::TYPE_INTERPOLATE); int nsb, nsa, psb, psa; Real pp, np; Real nw, pw, rw(0.0); const Real epsilon(0.0000001f); np=next.get_position(); pp=prev.get_position(); nw=next.get_width(); pw=prev.get_width(); nsb=next.get_side_type_before(); nsa=next.get_side_type_after(); psb=prev.get_side_type_before(); psa=prev.get_side_type_after(); if(p==np) return nw; if(p==pp) return pw; // Normal case: previous position is lower than next position if(np > pp) { if(np > p && p > pp ) { Real q; if(nsb != side_int) nw=0.0; if(psa != side_int) pw=0.0; if(np-pp < epsilon) q=0.5; else q=(p-pp)/(np-pp); rw=pw+(nw-pw)*(q*(1.0-smoothness)+q*q*q*(10+q*(6*q-15))*smoothness); } else if(p < pp) { if(psb != side_int) pw=0.0; rw=pw; } else if(p > np) { if(nsa != side_int) nw=0.0; rw=nw; } } // particular case: previous position is higher than next position else if(p > pp || np > p) { Real q(0); if(nsb != side_int) nw=0.0; if(psa != side_int) pw=0.0; if(np+1.0-pp < epsilon) q=0.5; else { if(p > pp) q=(p-pp)/(np+1.0-pp); if(np > p) q=(p+1.0-pp)/(np+1.0-pp); } rw=pw+(nw-pw)*(q*(1.0-smoothness)+q*q*q*(10+q*(6*q-15))*smoothness); } else if(p > np && p < pp) { Real q; if(nsa != side_int) nw=0.0; if(psb != side_int) pw=0.0; if(pp-np < epsilon) q=0.5; else q=(p-np)/(pp-np); rw=nw+(pw-nw)*(q*(1.0-smoothness)+q*q*q*(10+q*(6*q-15))*smoothness); } return rw; }