Real synfig::bline_length(const ValueBase &bline, bool bline_loop, std::vector<Real> *lengths) { BLinePoint blinepoint0, blinepoint1; const std::vector<BLinePoint> list(bline.get_list().begin(),bline.get_list().end()); int size(list.size()); if(!bline_loop) size--; if(size < 1) return Real(); // Calculate the lengths and the total length Real tl(0), l; vector<BLinePoint>::const_iterator iter, next(list.begin()); iter = bline_loop ? --list.end() : next++; for(;next!=list.end(); next++) { blinepoint0 = *iter; blinepoint1 = *next; etl::hermite<Vector> curve(blinepoint0.get_vertex(), blinepoint1.get_vertex(), blinepoint0.get_tangent2(), blinepoint1.get_tangent1()); l=curve.length(); if(lengths) lengths->push_back(l); tl+=l; iter=next; } return tl; }
Real synfig::std_to_hom(const ValueBase &bline, Real pos, bool index_loop, bool bline_loop) { BLinePoint blinepoint0, blinepoint1; const std::vector<BLinePoint> list(bline.get_list().begin(),bline.get_list().end()); int size = list.size(), from_vertex; // trivial cases if(pos == 0.0 || pos == 1.0) return pos; if(!bline_loop) size--; if(size < 1) return Real(); Real int_pos((int)pos); Real one(0.0); if (index_loop) { pos = pos - int_pos; if (pos < 0) { pos++; one=1.0; } } else { if (pos < 0) pos = 0; if (pos > 1) pos = 1; } // Calculate the lengths and the total length Real tl=0, pl=0; std::vector<Real> lengths; vector<BLinePoint>::const_iterator iter, next; tl=bline_length(bline, bline_loop, &lengths); // If the total length of the bline is zero return pos if(tl==0.0) return pos; from_vertex = int(pos*size); // Calculate the partial length until the bezier that holds the current std::vector<Real>::const_iterator liter(lengths.begin()); for(int i=0;i<from_vertex; i++, liter++) pl+=*liter; // Calculate the remaining length of the position over current bezier // Setup the curve of the current bezier. next=list.begin(); iter = bline_loop ? --list.end() : next++; if (from_vertex > size-1) from_vertex = size-1; // if we are at the end of the last bezier blinepoint0 = from_vertex ? *(next+from_vertex-1) : *iter; blinepoint1 = *(next+from_vertex); etl::hermite<Vector> curve(blinepoint0.get_vertex(), blinepoint1.get_vertex(), blinepoint0.get_tangent2(), blinepoint1.get_tangent1()); // add the distance on the bezier we are on. pl+=curve.find_distance(0.0, pos*size - from_vertex); // and return the homogenous position return int_pos+pl/tl-one; }
void ValueAverage::set_average_value_weighted(ValueBase &weighted_list, const ValueBase &value) { if (weighted_list.get_type() != type_list) return; ValueBase::List list = weighted_list.get_list(); if (list.empty()) return; types_namespace::TypeWeightedValueBase *t = dynamic_cast<types_namespace::TypeWeightedValueBase *>(&(list.front().get_type())); if (t == NULL) return; if (!check_weighted_type(*t)) return; ValueBase::List values_list; values_list.reserve(list.size()); std::vector<Real> weights_list; weights_list.reserve(list.size()); for(ValueBase::List::const_iterator i = list.begin(); i != list.end(); ++i) { if (i->get_type() != *t) return; weights_list.push_back( t->extract_weight(*i) ); values_list.push_back( t->extract_value(*i) ); } set_average_value_generic( values_list.begin(), values_list.end(), weights_list.begin(), weights_list.end(), value ); std::vector<Real>::const_iterator j = weights_list.begin(); for(ValueBase::List::const_iterator i = values_list.begin(); i != values_list.end(); ++i, ++j) list[i - values_list.begin()] = t->create_weighted_value(*j, *i); weighted_list = list; }
bool ValueBase::operator==(const ValueBase& rhs)const { if(get_type()!=rhs.get_type()) return false; if(data==rhs.data) return true; switch(get_type()) { case TYPE_TIME: return get(Time()).is_equal(rhs.get(Time())); case TYPE_REAL: return abs(get(Real())-rhs.get(Real()))<=0.00000000000001; case TYPE_INTEGER: return get(int())==rhs.get(int()); case TYPE_BOOL: return get(bool())==rhs.get(bool()); case TYPE_ANGLE: return get(Angle())==rhs.get(Angle()); case TYPE_VECTOR: return get(Vector()).is_equal_to(rhs.get(Vector())); case TYPE_COLOR: return get(Color())==rhs.get(Color()); case TYPE_STRING: return get(String())==rhs.get(String()); case TYPE_CANVAS: return get(Canvas::LooseHandle())==rhs.get(Canvas::LooseHandle()); case TYPE_LIST: return get_list()==rhs.get_list(); case TYPE_VALUENODE_BONE: return get(ValueNode_Bone::Handle())==rhs.get(ValueNode_Bone::Handle()); case TYPE_DASHITEM: return get(DashItem())==rhs.get(DashItem()); case TYPE_SEGMENT: // return get(Segment())==rhs.get(Segment()); case TYPE_GRADIENT: // return get(Gradient())==rhs.get(Gradient()); case TYPE_BONE: // return get(Bone())==rhs.get(Bone()); case TYPE_BLINEPOINT: // return get(BLinePoint())==rhs.get(BLinePoint()); case TYPE_MATRIX: // return get(Matrix())==rhs.get(Matrix()); case TYPE_BONE_WEIGHT_PAIR: // return get(BoneWeightPair())==rhs.get(BoneWeightPair()); case TYPE_WIDTHPOINT: case TYPE_NIL: default: return false; } return false; }
ValueBase synfig::convert_bline_to_segment_list(const ValueBase& bline) { std::vector<Segment> ret; // std::vector<BLinePoint> list(bline.operator std::vector<BLinePoint>()); //std::vector<BLinePoint> list(bline); std::vector<BLinePoint> list(bline.get_list().begin(),bline.get_list().end()); std::vector<BLinePoint>::const_iterator iter; BLinePoint prev,first; //start with prev = first and iter on the second... if(list.empty()) return ValueBase(ret,bline.get_loop()); first = prev = list.front(); for(iter=++list.begin();iter!=list.end();++iter) { ret.push_back( Segment( prev.get_vertex(), prev.get_tangent2(), iter->get_vertex(), iter->get_tangent1() ) ); prev=*iter; } if(bline.get_loop()) { ret.push_back( Segment( prev.get_vertex(), prev.get_tangent2(), first.get_vertex(), first.get_tangent1() ) ); } return ValueBase(ret,bline.get_loop()); }
ValueBase synfig::convert_bline_to_width_list(const ValueBase& bline) { std::vector<Real> ret; // std::vector<BLinePoint> list(bline.operator std::vector<BLinePoint>()); //std::vector<BLinePoint> list(bline); std::vector<BLinePoint> list(bline.get_list().begin(),bline.get_list().end()); std::vector<BLinePoint>::const_iterator iter; if(bline.empty()) return ValueBase(ValueBase::TYPE_LIST); for(iter=list.begin();iter!=list.end();++iter) ret.push_back(iter->get_width()); if(bline.get_loop()) ret.push_back(list.front().get_width()); return ValueBase(ret,bline.get_loop()); }
ValueBase ValueAverage::average_weighted(const ValueBase &weighted_list, const ValueBase &default_value) { if (weighted_list.get_type() != type_list) return default_value; const ValueBase::List &list = weighted_list.get_list(); ValueBase::List values_list; values_list.reserve(list.size()); std::vector<Real> weights_list; weights_list.reserve(list.size()); for(ValueBase::List::const_iterator i = list.begin(); i != list.end(); ++i) { types_namespace::TypeWeightedValueBase *t = dynamic_cast<types_namespace::TypeWeightedValueBase *>(&(i->get_type())); if (t == NULL) continue; if (!check_weighted_type(*t)) continue; weights_list.push_back( t->extract_weight(*i) ); values_list.push_back( t->extract_value(*i) ); } return average_generic( values_list.begin(), values_list.end(), weights_list.begin(), weights_list.end(), default_value ); }
Real synfig::hom_to_std(const ValueBase &bline, Real pos, bool index_loop, bool bline_loop) { BLinePoint blinepoint0, blinepoint1; const std::vector<BLinePoint> list(bline.get_list().begin(),bline.get_list().end()); int size = list.size(), from_vertex(0); // trivial cases if(pos == 0.0 || pos == 1.0) return pos; if(!bline_loop) size--; if(size < 1) return Real(); Real int_pos=int(pos); Real one(0.0); if (index_loop) { pos = pos - int_pos; if (pos < 0) { pos++; one=1.0; } } else { if (pos < 0) pos = 0; if (pos > 1) pos = 1; } // Calculate the lengths and the total length Real tl(0), pl(0), mpl, bl; std::vector<Real> lengths; vector<BLinePoint>::const_iterator iter, next; tl=bline_length(bline, bline_loop,&lengths); // Calculate the my partial length (the length where pos is) mpl=pos*tl; next=list.begin(); iter = bline_loop ? --list.end() : next++; std::vector<Real>::const_iterator liter(lengths.begin()); // Find the previous bezier where we pos is placed and the sum // of lengths to it (pl) // also remember the bezier's length where we stop while(mpl > pl && next!=list.end()) { pl+=*liter; bl=*liter; iter=next; next++; liter++; from_vertex++; } // correct the iters and partial length in case we passed over if(pl > mpl) { liter--; next--; if(next==list.begin()) iter=--list.end(); else iter--; pl-=*liter; from_vertex--; } // set up the cureve blinepoint0 = *iter; blinepoint1 = *next; etl::hermite<Vector> curve(blinepoint0.get_vertex(), blinepoint1.get_vertex(), blinepoint0.get_tangent2(), blinepoint1.get_tangent1()); // Find the solution to which is the standard postion which matches the current // homogenous position // Secant method: http://en.wikipedia.org/wiki/Secant_method Real sn(0.0); // the standard position on current bezier Real sn1(0.0), sn2(1.0); Real t0((mpl-pl)/bl); // the homogenous position on the current bezier int iterations=0; int max_iterations=100; Real max_error(0.00001); Real error; Real fsn1(t0-curve.find_distance(0.0,sn1)/bl); Real fsn2(t0-curve.find_distance(0.0,sn2)/bl); Real fsn; do { sn=sn1-fsn1*((sn1-sn2)/(fsn1-fsn2)); fsn=t0-curve.find_distance(0.0, sn)/bl; sn2=sn1; sn1=sn; fsn2=fsn1; fsn1=fsn; error=fabs(fsn2-fsn1); iterations++; }while (error>max_error && max_iterations > iterations); // convert the current standard index (s) to the bline's standard index // and return it return int_pos+Real(from_vertex + sn)/size-one; }
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; }