Difference between revisions of "Inkscape/liveeffectsgoodness"

From Inkscape Wiki
Jump to navigation Jump to search
 
(Redirecting to LivePathEffects)
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
BByak's email detailing pathe effects stage II
#REDIRECT [[LivePathEffects]]
 
Overall, our Stage II goals are:
 
1. make the system capable of handling several different effects,
with new ones easy to add
 
2. make sure effects are correctly read in SPPath and in all
shapes
 
3. make sure objects with effects are correctly transformed
 
4. make sure paths with effects are correctly node-edited
 
5. make sure shapes with effects are correctly handle-edited
 
6. make sure objects with effects are correctly written and
rendered the same in Batik
 
Most of these goals are surprisingly easy to achieve  :)  So don't
be frightened by the length of this email - it's just wordy
explanations.
 
After all this works, we can move on to implementing the Path
Effects tool and handle-dragging UI for editing effects on
canvas... that will be Stage III.
 
Now, the goals in detail:
 
1. Rename inkscape:distorted into inkscape:path-effect. This
attribute would store a string identifier of the effect to apply,
or "none". If there's no such attribute, it's the same as
"none". In addition, register several attributes for distortion
parameters:
 
inkscape:path-effect-param1
inkscape:path-effect-param2
inkscape:path-effect-param3
 
etc. The interpretation of these will of course depend on the
value of inkscape:path-effect.
 
Then, move the reading of these attributes into SPShape, as they
will be used by all its subclasses (not only SPPath but also
shapes) in the same way. (That is, sp_object_read_attr(object,
"inkscape:path-effect") etc must also be in sp_shape_build.)
Store the values in appropriate new members of SPShape. Write a
generic function that takes SPCurve and a SPShape pointers and
distorts the SPCurve according to the values of the members of
SPShape. Store that function in sp-shape.cpp and declare in
sp-shape.h so that it can be used from outside.
 
You can even code a couple useful effects at this stage  :)
 
2. For SPPath, it's all ready: it reads original-d, distorts it
and sets the curve from that. In shapes, it's even simpler. Take
SPStar for an example. In sp-star.cpp, find the line
 
sp_shape_set_curve_insync (SP_SHAPE (star), c, TRUE);
 
and just insert the call to the distortion function in sp-shape
before that, passing it the curve and SP_SHAPE (star). That is
all! Shapes have no need for original-d because their path is
generated from the shape parameters anyway.
 
3. Transforming objects works like this. In "preserve" mode (see
Inkscape Prefs), a transform= attribute is added or edited on all
transformed objects. In the "optimize" mode (which is the
default), various types of objects variously try to embed the
transform, or a component thereof. If this is not possible, again,
transform= attribute is added. For example, for paths,
sp_path_transform can completely embed all of the transform into
its curve (i.e. into d=), by transforming each path point by that
matrix, so it returns identity and transform= is not set. For
rects, sp_rect_set_transform embeds only translation and scaling
components of the matrix; the remainder, if any, is written as
transform=. For stars and ellipses, no embedding is attempted at
all, so the whole transform is always written as transform=.
 
Now, for paths, sp_path_transform currently transforms the
(SPShape*)path->curve, i.e. the distorted curve stored in base
SPShape instance. But we also need to transform the original path
by the same matrix too, so that it stays in sync. The easiest way
to do this, which will also have other benefits, is to store the
original path in SPPath as another SPCurve. That is,
(SPShape*)path->curve will be the distorted path, while
(SPPath*)path->original_curve will store the original path.
 
You will thus need to add this member in sp-path.h and to add to
store the original SPCurve before distortion in that member in
sp_path_set, case SP_ATTR_ORIGINAL_D. (You may need to figure out
how to copy SPCurves and/or bpaths. Also don't forget to free the
SPCurve when destroying the path in sp_path_release.) Then look at
sp_path_transform:
 
    /* Transform the path */
    NRBPath dpath, spath;
    spath.path = shape->curve->bpath;
    nr_path_duplicate_transform(&dpath, &spath, xform);
    SPCurve *curve = sp_curve_new_from_bpath(dpath.path);
    if (curve) {
        sp_shape_set_curve(shape, curve, TRUE);
        sp_curve_unref(curve);
    }
 
And just do the same also for your original SPCurve stored in
SPPath. That is all.
 
For shapes, you normally don't need to do anything at all. Those
that don't attempt any embedding and always use transform=
attribute are not affected at all. Those that do embed do it just
by adjusting their internal shape parameters and regenerating the
curve - for example sp_rect_set_transform calls
sp_rect_set_shape(rect). Provided you inserted a distortion call
into *_set_shape, you are all set.
 
CAVEAT: rects are the only shape which currently uses <rect>, not
<path>. So you cannot apply shape effects to rects at all, until
this is changed. It's on my TODO for a long time, hope I will get
a round tuit soon.
 
4. The Inkscape::NodePath::Path reads the path from SPCurve, but
after modifying it, it writes directly to the d= attribute. This
needs to be changed thus: (a) if the path is distorted, read the
SPCurve from SPPath, not from SPShape (i.e. the original, not the
distorted one), and (b) if the path is distorted, write the edited
path to inkscape:original-d= instead of d= (in
update_repr_internal). Setting inkscape:original-d will trigger
reading it and setting both original and distorted curves, the
latter in turn triggering a redisplay of the distorted path. So I
think this will be enough for nodepath to edit the source path,
with the nodes generally not lying on the visible distorted
path. Adding a helper display of the original path between
nodepath nodes can be left for later.
 
5. I think here nothing at all is needed. The knotholder thing
reads and writes from the shape's internal parameters, and thus is
totally unaffected by the visible distorted path.
 
6. Look at sp_path_write: it writes the d= attribute from
(SPShape*)path->curve, that is, from the distorted path. So the
"same display in Batik" part is already taken care of. We only
need to write the original-d so it stays in sync. Just repeat this
block:
 
    if ( shape->curve != NULL ) {
        NArtBpath *abp = sp_curve_first_bpath(shape->curve);
        if (abp) {
            gchar *str = sp_svg_write_path(abp);
            sp_repr_set_attr(repr, "d", str);
            g_free(str);
        } else {
            sp_repr_set_attr(repr, "d", "");
        }
    } else {
        sp_repr_set_attr(repr, "d", NULL);
    }
 
but for path->original_curve and the inkscape:original-d
attribute, and you are all set.
 
For shapes, again, nothing needs to be done. Except for rects,
shapes' _write methods (e.g. sp_star_write) create <path> element
and set its d= from the SPShape curve. This is just what we need.
 
That is all - as you see, it's all quite simple, logical and fits
neatly. There will be gotchas of course, but overall the system
looks quite straightforward and robust. I'm really excited by
this.

Latest revision as of 19:11, 9 March 2007

Redirect to: