summaryrefslogtreecommitdiffstats
path: root/src/live_effects/lpe-interpolate.cpp
blob: a4c722acc99e8b684ac413f2429d2b91cae33875 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#define INKSCAPE_LPE_INTERPOLATE_CPP
/** \file
 * LPE interpolate implementation
 */
/*
 * Authors:
 *   Johan Engelen
 *
 * Copyright (C) Johan Engelen 2007-2008 <j.b.c.engelen@utwente.nl>
 *
 * Released under GNU GPL, read the file 'COPYING' for more information
 */

#include "live_effects/lpe-interpolate.h"

#include <2geom/path.h>
#include <2geom/sbasis-to-bezier.h>
#include <2geom/d2-sbasis.h>
#include <2geom/piecewise.h>
#include <2geom/sbasis-geometric.h>

#include "sp-path.h"
#include "display/curve.h"

namespace Inkscape {
namespace LivePathEffect {

LPEInterpolate::LPEInterpolate(LivePathEffectObject *lpeobject) :
    Effect(lpeobject),
    trajectory_path(_("Trajectory"), _("Path along which intermediate steps are created."), "trajectory", &wr, this, "M0,0 L0,0"),
    number_of_steps(_("Steps"), _("Determines the number of steps from start to end path."), "steps", &wr, this, 5),
    equidistant_spacing(_("Equidistant 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)
{
    show_orig_path = true;

    registerParameter( dynamic_cast<Parameter *>(&trajectory_path) );
    registerParameter( dynamic_cast<Parameter *>(&equidistant_spacing) );
    registerParameter( dynamic_cast<Parameter *>(&number_of_steps) );

    number_of_steps.param_make_integer();
    number_of_steps.param_set_range(2, NR_HUGE);
}

LPEInterpolate::~LPEInterpolate()
{

}

/*
 * interpolate path_in[0] to path_in[1]
 */
Geom::PathVector
LPEInterpolate::doEffect_path (Geom::PathVector const & path_in)
{
    if ( (path_in.size() < 2) || (number_of_steps < 2))
        return path_in;

    std::vector<Geom::Path> path_out;

    Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_A = path_in[0].toPwSb();
    Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_B = path_in[1].toPwSb();

    // Transform both paths to (0,0) midpoint, so they can easily be positioned along interpolate_path
    pwd2_A -= Geom::bounds_exact(pwd2_A).midpoint();
    pwd2_B -= Geom::bounds_exact(pwd2_B).midpoint();

    // Make sure both paths have the same number of segments and cuts at the same locations
    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)
{
    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::Rect bounds_A = pathv[0].boundsExact();
    Geom::Rect bounds_B = pathv[1].boundsExact();

    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 );
}

} //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 :