lpe-taperstroke.cpp revision 49ab42a72a35618fae86c8f4ffbe98c85c743247
/**
* @file
* Taper Stroke path effect, provided as an alternative to Power Strokes
* for otherwise constant-width paths.
*
* Authors:
* Liam P White <inkscapebrony@gmail.com>
*
* Copyright (C) 2014 Authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include "live_effects/lpe-taperstroke.h"
#include "pathoutlineprovider.h"
#include "sp-shape.h"
#include "style.h"
#include "sp-paint-server.h"
#include "svg/svg-color.h"
#include "desktop-style.h"
#include "svg/css-ostringstream.h"
#include "knot-holder-entity.h"
#include "knotholder.h"
namespace Inkscape {
namespace LivePathEffect {
namespace TpS {
class KnotHolderEntityAttachBegin : public LPEKnotHolderEntity {
public:
};
class KnotHolderEntityAttachEnd : public LPEKnotHolderEntity {
public:
};
} // TpS
};
static const Util::EnumDataConverter<unsigned> JoinTypeConverter(JoinType, sizeof (JoinType)/sizeof(*JoinType));
line_width(_("Stroke width"), _("The (non-tapered) width of the path"), "stroke_width", &wr, this, 3),
attach_start(_("Start offset"), _("Taper distance from path start"), "attach_start", &wr, this, 0.2),
smoothing(_("Taper smoothing"), _("Amount of smoothing to apply to the tapers"), "smoothing", &wr, this, 0.5),
join_type(_("Join type"), _("Join type for non-smooth nodes"), "jointype", JoinTypeConverter, &wr, this, LINEJOIN_EXTRAPOLATED),
{
show_orig_path = true;
_provides_knotholder_entities = true;
}
{
}
//from LPEPowerStroke -- sets fill if stroke color because we will
//be converting to a fill to make the new join.
{
if (SP_IS_SHAPE(lpeitem)) {
if (server) {
str += "url(#";
str += ")";
}
gchar c[64];
sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value)));
} else {
}
} else {
}
} else {
g_warning("LPE Join Type can only be applied to paths (not groups).");
}
}
//from LPEPowerStroke -- sets stroke color from existing fill color
{
if (SP_IS_SHAPE(lpeitem)) {
//TODO: make it getobjbyrepr instead of const_cast because this can cause
//undefined behavior
if (server) {
str += "url(#";
str += ")";
}
gchar c[64];
sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value)));
} else {
}
} else {
}
item->updateRepr();
}
}
//actual effect impl here
{
}
Geom::Piecewise<Geom::D2<Geom::SBasis> > stretch_along(Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in, Geom::Path pattern, double width);
//references to pointers, because magic
void subdivideCurve(Geom::Curve * curve_in, Geom::Coord t, Geom::Curve *& val_first, Geom::Curve *& val_second);
{
bool zeroStart = false;
bool zeroEnd = false;
//there is a pretty good chance that people will try to drag the knots
//on top of each other, so block it
//check to see if the knots were dragged over each other
//if so, reset the end offset
}
}
//don't let it be zero
if (attach_start <= 0.00000001) {
zeroStart = true;
}
if (attach_end <= 0.00000001) {
zeroEnd = true;
}
//don't let it be integer
if (double(unsigned(attach_start)) == attach_start) {
}
if (double(unsigned(attach_end)) == attach_end) {
}
//don't let the knots be farther than they are allowed to be
if ((unsigned)attach_start >= allowed_start) {
}
if ((unsigned)attach_end >= allowed_end) {
}
//remember, Path::operator () means get point at time t
//the following function just splits it up into three pieces.
//now for the actual tapering. We use a Pattern Along Path method to get this done.
if (!zeroStart) {
//Construct the pattern (pat_str stands for pattern string) (yes, this is easier, trust me)
pat_str << "M 1,0 C " << 1 - (double)smoothing << ",0 0,0.5 0,0.5 0,0.5 " << 1 - (double)smoothing << ",1 1,1";
}
//append the outside outline of the path (with direction)
if (!zeroEnd) {
//append the ending taper
pat_str_1 << "M 0,0 0,1 C " << (double)smoothing << ",1 1,0.5 1,0.5 1,0.5 " << double(smoothing) << ",0 0,0";
}
//append the inside outline of the path (against direction)
return real_pathv;
}
//in all cases, this should return a PathVector with three elements.
{
//do subdivision and get out
unsigned loc = (unsigned)attach_start;
for (unsigned i = 0; i < loc; i++) {
}
//special case: path is one segment long
//special case: what if the two knots occupy the same segment?
//it is just a dumb segment
//we have to do some shifting here because the value changed when we reduced the length
//of the previous segment.
}
return pathv_out;
}
//append almost all of the rest of the path, ignore the curves that the knot is past (we'll get to it in a minute)
}
//deal with the last segment in a very similar fashion to the first
}
if (curve_start) delete curve_start;
return pathv_out;
}
//most of the below code is verbatim from Pattern Along Path. However, it needed a little
//tweaking to get it to work right in this case.
Geom::Piecewise<Geom::D2<Geom::SBasis> > stretch_along(Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in, Geom::Path pattern, double prop_scale)
{
using namespace Geom;
// Don't allow empty path parameter:
return pwd2_in;
}
/* Much credit should go to jfb and mgsloan of lib2geom development for the code below! */
double xspace = 0;
double noffset = 0;
double toffset = 0;
//Prevent more than 90% overlap...
}
int nbCopies = 0;
double scaling = 1;
nbCopies = 1;
if (scaling != 1.0) {
x*=scaling;
}
if ( false ) {
y*=(scaling*prop_scale);
} else {
}
x += toffset;
double offs = 0;
for (int i=0; i<nbCopies; i++) {
if (false) {
Geom::Piecewise<Geom::D2<Geom::SBasis> > output_piece = compose(uskeleton,x+offs)+y*compose(n,x+offs);
std::vector<Geom::Piecewise<Geom::D2<Geom::SBasis> > > splited_output_piece = split_at_discontinuities(output_piece);
} else {
}
}
}
return output;
} else {
return pwd2_in;
}
}
void subdivideCurve(Geom::Curve * curve_in, Geom::Coord t, Geom::Curve *& val_first, Geom::Curve *& val_second)
{
switch (order) {
case 3: {
//trimmed_start.append(cb_pair.first);
break;
}
case 2: {
//trimmed_start.append(qb_pair.first);
break;
}
case 1: {
//trimmed_start.append(lb_pair.first);
break;
}
}
}
void LPETaperStroke::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
{
{
_("Start point of the taper"), SP_KNOT_SHAPE_CIRCLE );
knotholder->add(e);
}
{
_("End point of the taper"), SP_KNOT_SHAPE_CIRCLE );
knotholder->add(e);
}
}
namespace TpS {
void KnotHolderEntityAttachBegin::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state)
{
using namespace Geom;
return;
}
//oops
//lpe->attach_start.param_set_value(0);
return;
}
//in case you are wondering, the above are simply sanity checks. we never want to actually
//use that object.
// FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating.
}
void KnotHolderEntityAttachEnd::knot_set(Geom::Point const &p, Geom::Point const& /*origin*/, guint state)
{
using namespace Geom;
return;
}
//oops
//lpe->attach_end.param_set_value(0);
return;
}
}
{
return lpe->start_attach_point;
}
{
return lpe->end_attach_point;
}
}
/* ######################## */
} //namespace LivePathEffect
} /* namespace Inkscape */
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :