18#include <glibmm/i18n.h>
25namespace LivePathEffect {
37 std::pair<unsigned,unsigned> next_on_curve;
38 std::pair<unsigned,unsigned> prev_on_curve;
40struct LevelCrossingOrder {
41 bool operator()(LevelCrossing a, LevelCrossing b) {
42 return ( a.pt[
Y] < b.pt[
Y] );
46struct LevelCrossingInfo{
51struct LevelCrossingInfoOrder {
52 bool operator()(LevelCrossingInfo a, LevelCrossingInfo b) {
59static std::vector<double>
61 std::vector<double>
result;
62 if (f.size()==0)
return result;
63 result.push_back(f.cuts[0]);
64 Point prev_pt = f.segs[0].at1();
66 for(
unsigned i=1; i<f.size(); i++){
67 if ( f.segs[i].at0()!=prev_pt){
68 result.push_back(f.cuts[i]);
72 prev_pt = f.segs[i].at1();
74 result.push_back(f.cuts.back());
79class LevelsCrossings:
public std::vector<LevelCrossings>{
82 LevelsCrossings(std::vector<std::vector<double> >
const ×,
86 for (
const auto & time : times){
88 for (
double j : time){
96 std::sort(lcs.begin(), lcs.end(), LevelCrossingOrder());
100 std::vector<LevelCrossingInfo>temp;
101 for (
unsigned i=0; i<
size(); i++){
102 for (
unsigned j=0; j<(*this)[i].size(); j++){
103 LevelCrossingInfo elem;
104 elem.t = (*this)[i][j].t;
107 temp.push_back(elem);
110 std::sort(temp.begin(),temp.end(),LevelCrossingInfoOrder());
112 unsigned jump_idx = 0;
113 unsigned first_in_comp = 0;
114 for (
unsigned i=0; i<temp.size(); i++){
115 unsigned lvl = temp[i].level, idx = temp[i].idx;
116 if ( i == temp.size()-1 || temp[i+1].t > jumps[jump_idx+1]){
117 std::pair<unsigned,unsigned>next_data(temp[first_in_comp].level,temp[first_in_comp].idx);
118 (*this)[lvl][idx].next_on_curve = next_data;
122 std::pair<unsigned,unsigned> next_data(temp[i+1].level,temp[i+1].idx);
123 (*this)[lvl][idx].next_on_curve = next_data;
127 for (
unsigned i=0; i<
size(); i++){
128 for (
unsigned j=0; j<(*this)[i].size(); j++){
129 std::pair<unsigned,unsigned> next = (*this)[i][j].next_on_curve;
130 (*this)[next.first][next.second].prev_on_curve = std::pair<unsigned,unsigned>(i,j);
135 void findFirstUnused(
unsigned &level,
unsigned &idx){
138 for (
unsigned i=0; i<
size(); i++){
139 for (
unsigned j=0; j<(*this)[i].size(); j++){
140 if (!(*
this)[i][j].used){
154 void step(
unsigned &level,
unsigned &idx,
int &direction){
155 if ( direction % 2 == 0 ){
156 if (direction == 0) {
157 if ( idx >= (*
this)[level].
size()-1 || (*
this)[level][idx+1].
used ) {
163 if ( idx <= 0 || (*
this)[level][idx-1].
used ) {
173 double sign = ((*this)[level][idx].sign ? 1 : -1);
176 direction = (direction + 1)%4;
177 if (level ==
size()){
181 std::pair<unsigned,unsigned> next;
183 next = (*this)[level][idx].next_on_curve;
185 next = (*this)[level][idx].prev_on_curve;
188 if ( level+1 != next.first || (*
this)[next.first][next.second].used ) {
214 dist_rdm(_(
"Randomness"), _(
"Global variation of distance between hatches, in %."),
"dist_rdm", &wr, this, 75),
215 growth(_(
"Growth"), _(
"Growth of distance between hatches."),
"growth", &wr, this, 0.),
218 scale_tf(_(
"Smooth: Bottom ←"), _(
"Set smoothness/sharpness of path when reaching a 'bottom' half-turn. 0=sharp, 1=default"),
"scale_bf", &wr, this, 1.),
219 scale_tb(_(
"Smooth: Bottom →"), _(
"Set smoothness/sharpness of path when leaving a 'bottom' half-turn. 0=sharp, 1=default"),
"scale_bb", &wr, this, 1.),
220 scale_bf(_(
"Smooth: Top ←"), _(
"Set smoothness/sharpness of path when reaching a 'top' half-turn. 0=sharp, 1=default"),
"scale_tf", &wr, this, 1.),
221 scale_bb(_(
"Smooth: Top →"), _(
"Set smoothness/sharpness of path when leaving a 'top' half-turn. 0=sharp, 1=default"),
"scale_tb", &wr, this, 1.),
222 top_edge_variation(_(
"↑↓ Random: Bottom"), _(
"Randomly moves 'bottom' half-turns up and down to produce magnitude variations."),
"bottom_edge_variation", &wr, this, 0),
223 bot_edge_variation(_(
"↑↓ Random: Top"), _(
"Randomly moves 'top' half-turns up and down to produce magnitude variations."),
"top_edge_variation", &wr, this, 0),
224 top_tgt_variation(_(
"←→ Random: Bottom"), _(
"Add direction randomness by moving 'bottom' half-turns tangentially to the boundary."),
"bottom_tgt_variation", &wr, this, 0),
225 bot_tgt_variation(_(
"←→ Random: Top"), _(
"Add direction randomness by randomly moving 'top' half-turns tangentially to the boundary."),
"top_tgt_variation", &wr, this, 0),
226 top_smth_variation(_(
"Rand. Smooth: Bottom"), _(
"Randomness of 'bottom' half-turns' smoothness"),
"top_smth_variation", &wr, this, 0),
227 bot_smth_variation(_(
"Rand. Smooth: Top"), _(
"Randomness of 'top' half-turns' smoothness"),
"bottom_smth_variation", &wr, this, 0),
229 fat_output(_(
"Vary stroke width"), _(
"Simulate a stroke of varying width"),
"fat_output", &wr, this, true),
230 do_bend(_(
"Bend hatches"), _(
"Add a global bending to the hatches (slower)"),
"do_bend", &wr, this, true),
231 stroke_width_top(_(
"↓ Width"), _(
"Width at 'bottom' half-turns"),
"stroke_width_top", &wr, this, 1.),
232 stroke_width_bot(_(
"↑ Width"), _(
"Width at 'top' half-turns"),
"stroke_width_bottom", &wr, this, 1.),
234 front_thickness(_(
"← Width"), _(
"Width of line from 'top' to 'bottom'"),
"front_thickness", &wr, this, 1.),
235 back_thickness(_(
"→ Width"), _(
"Width of line from 'bottom' to 'top'"),
"back_thickness", &wr, this, .25),
237 direction(_(
"Hatches width and dir"), _(
"Defines hatches frequency and direction"),
"direction", &wr, this,
Geom::
Point(50,0)),
239 bender(_(
"Global bending"), _(
"Relative position to a reference point defines global bending direction and amount"),
"bender", &wr, this,
Geom::
Point(-5,0))
297 Point end = pwd2_in.segs.back().at1();
299 transformed_pwd2_in.
push_cut( transformed_pwd2_in.
cuts.back() + 1 );
301 transformed_pwd2_in.
push_seg( stitch );
310 bend_mat =
Affine(-bend_dir[
Y], bend_dir[
X], bend_dir[
X], bend_dir[
Y],0,0);
311 transformed_pwd2_in = transformed_pwd2_in * bend_mat;
314 if (!(bbox))
return pwd2_in;
316 transformed_pwd2_in =
bend(transformed_pwd2_in, tilter);
317 transformed_pwd2_in = transformed_pwd2_in * bend_mat.inverse();
321 Affine mat(-hatches_dir[
Y], hatches_dir[
X], hatches_dir[
X], hatches_dir[
Y],0,0);
322 transformed_pwd2_in = transformed_pwd2_in * mat;
323 transformed_org *= mat;
325 std::vector<std::vector<Point> > snakePoints;
326 snakePoints =
linearSnake(transformed_pwd2_in, transformed_org);
327 if (!snakePoints.empty()){
329 smthSnake = smthSnake*mat.
inverse();
331 smthSnake = smthSnake*bend_mat;
332 smthSnake =
bend(smthSnake, -tilter);
333 smthSnake = smthSnake*bend_mat.inverse();
345 std::vector<double>
result;
351 while (x < domain.
max()){
366std::vector<std::vector<Point> >
370 std::vector<std::vector<Point> >
result;
376 if (!range)
return result;
378 std::vector<std::vector<double> > times;
382 std::vector<std::vector<double> > cleaned_times(levels.size(),std::vector<double>());
383 for (
unsigned i=0; i<times.size(); i++){
384 if ( times[i].
size()>0 ){
385 double last_t = times[i][0]-1;
386 for (
unsigned j=0; j<times[i].size(); j++){
387 if (times[i][j]-last_t >0.000001){
388 last_t = times[i][j];
389 cleaned_times[i].push_back(last_t);
394 times = cleaned_times;
397 LevelsCrossings lscs(times,f,dx);
400 lscs.findFirstUnused(i,j);
402 std::vector<Point> result_component;
405 while ( i < lscs.size() ){
408 if ((
static_cast<long long>(i) % 2 == n % 2) && ((j + 1) < lscs[i].
size()) && !lscs[i][j].
used){
413 while ( i < lscs.size() ){
414 result_component.push_back(lscs[i][j].pt);
415 lscs[i][j].used =
true;
418 result.push_back(result_component);
419 result_component = std::vector<Point>();
420 lscs.findFirstUnused(i,j);
434 Point last_pt = comp[0];
437 Point last_hdle = comp[0];
438 Point last_top_hdle = comp[0];
439 Point last_bot_hdle = comp[0];
445 bool is_top = ( comp[0][
Y] < comp[1][
Y] );
447 while( i+1<comp.size() ){
449 Point pt1 = comp[i+1];
450 Point new_pt = (pt0+pt1)/2;
472 Point new_hdle_in = new_pt + (pt0-pt1) * (scale_in /2.);
473 Point new_hdle_out = new_pt - (pt0-pt1) * (scale_out/2.);
479 Point inside = new_pt;
480 Point inside_hdle_in;
481 Point inside_hdle_out;
483 inside_hdle_in = inside + (new_hdle_in -new_pt);
484 inside_hdle_out = inside + (new_hdle_out-new_pt);
498 last_top_hdle = new_hdle_out;
499 last_bot_hdle = inside_hdle_out;
503 last_top_hdle = inside_hdle_out;
504 last_bot_hdle = new_hdle_out;
510 last_hdle = new_hdle_out;
514 if ( i<comp.size() ){
523 res_comp = res_comp_bot;
536 using namespace Geom;
558 origin = bbox->midpoint();
pair< double, double > Point
Conversion between Bezier control points and SBasis curves.
3x3 matrix representing an affine transformation.
Affine inverse() const
Compute the inverse matrix.
Bezier curve with compile-time specified order.
Adaptor that creates 2D functions from 1D ones.
constexpr C extent() const
Range of real numbers that is never empty.
Function that interpolates linearly between two values.
Range of real numbers that can be empty.
Axis-aligned rectangle that can be empty.
Sequence of contiguous curves, aka spline.
void setStitching(bool x)
Enable or disable the throwing of exceptions when stitching discontinuities.
Piecewise< D2< SBasis > > toPwSb() const
void append(Curve *curve)
Add a new curve to the end of the path.
Path reversed() const
Obtain a reversed version of the current path.
void appendNew(Args &&... args)
Append a new curve to the path.
Function defined as discrete pieces.
output_type valueAt(double t) const
void push_seg(const T &s)
std::vector< double > cuts
void setDomain(Interval dom)
Two-dimensional point that doubles as a vector.
Polynomial in symmetric power basis.
void registerParameter(Parameter *param)
virtual void resetDefaults(SPItem const *item)
Sets all parameters to their default values and writes them to SVG.
bool concatenate_before_pwd2
void param_setValue(Glib::ustring newvalue, bool write=false)
RandomParam bot_tgt_variation
RandomParam top_tgt_variation
void resetDefaults(SPItem const *item) override
Sets all parameters to their default values and writes them to SVG.
RandomParam top_smth_variation
ScalarParam front_thickness
~LPERoughHatches() override
void doBeforeEffect(SPLPEItem const *item) override
Is performed each time before the effect is updated.
std::vector< double > generateLevels(Geom::Interval const &domain, double x_org)
LPERoughHatches(LivePathEffectObject *lpeobject)
RandomParam bot_smth_variation
ScalarParam stroke_width_bot
void doOnApply(SPLPEItem const *lpeitem) override
Is performed a single time when the effect is freshly applied to a path.
Geom::Piecewise< Geom::D2< Geom::SBasis > > doEffect_pwd2(Geom::Piecewise< Geom::D2< Geom::SBasis > > const &pwd2_in) override
std::vector< std::vector< Geom::Point > > linearSnake(Geom::Piecewise< Geom::D2< Geom::SBasis > > const &f, Geom::Point const &org)
ScalarParam stroke_width_top
Geom::Piecewise< Geom::D2< Geom::SBasis > > smoothSnake(std::vector< std::vector< Geom::Point > > const &linearSnake)
RandomParam bot_edge_variation
RandomParam top_edge_variation
ScalarParam back_thickness
void param_set_value(gdouble val, long newseed)
void param_set_range(gdouble min, gdouble max)
void param_set_range(double min, double max)
Geom::Point getVector() const
void set_oncanvas_color(guint32 color)
void set_and_write_new_values(Geom::Point const &new_origin, Geom::Point const &new_vector)
Geom::Point getOrigin() const
Base class for visual SVG elements.
Geom::OptRect geometricBounds(Geom::Affine const &transform=Geom::identity()) const
Get item's geometric bounding box in this item's coordinate system.
std::vector< LevelCrossing > LevelCrossings
std::vector< Point > linearSnake(Piecewise< D2< SBasis > > const &f, double dy, double growth, double rdmness)
Fills an area with rough hatches.
Various utility functions.
D2< Piecewise< SBasis > > make_cuts_independent(Piecewise< D2< SBasis > > const &a)
OptInterval bounds_exact(Bezier const &b)
static float sign(double number)
Returns +1 for positive numbers, -1 for negative numbers, and 0 otherwise.
Piecewise< D2< SBasis > > sectionize(D2< Piecewise< SBasis > > const &a)
SBasisOf< T > shift(SBasisOf< T > const &a, int sh)
D2< T > compose(D2< T > const &a, T const &b)
Bezier derivative(Bezier const &a)
std::vector< std::vector< double > > multi_roots(SBasis const &f, std::vector< double > const &levels, double htol=1e-7, double vtol=1e-7, double a=0, double b=1)
SBasis L2(D2< SBasis > const &a, unsigned k)
Point unit_vector(Point const &a)
D2< T > rot90(D2< T > const &a)
static Piecewise< D2< SBasis > > bend(Piecewise< D2< SBasis > > const &f, Piecewise< SBasis > bending)
std::vector< LevelCrossing > LevelCrossings
static std::vector< double > discontinuities(Piecewise< D2< SBasis > > const &f)
Helper class to stream background task notifications as a series of messages.
some std functions to work with (pw)s-basis
Some things pertinent to all visible shapes: SPItem, SPItemView, SPItemCtx.