lpe-interpolate.cpp revision e5e0e89fd171e5d78721aac368322d3ca26ca883
166N/A#define INKSCAPE_LPE_INTERPOLATE_CPP
166N/A/** \file
166N/A * LPE interpolate implementation
166N/A */
166N/A/*
166N/A * Authors:
166N/A * Johan Engelen
166N/A *
166N/A * Copyright (C) Johan Engelen 2007-2008 <j.b.c.engelen@utwente.nl>
166N/A *
166N/A * Released under GNU GPL, read the file 'COPYING' for more information
166N/A */
166N/A
166N/A#include "live_effects/lpe-interpolate.h"
166N/A
166N/A#include <2geom/path.h>
166N/A#include <2geom/sbasis-to-bezier.h>
166N/A#include <2geom/d2-sbasis.h>
166N/A#include <2geom/piecewise.h>
166N/A#include <2geom/sbasis-geometric.h>
166N/A
166N/A#include "sp-path.h"
3728N/A#include "display/curve.h"
166N/A
166N/Anamespace Inkscape {
166N/Anamespace LivePathEffect {
166N/A
166N/ALPEInterpolate::LPEInterpolate(LivePathEffectObject *lpeobject) :
3728N/A Effect(lpeobject),
166N/A trajectory_path(_("Trajectory:"), _("Path along which intermediate steps are created."), "trajectory", &wr, this, "M0,0 L0,0"),
618N/A number_of_steps(_("Steps_:"), _("Determines the number of steps from start to end path."), "steps", &wr, this, 5),
166N/A equidistant_spacing(_("E_quidistant spacing"), _("If true, the spacing between intermediates is constant along the length of the path. If false, the distance depends on the location of the nodes of the trajectory path."), "equidistant_spacing", &wr, this, true)
3728N/A{
844N/A show_orig_path = true;
3728N/A
166N/A registerParameter( dynamic_cast<Parameter *>(&trajectory_path) );
1258N/A registerParameter( dynamic_cast<Parameter *>(&equidistant_spacing) );
166N/A registerParameter( dynamic_cast<Parameter *>(&number_of_steps) );
3728N/A
2899N/A number_of_steps.param_make_integer();
166N/A number_of_steps.param_set_range(2, NR_HUGE);
166N/A}
166N/A
166N/ALPEInterpolate::~LPEInterpolate()
166N/A{
166N/A
166N/A}
166N/A
166N/A/*
166N/A * interpolate path_in[0] to path_in[1]
166N/A */
166N/AGeom::PathVector
3728N/ALPEInterpolate::doEffect_path (Geom::PathVector const & path_in)
3728N/A{
3728N/A if ( (path_in.size() < 2) || (number_of_steps < 2)) {
3728N/A return path_in;
3728N/A }
3728N/A // Don't allow empty path parameter:
3728N/A if ( trajectory_path.get_pathvector().empty() ) {
3728N/A return path_in;
3728N/A }
3728N/A
3477N/A std::vector<Geom::Path> path_out;
3728N/A
3728N/A Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_A = path_in[0].toPwSb();
3728N/A Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_B = path_in[1].toPwSb();
3728N/A
166N/A // Transform both paths to (0,0) midpoint, so they can easily be positioned along interpolate_path
3728N/A if (Geom::OptRect bounds = Geom::bounds_exact(pwd2_A)) {
166N/A pwd2_A -= bounds->midpoint();
3728N/A }
3728N/A if (Geom::OptRect bounds = Geom::bounds_exact(pwd2_B)) {
3728N/A pwd2_B -= bounds->midpoint();
166N/A }
166N/A
166N/A // Make sure both paths have the same number of segments and cuts at the same locations
166N/A pwd2_B.setDomain(pwd2_A.domain());
Geom::Piecewise<Geom::D2<Geom::SBasis> > pA = Geom::partition(pwd2_A, pwd2_B.cuts);
Geom::Piecewise<Geom::D2<Geom::SBasis> > pB = Geom::partition(pwd2_B, pwd2_A.cuts);
Geom::Piecewise<Geom::D2<Geom::SBasis> > trajectory = trajectory_path.get_pathvector()[0].toPwSb();
if (equidistant_spacing)
trajectory = Geom::arc_length_parametrization(trajectory);
Geom::Interval trajectory_domain = trajectory.domain();
for (int i = 0; i < number_of_steps; ++i) {
double fraction = i / (number_of_steps-1);
Geom::Piecewise<Geom::D2<Geom::SBasis> > pResult = pA*(1-fraction) + pB*fraction;
pResult += trajectory.valueAt(trajectory_domain.min() + fraction*trajectory_domain.extent());
Geom::PathVector pathv = Geom::path_from_piecewise(pResult, LPE_CONVERSION_TOLERANCE);
path_out.push_back( pathv[0] );
}
return path_out;
}
void
LPEInterpolate::resetDefaults(SPItem * item)
{
Effect::resetDefaults(item);
if (!SP_IS_PATH(item))
return;
SPCurve const *crv = sp_path_get_curve_reference(SP_PATH(item));
Geom::PathVector const &pathv = crv->get_pathvector();
if ( (pathv.size() < 2) )
return;
Geom::OptRect bounds_A = pathv[0].boundsExact();
Geom::OptRect bounds_B = pathv[1].boundsExact();
if (bounds_A && bounds_B) {
Geom::PathVector traj_pathv;
traj_pathv.push_back( Geom::Path() );
traj_pathv[0].start( bounds_A->midpoint() );
traj_pathv[0].appendNew<Geom::LineSegment>( bounds_B->midpoint() );
trajectory_path.set_new_value( traj_pathv, true );
} else {
trajectory_path.param_set_and_write_default();
}
}
} //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 :