CurveGradient::CurveGradient(): Layer_Composite(1.0,Color::BLEND_COMPOSITE), param_origin(ValueBase(Point(0,0))), param_width(ValueBase(Real(0.25))), param_bline(ValueBase(std::vector<synfig::BLinePoint>())), param_gradient(Gradient(Color::black(), Color::white())), param_loop(ValueBase(false)), param_zigzag(ValueBase(false)), param_perpendicular(ValueBase(false)), param_fast(ValueBase(true)) { std::vector<synfig::BLinePoint> bline; bline.push_back(BLinePoint()); bline.push_back(BLinePoint()); bline.push_back(BLinePoint()); bline[0].set_vertex(Point(0,1)); bline[1].set_vertex(Point(0,-1)); bline[2].set_vertex(Point(1,0)); bline[0].set_tangent(bline[1].get_vertex()-bline[2].get_vertex()*0.5f); bline[1].set_tangent(bline[2].get_vertex()-bline[0].get_vertex()*0.5f); bline[2].set_tangent(bline[0].get_vertex()-bline[1].get_vertex()*0.5f); bline[0].set_width(1.0f); bline[1].set_width(1.0f); bline[2].set_width(1.0f); bline_loop=true; param_bline.set(bline); sync(); SET_INTERPOLATION_DEFAULTS(); SET_STATIC_DEFAULTS(); }
CurveWarp::CurveWarp(): param_origin(ValueBase(Point(0,0))), param_perp_width(ValueBase(Real(1))), param_start_point(ValueBase(Point(-2.5,-0.5))), param_end_point(ValueBase(Point(2.5,-0.3))), param_bline(ValueBase(std::vector<synfig::BLinePoint>())), param_fast(ValueBase(true)) { std::vector<synfig::BLinePoint> bline; bline.push_back(BLinePoint()); bline.push_back(BLinePoint()); bline[0].set_vertex(Point(-2.5,0)); bline[1].set_vertex(Point( 2.5,0)); bline[0].set_tangent(Point(1, 0.1)); bline[1].set_tangent(Point(1, -0.1)); bline[0].set_width(1.0f); bline[1].set_width(1.0f); param_bline.set(bline); sync(); SET_INTERPOLATION_DEFAULTS(); SET_STATIC_DEFAULTS(); }
inline Color CurveGradient::color_func(const Point &point_, int quality, float supersample)const { Point origin=param_origin.get(Point()); Real width=param_width.get(Real()); std::vector<synfig::BLinePoint> bline(param_bline.get_list_of(BLinePoint())); Gradient gradient=param_gradient.get(Gradient()); bool loop=param_loop.get(bool()); bool zigzag=param_zigzag.get(bool()); bool perpendicular=param_perpendicular.get(bool()); bool fast=param_fast.get(bool()); Vector tangent; Vector diff; Point p1; Real thickness; Real dist; float perp_dist; bool edge_case = false; if(bline.size()==0) return Color::alpha(); else if(bline.size()==1) { tangent=bline.front().get_tangent1(); p1=bline.front().get_vertex(); thickness=bline.front().get_width(); } else { float t; Point point(point_-origin); std::vector<synfig::BLinePoint>::const_iterator iter,next; // Figure out the BLinePoints we will be using, // Taking into account looping. if(perpendicular) { next=find_closest(fast,bline,point,t,bline_loop,&perp_dist); perp_dist/=curve_length_; } else // not perpendicular { next=find_closest(fast,bline,point,t,bline_loop); } iter=next++; if(next==bline.end()) next=bline.begin(); // Setup the curve etl::hermite<Vector> curve( iter->get_vertex(), next->get_vertex(), iter->get_tangent2(), next->get_tangent1() ); // Setup the derivative function etl::derivative<etl::hermite<Vector> > deriv(curve); int search_iterations(7); /*if(quality==0)search_iterations=8; else if(quality<=2)search_iterations=10; else if(quality<=4)search_iterations=8; */ if(perpendicular) { if(quality>7) search_iterations=4; } else // not perpendicular { if(quality<=6)search_iterations=7; else if(quality<=7)search_iterations=6; else if(quality<=8)search_iterations=5; else search_iterations=4; } // Figure out the closest point on the curve if (fast) t = curve.find_closest(fast, point,search_iterations); // Calculate our values p1=curve(t); // the closest point on the curve tangent=deriv(t); // the tangent at that point // if the point we're nearest to is at either end of the // bline, our distance from the curve is the distance from the // point on the curve. we need to know which side of the // curve we're on, so find the average of the two tangents at // this point if (t<0.00001 || t>0.99999) { bool zero_tangent = (tangent[0] == 0 && tangent[1] == 0); if (t<0.5) { if (iter->get_split_tangent_angle() || iter->get_split_tangent_radius() || zero_tangent) { // fake the current tangent if we need to if (zero_tangent) tangent = curve(FAKE_TANGENT_STEP) - curve(0); // calculate the other tangent Vector other_tangent(iter->get_tangent1()); if (other_tangent[0] == 0 && other_tangent[1] == 0) { // find the previous blinepoint std::vector<synfig::BLinePoint>::const_iterator prev; if (iter != bline.begin()) (prev = iter)--; else if (loop) (prev = bline.end())--; else prev = iter; etl::hermite<Vector> other_curve(prev->get_vertex(), iter->get_vertex(), prev->get_tangent2(), iter->get_tangent1()); other_tangent = other_curve(1) - other_curve(1-FAKE_TANGENT_STEP); } // normalise and sum the two tangents tangent=(other_tangent.norm()+tangent.norm()); edge_case=true; } } else { if (next->get_split_tangent_angle() || next->get_split_tangent_radius() || zero_tangent) { // fake the current tangent if we need to if (zero_tangent) tangent = curve(1) - curve(1-FAKE_TANGENT_STEP); // calculate the other tangent Vector other_tangent(next->get_tangent2()); if (other_tangent[0] == 0 && other_tangent[1] == 0) { // find the next blinepoint std::vector<synfig::BLinePoint>::const_iterator next2(next); if (++next2 == bline.end()) { if (loop) next2 = bline.begin(); else next2 = next; } etl::hermite<Vector> other_curve(next->get_vertex(), next2->get_vertex(), next->get_tangent2(), next2->get_tangent1()); other_tangent = other_curve(FAKE_TANGENT_STEP) - other_curve(0); } // normalise and sum the two tangents tangent=(other_tangent.norm()+tangent.norm()); edge_case=true; } } } tangent = tangent.norm(); if(perpendicular) { tangent*=curve_length_; p1-=tangent*perp_dist; tangent=-tangent.perp(); } else // not perpendicular // the width of the bline at the closest point on the curve thickness=(next->get_width()-iter->get_width())*t+iter->get_width(); } if(perpendicular) { if(quality>7) { dist=perp_dist; /* diff=tangent.perp(); const Real mag(diff.inv_mag()); supersample=supersample*mag; */ supersample=0; } else { diff=tangent.perp(); //p1-=diff*0.5; const Real mag(diff.inv_mag()); supersample=supersample*mag; diff*=mag*mag; dist=(point_-origin - p1)*diff; } } else // not perpendicular { if (edge_case) { diff=(p1-(point_-origin)); if(diff*tangent.perp()<0) diff=-diff; diff=diff.norm()*thickness*width; } else diff=tangent.perp()*thickness*width; p1-=diff*0.5; const Real mag(diff.inv_mag()); supersample=supersample*mag; diff*=mag*mag; dist=(point_-origin - p1)*diff; } if(loop) dist-=floor(dist); if(zigzag) { dist*=2.0; supersample*=2.0; if(dist>1)dist=2.0-dist; } if(loop) { if(dist+supersample*0.5>1.0) { float left(supersample*0.5-(dist-1.0)); float right(supersample*0.5+(dist-1.0)); Color pool(gradient(1.0-(left*0.5),left).premult_alpha()*left/supersample); if (zigzag) pool+=gradient(1.0-right*0.5,right).premult_alpha()*right/supersample; else pool+=gradient(right*0.5,right).premult_alpha()*right/supersample; return pool.demult_alpha(); } if(dist-supersample*0.5<0.0) { float left(supersample*0.5-dist); float right(supersample*0.5+dist); Color pool(gradient(right*0.5,right).premult_alpha()*right/supersample); if (zigzag) pool+=gradient(left*0.5,left).premult_alpha()*left/supersample; else pool+=gradient(1.0-left*0.5,left).premult_alpha()*left/supersample; return pool.demult_alpha(); } } return gradient(dist,supersample); }
inline void CurveGradient::sync() { std::vector<synfig::BLinePoint> bline(param_bline.get_list_of(BLinePoint())); curve_length_=calculate_distance(bline, bline_loop); }