/* === S Y N F I G ========================================================= */
/*! \file curvegradient.cpp
-** \brief Template Header
+** \brief Implementation of the "Curve Gradient" layer
**
** $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
/* === M A C R O S ========================================================= */
+#define FAKE_TANGENT_STEP 0.000001
+
/* === G L O B A L S ======================================================= */
SYNFIG_LAYER_INIT(CurveGradient);
SYNFIG_LAYER_SET_NAME(CurveGradient,"curve_gradient");
-SYNFIG_LAYER_SET_LOCAL_NAME(CurveGradient,_("Curve Gradient"));
-SYNFIG_LAYER_SET_CATEGORY(CurveGradient,_("Gradients"));
+SYNFIG_LAYER_SET_LOCAL_NAME(CurveGradient,N_("Curve Gradient"));
+SYNFIG_LAYER_SET_CATEGORY(CurveGradient,N_("Gradients"));
SYNFIG_LAYER_SET_VERSION(CurveGradient,"0.0");
SYNFIG_LAYER_SET_CVS_ID(CurveGradient,"$Id$");
#endif
}
-inline float calculate_distance(const std::vector<synfig::BLinePoint>& bline)
+inline float calculate_distance(const std::vector<synfig::BLinePoint>& bline, bool bline_loop)
{
std::vector<synfig::BLinePoint>::const_iterator iter,next,ret;
std::vector<synfig::BLinePoint>::const_iterator end(bline.end());
next=bline.begin();
- //if(loop)
- // iter=--bline.end();
- //else
- iter=next++;
+ if(bline_loop)
+ iter=--bline.end();
+ else
+ iter=next++;
for(;next!=end;iter=next++)
{
inline void
CurveGradient::sync()
{
- curve_length_=calculate_distance(bline);
+ curve_length_=calculate_distance(bline, bline_loop);
}
CurveGradient::CurveGradient():
- offset(0,0),
+ origin(0,0),
width(0.25),
gradient(Color::black(), Color::white()),
loop(false),
Real dist;
float perp_dist;
+ bool edge_case = false;
if(bline.size()==0)
return Color::alpha();
else
{
float t;
- Point point(point_-offset);
+ Point point(point_-origin);
std::vector<synfig::BLinePoint>::const_iterator iter,next;
// Calculate our values
p1=curve(t); // the closest point on the curve
- tangent=deriv(t).norm(); // the unit tangent at that point
+ 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_flag() || 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_flag() || 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)
{
const Real mag(diff.inv_mag());
supersample=supersample*mag;
diff*=mag*mag;
- dist=((point_-offset)*diff-p1*diff);
+ dist=(point_-origin - p1)*diff;
}
}
else // not perpendicular
{
- diff=tangent.perp()*thickness*width;
+ 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_-offset)*diff-p1*diff);
+ dist=(point_-origin - p1)*diff;
}
if(loop)
{
- IMPORT(offset);
+ IMPORT(origin);
IMPORT(perpendicular);
IMPORT(fast);
IMPORT(gradient);
IMPORT(loop);
IMPORT(zigzag);
+
+ IMPORT_AS(origin,"offset");
+
return Layer_Composite::set_param(param,value);
}
ValueBase
CurveGradient::get_param(const String & param)const
{
- EXPORT(offset);
+ EXPORT(origin);
EXPORT(bline);
EXPORT(gradient);
EXPORT(loop);
{
Layer::Vocab ret(Layer_Composite::get_param_vocab());
- ret.push_back(ParamDesc("offset")
- .set_local_name(_("Offset")));
+ ret.push_back(ParamDesc("origin")
+ .set_local_name(_("Origin")));
ret.push_back(ParamDesc("width")
.set_is_distance()
ret.push_back(ParamDesc("bline")
.set_local_name(_("Vertices"))
- .set_origin("offset")
- .set_scalar("width")
+ .set_origin("origin")
+ .set_hint("width")
.set_description(_("A list of BLine Points")));
ret.push_back(ParamDesc("gradient")