Difference between revisions of "Creating Live Path Effects"
Johanengelen (talk | contribs) |
(cat) |
||
(19 intermediate revisions by 5 users not shown) | |||
Line 3: | Line 3: | ||
=How does LPE work?= | =How does LPE work?= | ||
The following schematic tries to explain how LPE work. | |||
original style ------------> output style | |||
original path --> LPE --> output path | |||
^ | |||
| | |||
parameters | |||
=Groundwork | The original style and path are from the path that the effect is applied on. The output is what is visible on screen. What is very important to notice is that <b>output style equals original style</b>. | ||
The parameters can be paths, numbers, points, text, in principle anything. | |||
=Groundwork= | |||
It is best to put your new effect in the /live_effects directory. Copy lpe-skeleton.cpp and lpe-skeleton.h to your files (say lpe-youreffect.cpp and lpe-youreffect.h), and rename everything from <i>skeleton</i> to your name. | It is best to put your new effect in the /live_effects directory. Copy lpe-skeleton.cpp and lpe-skeleton.h to your files (say lpe-youreffect.cpp and lpe-youreffect.h), and rename everything from <i>skeleton</i> to your name. | ||
In effect.h: | In effect-enum.h: | ||
Add your effect to the enumeration: "enum EffectType". This way, Inkscape knows how to refer to your effect. | Add your effect to the enumeration: "enum EffectType". This way, Inkscape knows how to refer to your effect. | ||
Line 33: | Line 43: | ||
That's all! Now your effect should pop up in the LivePathEffect dialog in Inkscape! But your effect won't do anything now, it would just pass along the original path. Time to start writing the main machinery of your cool effect! | That's all! Now your effect should pop up in the LivePathEffect dialog in Inkscape! But your effect won't do anything now, it would just pass along the original path. Time to start writing the main machinery of your cool effect! | ||
=Write your effect= | |||
=Write your effect | |||
The effect code should go into a doEffect function. The doEffect function receives the original path, and should return the path that results from your effect. | The effect code should go into a doEffect function. The doEffect function receives the original path, and should return the path that results from your effect. | ||
Line 50: | Line 51: | ||
These are the doEffect functions in the order in which they are called: | These are the doEffect functions in the order in which they are called: | ||
1 | 1) void doEffect (SPCurve * curve)<br> | ||
2 | 2) std::vector<Geom::Path> doEffect_path (std::vector<Geom::Path> & path_in)<br> | ||
3) Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > & pwd2_in) | |||
It is easy to replace the standard doEffect function with yours. Let's say you want to create your effect with the path types of the 3rd function. You have to declare that one for your effect in lpe-youreffect.h: they are already writting down in there, you just have to un-comment the one you want, and you can delete the other doEffect functions. You must do the same in lpe-youreffect.cpp. | It is easy to replace the standard doEffect function with yours. Let's say you want to create your effect with the path types of the 3rd function. You have to declare that one for your effect in lpe-youreffect.h: they are already writting down in there, you just have to un-comment the one you want, and you can delete the other doEffect functions. You must do the same in lpe-youreffect.cpp. | ||
A "copy" effect has already been put in the .cpp file, you have to spice that up to make it do what you want. It is best to have a look at the doEffect functions of | The first 2 doEffect_xxxs receive the full <svg:path>, the 3rd (_pwd2) only continuous paths. What happens is that the default std::vector<Geom::Path> doEffect_path function splits the path into continuous parts (if there are more) and calls doEffect_pwd2 for each path part; then it combines the results again into its output std::vector<Geom::Path>. If you do not want this behavior but would like to use _pwd2, you must set the 'concatenate_before_pwd2' boolean to true in the constructor of your effect (see for example LPEBendPath). | ||
A "copy" effect has already been put in the .cpp file, you have to spice that up to make it do what you want. It is best to have a look at the doEffect functions of other effects and lpe-skeleton.cpp to see what is possible and how to implement something! | |||
=Parameter types:= | =Parameter types:= | ||
Line 89: | Line 91: | ||
* <b>RandomParam</b>: <br> | * <b>RandomParam</b>: <br> | ||
include "live_effects/parameter/random.h"<br> | include "live_effects/parameter/random.h"<br> | ||
This gives a random value between 0 and the value set by the user. See how to use it in lpe-curvestitch.cpp) | |||
* <b>PointParam</b>: a parameter that describes a coordinate on the page. <br> | * <b>PointParam</b>: a parameter that describes a coordinate on the page. <br> | ||
include "live_effects/parameter/point.h"<br> | include "live_effects/parameter/point.h"<br> | ||
The parameters will automatically appear in the Live Path Effects dialog! | The parameters will automatically appear in the Live Path Effects dialog! | ||
=LPE on group : get the entire bounding box= | |||
Some effects, such as [[Bend_Path|Bend Path]], need the information of the size of the entire Bounding Box of the item on which the effect is applied. | |||
How to get the Bounding box of the item ? | |||
in ''lpe-YourEffect.h :'' | |||
#include "live_effects/lpegroupbbox.h" | |||
Then inherit from GroupBBoxEffect : | |||
class LPESkeleton : public Effect, GroupBBoxEffect { | |||
Now we can use the ''original_bbox(SPLPEItem *)'' method. | |||
When it is called, it stores the bounding box dimensions in ''Geom::Interval boundingbox_X'' and ''Geom::Interval boundingbox_Y''. So let's call it before the calculation of the effect : | |||
- Overload the ''doBeforeEffect'' method | |||
'''lpe-YourEffect.h''' : | |||
virtual void doBeforeEffect (SPLPEItem *lpeitem); | |||
'''lpe-YourEffect.cpp''' : | |||
void | |||
LPEBendPath::doBeforeEffect (SPLPEItem *lpeitem) | |||
{ | |||
original_bbox(lpeitem); | |||
} | |||
And to set defaults values : | |||
- the ''reset Defaults'' method | |||
'''lpe-YourEffect.h :''' | |||
virtual void resetDefaults(SPItem * item); | |||
'''lpe-YourEffect.cpp :''' | |||
void | |||
LPEBendPath::resetDefaults(SPItem * item) | |||
{ | |||
original_bbox(SP_LPE_ITEM(item)); | |||
} | |||
=Examples and details= | |||
*[[Bend Path]] | |||
*[[Envelope Deformation]] | |||
*[[Latice Deformation]] | |||
[[Category:Developer Documentation]] | [[Category:Developer Documentation]] | ||
[[Category:LPE]] |
Latest revision as of 22:05, 28 February 2012
Instructions for making Live Path Effects.
How does LPE work?
The following schematic tries to explain how LPE work.
original style ------------> output style original path --> LPE --> output path ^ | parameters
The original style and path are from the path that the effect is applied on. The output is what is visible on screen. What is very important to notice is that output style equals original style.
The parameters can be paths, numbers, points, text, in principle anything.
Groundwork
It is best to put your new effect in the /live_effects directory. Copy lpe-skeleton.cpp and lpe-skeleton.h to your files (say lpe-youreffect.cpp and lpe-youreffect.h), and rename everything from skeleton to your name.
In effect-enum.h: Add your effect to the enumeration: "enum EffectType". This way, Inkscape knows how to refer to your effect.
In effect.cpp:
-Add #include "live_effects/lpe-youreffect.h" (below //include effects )
-Add your effect to the "const Util::EnumData<EffectType> LPETypeData[INVALID_LPE]" array. This way, Inkscape knows how to tell the user what the name of the effect is and also how to write its name to SVG.
-Tell inkscape how to create it by inserting it in
... Effect* Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) ... case YOUREFFECT: neweffect = (Effect*) new LPEYourEffect(lpeobj); break; ... ...
.
One more thing to do: add your files to /live_effects/Makefile_insert. (Be aware of the spaces and tabs in that file!)
That's all! Now your effect should pop up in the LivePathEffect dialog in Inkscape! But your effect won't do anything now, it would just pass along the original path. Time to start writing the main machinery of your cool effect!
Write your effect
The effect code should go into a doEffect function. The doEffect function receives the original path, and should return the path that results from your effect.
You have to choose between 4 doEffect functions and implement just one of them. There is a "chain" of these functions. The first doEffect function calls the second, which calls the 3rd, which calls the 4th. The 4th returns its result to the 3rd which returns its result to the 2nd which returns it to the first and finally Inkscape receives the result. But all these standard functions do nothing real, they just change the path from one type to another. You have to determine which type is most convenient for you and overload that function. This means you put your own doEffect function in the place where normally the standard function would be called.
These are the doEffect functions in the order in which they are called:
1) void doEffect (SPCurve * curve)
2) std::vector<Geom::Path> doEffect_path (std::vector<Geom::Path> & path_in)
3) Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > & pwd2_in)
It is easy to replace the standard doEffect function with yours. Let's say you want to create your effect with the path types of the 3rd function. You have to declare that one for your effect in lpe-youreffect.h: they are already writting down in there, you just have to un-comment the one you want, and you can delete the other doEffect functions. You must do the same in lpe-youreffect.cpp.
The first 2 doEffect_xxxs receive the full <svg:path>, the 3rd (_pwd2) only continuous paths. What happens is that the default std::vector<Geom::Path> doEffect_path function splits the path into continuous parts (if there are more) and calls doEffect_pwd2 for each path part; then it combines the results again into its output std::vector<Geom::Path>. If you do not want this behavior but would like to use _pwd2, you must set the 'concatenate_before_pwd2' boolean to true in the constructor of your effect (see for example LPEBendPath).
A "copy" effect has already been put in the .cpp file, you have to spice that up to make it do what you want. It is best to have a look at the doEffect functions of other effects and lpe-skeleton.cpp to see what is possible and how to implement something!
Parameter types:
Your effect can have any number of parameters that you'd like. You have to define them in the .h file. "RealParam number" is already there in the skeleton file; you can delete this if you do not want that kind of parameter ofcourse. That is the location where you can put the parameters that you want.
You also have to initialise and register them, so Inkscape knows about them. This you should do in the .cpp file:
// initialise your parameters here: number(_("Float parameter"), _("just a real number like 1.4!"), "svgname", &wr, this, 1.2)
The arguments are respectively, the name of the parameter in the UI, the tooltip text, the name of the parameter in SVG, 2 parameters that you don't have to bother about (they are always the same), and finally the default value. You can also omit the default value.
And these lines register your parameter:
// register all your parameters here, so Inkscape knows which parameters this effect has: registerParameter( dynamic_cast<Parameter *>(&number) );
Available parameter types
Check the /live_effects/parameter dir for more up-to-date info; perhaps some parameter types were added! You have to include the .h file that belongs to the parameter type in your own .h file to be able to use that parameter type.
- ScalarParam: a number of type 'gdouble'.
include "live_effects/parameter/parameter.h"
(see lpe-slant.cpp to learn how to use this type)
- PathParam: a parameter that is a path. This is a single path! If the input for this parameter are multiple paths, it is converted to just one path.
include "live_effects/parameter/path.h"
(see lpe-skeletal.cpp to learn how to use this type)
- EnumParam: a parameter that lets the user choose between a number of options from a dropdown box.
include "live_effects/parameter/enum.h"
(see lpe-skeletal.cpp to learn how to use this type)
- BoolParam:
include "live_effects/parameter/bool.h"
- RandomParam:
include "live_effects/parameter/random.h"
This gives a random value between 0 and the value set by the user. See how to use it in lpe-curvestitch.cpp)
- PointParam: a parameter that describes a coordinate on the page.
include "live_effects/parameter/point.h"
The parameters will automatically appear in the Live Path Effects dialog!
LPE on group : get the entire bounding box
Some effects, such as Bend Path, need the information of the size of the entire Bounding Box of the item on which the effect is applied.
How to get the Bounding box of the item ?
in lpe-YourEffect.h :
#include "live_effects/lpegroupbbox.h"
Then inherit from GroupBBoxEffect :
class LPESkeleton : public Effect, GroupBBoxEffect {
Now we can use the original_bbox(SPLPEItem *) method. When it is called, it stores the bounding box dimensions in Geom::Interval boundingbox_X and Geom::Interval boundingbox_Y. So let's call it before the calculation of the effect :
- Overload the doBeforeEffect method
lpe-YourEffect.h :
virtual void doBeforeEffect (SPLPEItem *lpeitem);
lpe-YourEffect.cpp :
void LPEBendPath::doBeforeEffect (SPLPEItem *lpeitem) { original_bbox(lpeitem); }
And to set defaults values :
- the reset Defaults method lpe-YourEffect.h :
virtual void resetDefaults(SPItem * item);
lpe-YourEffect.cpp :
void LPEBendPath::resetDefaults(SPItem * item) { original_bbox(SP_LPE_ITEM(item)); }