~ubuntu-branches/debian/experimental/inkscape/experimental

« back to all changes in this revision

Viewing changes to src/live_effects/lpe-curvestitch.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Viehmann
  • Date: 2008-09-09 23:29:02 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20080909232902-c50iujhk1w79u8e7
Tags: 0.46-2.1
* Non-maintainer upload.
* Add upstream patch fixing a crash in the open dialog
  in the zh_CN.utf8 locale. Closes: #487623.
  Thanks to Luca Bruno for the patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#define INKSCAPE_LPE_CURVESTITCH_CPP
 
2
/** \file
 
3
 * LPE Curve Stitching implementation, used as an example for a base starting class
 
4
 * when implementing new LivePathEffects.
 
5
 *
 
6
 */
 
7
/*
 
8
 * Authors:
 
9
 *   Johan Engelen
 
10
*
 
11
* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
 
12
 *
 
13
 * Released under GNU GPL, read the file 'COPYING' for more information
 
14
 */
 
15
 
 
16
#include "live_effects/lpe-curvestitch.h"
 
17
#include "display/curve.h"
 
18
#include <libnr/n-art-bpath.h>
 
19
#include "sp-item.h"
 
20
#include "sp-path.h"
 
21
#include "live_effects/n-art-bpath-2geom.h"
 
22
 
 
23
#include <2geom/path.h>
 
24
#include <2geom/piecewise.h>
 
25
#include <2geom/sbasis.h>
 
26
#include <2geom/sbasis-geometric.h>
 
27
#include <2geom/bezier-to-sbasis.h>
 
28
#include <2geom/sbasis-to-bezier.h>
 
29
#include <2geom/d2.h>
 
30
#include <2geom/matrix.h>
 
31
 
 
32
 
 
33
#include "ui/widget/scalar.h"
 
34
#include "libnr/nr-values.h"
 
35
 
 
36
namespace Inkscape {
 
37
namespace LivePathEffect {
 
38
 
 
39
using namespace Geom;
 
40
 
 
41
LPECurveStitch::LPECurveStitch(LivePathEffectObject *lpeobject) :
 
42
    Effect(lpeobject),
 
43
    strokepath(_("Stroke path"), _("The path that will be used as stitch."), "strokepath", &wr, this, "M0,0 L1,0"),
 
44
    nrofpaths(_("Number of paths"), _("The number of paths that will be generated."), "count", &wr, this, 5),
 
45
    startpoint_edge_variation(_("Start edge variance"), _("The amount of random jitter to move the start points of the stitches inside & outside the guide path"), "startpoint_edge_variation", &wr, this, 0),
 
46
    startpoint_spacing_variation(_("Start spacing variance"), _("The amount of random shifting to move the start points of the stitches back & forth along the guide path"), "startpoint_spacing_variation", &wr, this, 0),
 
47
    endpoint_edge_variation(_("End edge variance"), _("The amount of randomness that moves the end points of the stitches inside & outside the guide path"), "endpoint_edge_variation", &wr, this, 0),
 
48
    endpoint_spacing_variation(_("End spacing variance"), _("The amount of random shifting to move the end points of the stitches back & forth along the guide path"), "endpoint_spacing_variation", &wr, this, 0),
 
49
    prop_scale(_("Scale width"), _("Scaling of the width of the stroke path"), "prop_scale", &wr, this, 1),
 
50
    scale_y_rel(_("Scale width relative"), _("Scale the width of the stroke path relative to its length"), "scale_y_rel", &wr, this, false)
 
51
{
 
52
    registerParameter( dynamic_cast<Parameter *>(&nrofpaths) );
 
53
    registerParameter( dynamic_cast<Parameter *>(&startpoint_edge_variation) );
 
54
    registerParameter( dynamic_cast<Parameter *>(&startpoint_spacing_variation) );
 
55
    registerParameter( dynamic_cast<Parameter *>(&endpoint_edge_variation) );
 
56
    registerParameter( dynamic_cast<Parameter *>(&endpoint_spacing_variation) );
 
57
    registerParameter( dynamic_cast<Parameter *>(&strokepath) );
 
58
    registerParameter( dynamic_cast<Parameter *>(&prop_scale) );
 
59
    registerParameter( dynamic_cast<Parameter *>(&scale_y_rel) );
 
60
 
 
61
    nrofpaths.param_make_integer();
 
62
    nrofpaths.param_set_range(2, NR_HUGE);
 
63
 
 
64
    prop_scale.param_set_digits(3);
 
65
    prop_scale.param_set_increments(0.01, 0.10);
 
66
}
 
67
 
 
68
LPECurveStitch::~LPECurveStitch()
 
69
{
 
70
 
 
71
}
 
72
 
 
73
std::vector<Geom::Path>
 
74
LPECurveStitch::doEffect_path (std::vector<Geom::Path> & path_in)
 
75
{
 
76
    if (path_in.size() >= 2) {
 
77
        startpoint_edge_variation.resetRandomizer();
 
78
        endpoint_edge_variation.resetRandomizer();
 
79
        startpoint_spacing_variation.resetRandomizer();
 
80
        endpoint_spacing_variation.resetRandomizer();
 
81
 
 
82
        D2<Piecewise<SBasis> > stroke = make_cuts_independant(strokepath);
 
83
        Interval bndsStroke = bounds_exact(stroke[0]);
 
84
        gdouble scaling = bndsStroke.max() - bndsStroke.min();
 
85
        Interval bndsStrokeY = bounds_exact(stroke[1]);
 
86
        Point stroke_origin(bndsStroke.min(), (bndsStrokeY.max()+bndsStrokeY.min())/2);
 
87
 
 
88
        std::vector<Geom::Path> path_out;
 
89
 
 
90
        // do this for all permutations (ii,jj) if there are more than 2 paths? realllly cool!
 
91
        for (int ii = 0   ; ii < path_in.size() - 1; ii++)
 
92
        for (int jj = ii+1; jj < path_in.size(); jj++)
 
93
        {
 
94
            Piecewise<D2<SBasis> > A = arc_length_parametrization(Piecewise<D2<SBasis> >(path_in[ii].toPwSb()),2,.1);
 
95
            Piecewise<D2<SBasis> > B = arc_length_parametrization(Piecewise<D2<SBasis> >(path_in[jj].toPwSb()),2,.1);
 
96
            Interval bndsA = A.domain();
 
97
            Interval bndsB = B.domain();
 
98
            gdouble incrementA = (bndsA.max()-bndsA.min()) / (nrofpaths-1);
 
99
            gdouble incrementB = (bndsB.max()-bndsB.min()) / (nrofpaths-1);
 
100
            gdouble tA = bndsA.min();
 
101
            gdouble tB = bndsB.min();
 
102
            gdouble tAclean = tA; // the tA without spacing_variation
 
103
            gdouble tBclean = tB; // the tB without spacing_variation
 
104
 
 
105
            for (int i = 0; i < nrofpaths; i++) {
 
106
                Point start = A(tA);
 
107
                Point end = B(tB);
 
108
                if (startpoint_edge_variation.get_value() != 0)
 
109
                    start = start + (startpoint_edge_variation - startpoint_edge_variation.get_value()/2) * (end - start);
 
110
                if (endpoint_edge_variation.get_value() != 0)
 
111
                    end = end + (endpoint_edge_variation - endpoint_edge_variation.get_value()/2)* (end - start);
 
112
        
 
113
                if (!Geom::are_near(start,end)) {
 
114
                    gdouble scaling_y = 1.0;
 
115
                    if (scale_y_rel.get_value()) {
 
116
                        scaling_y = (L2(end-start)/scaling)*prop_scale;
 
117
                    } else {
 
118
                        scaling_y = prop_scale;
 
119
                    }
 
120
 
 
121
                    Matrix transform;
 
122
                    transform.setXAxis( (end-start) / scaling );
 
123
                    transform.setYAxis( rot90(unit_vector(end-start)) * scaling_y);
 
124
                    transform.setTranslation( start );
 
125
                    Piecewise<D2<SBasis> > pwd2_out = (strokepath-stroke_origin) * transform;
 
126
 
 
127
                    // add stuff to one big pw<d2<sbasis> > and then outside the loop convert to path?
 
128
                    // No: this way, the separate result paths are kept separate which might come in handy some time!
 
129
                    std::vector<Geom::Path> result = Geom::path_from_piecewise(pwd2_out, LPE_CONVERSION_TOLERANCE);
 
130
                    path_out.push_back(result[0]);
 
131
                }
 
132
                gdouble svA = startpoint_spacing_variation - startpoint_spacing_variation.get_value()/2;
 
133
                gdouble svB = endpoint_spacing_variation - endpoint_spacing_variation.get_value()/2;
 
134
                tAclean += incrementA;
 
135
                tBclean += incrementB;
 
136
                tA = tAclean + incrementA * svA;
 
137
                tB = tBclean + incrementB * svB;
 
138
                if (tA > bndsA.max())
 
139
                    tA = bndsA.max();
 
140
                if (tB > bndsB.max())
 
141
                    tB = bndsB.max();
 
142
            }
 
143
        }
 
144
 
 
145
        return path_out;
 
146
    } else {
 
147
        return path_in;
 
148
    }
 
149
}
 
150
 
 
151
void
 
152
LPECurveStitch::resetDefaults(SPItem * item)
 
153
{
 
154
    if (!SP_IS_PATH(item)) return;
 
155
 
 
156
    using namespace Geom;
 
157
 
 
158
    // set the stroke path to run horizontally in the middle of the bounding box of the original path
 
159
    Piecewise<D2<SBasis> > pwd2;
 
160
    std::vector<Geom::Path> temppath = SVGD_to_2GeomPath( SP_OBJECT_REPR(item)->attribute("inkscape:original-d"));
 
161
    for (unsigned int i=0; i < temppath.size(); i++) {
 
162
        pwd2.concat( temppath[i].toPwSb() );
 
163
    }
 
164
 
 
165
    D2<Piecewise<SBasis> > d2pw = make_cuts_independant(pwd2);
 
166
    Interval bndsX = bounds_exact(d2pw[0]);
 
167
    Interval bndsY = bounds_exact(d2pw[1]);
 
168
    Point start(bndsX.min(), (bndsY.max()+bndsY.min())/2);
 
169
    Point end(bndsX.max(), (bndsY.max()+bndsY.min())/2);
 
170
 
 
171
    if ( !Geom::are_near(start,end) ) {
 
172
        Geom::Path path;
 
173
        path.start( start );
 
174
        path.appendNew<Geom::LineSegment>( end );
 
175
        strokepath.param_set_and_write_new_value( path.toPwSb() );
 
176
    } else {
 
177
        // bounding box is too small to make decent path. set to default default. :-)
 
178
        strokepath.param_set_and_write_default();
 
179
    }
 
180
}
 
181
 
 
182
void
 
183
LPECurveStitch::transform_multiply(Geom::Matrix const& postmul, bool set)
 
184
{
 
185
    // only take translations into account
 
186
    if (postmul.isTranslation()) {
 
187
        strokepath.param_transform_multiply(postmul, set);
 
188
    } else if (!scale_y_rel.get_value()) {
 
189
  // this basically means that for this transformation, the result should be the same as normal scaling the result path
 
190
  // don't know how to do this yet.
 
191
//        Geom::Matrix new_postmul;
 
192
        //new_postmul.setIdentity();
 
193
//        new_postmul.setTranslation(postmul.translation());
 
194
//        Effect::transform_multiply(new_postmul, set);
 
195
    }
 
196
}
 
197
 
 
198
} //namespace LivePathEffect
 
199
} /* namespace Inkscape */
 
200
 
 
201
/*
 
202
  Local Variables:
 
203
  mode:c++
 
204
  c-file-style:"stroustrup"
 
205
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
206
  indent-tabs-mode:nil
 
207
  fill-column:99
 
208
  End:
 
209
*/
 
210
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :