Subversion Repositories DIN Is Noise

Rev

Rev 2236 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
964 jag 1
/*
2
* fractaliser.cc
2302 jag 3
* DIN Is Noise is copyright (c) 2006-2025 Jagannathan Sampath
1713 jag 4
* DIN Is Noise is released under GNU Public License 2.0
1479 jag 5
* For more information, please visit https://dinisnoise.org/
964 jag 6
*/
7
 
8
#include "fractaliser.h"
9
#include "vector2d.h"
10
#include "ui_list.h"
1001 jag 11
#include "console.h"
964 jag 12
#include <vector>
13
#include <fstream>
14
using namespace std;
15
 
16
 
17
fractaliser::fractaliser () : seed ("seed.crv"), ed ("seed.ed"), lib ("seed.lib") {
18
  name = "Fractaliser";
19
  ed.add (&seed, &lis);
20
  ed.attach_library (&lib);
21
  threshold = 0;
22
  back_ed = 0;
23
  load_params ();
24
}
25
 
26
fractaliser::~fractaliser () {
27
  seed.save ("seed.crv");
28
  widget_save ("d_fractaliser", ctrls);
29
  save_params ();
30
}
31
 
32
void fractaliser::load_params () {
33
  ifstream f (make_fname().c_str(), ios::in);
34
  string ignore;
35
  f >> ignore >> threshold;
36
}
37
 
38
void fractaliser::save_params () {
39
  ofstream f (make_fname().c_str(), ios::out);
40
  string ignore;
2107 jag 41
  f << "threshold " << sp_threshold.value << endl;
964 jag 42
}
43
 
44
void fractaliser::setup () {
45
 
46
  plugin::setup ();
47
 
48
  widget* _ctrls [] = {&sp_threshold, &cd_seed, &ab_left, &ab_right, &l_seed, &b_edit, &b_mirror, &sp_scale};
49
  for (int i = 0; i < 8; ++i) ctrls.push_back (_ctrls[i]);
50
  num_ctrls = ctrls.size ();
51
 
1485 jag 52
  sp_threshold.set ("Threshold", 0.01f, 0, MILLION, 0, 0);
53
  sp_threshold.set_value (threshold);
964 jag 54
 
1485 jag 55
  sp_scale.set ("Scale", 0.01f, -MILLION, MILLION, 0, 0);
964 jag 56
  sp_scale.set_value (1.0f);
57
 
58
  l_seed.set_text ("Seed");
59
 
1120 jag 60
  b_edit.set_text ("Edit");
61
  b_mirror.set_text ("Flip");
964 jag 62
 
63
  cd_seed.crv = &seed;
64
  cd_seed.unit_bbox ();
65
 
1015 jag 66
  ab_left.set_dir (arrow_button::left);
67
  ab_right.set_dir (arrow_button::right);
964 jag 68
  ab_left.click_repeat = 1;
69
  ab_right.click_repeat = 1;
70
 
71
  widget_load ("d_fractaliser", ctrls);
72
 
73
  button* btn [] = {&ab_left, &ab_right, &b_edit, &b_mirror};
74
  for (int i = 0; i < 4; ++i) btn[i]->set_listener (this);
75
 
76
}
77
 
78
void fractaliser::clicked (button& b) {
79
  if (&b == &ab_left) {
80
    ed.win.calc ();
81
    ed.load_curve (-1);
82
    render ();
83
  } else if (&b == &ab_right) {
84
    ed.win.calc ();
85
    ed.load_curve (+1);
86
    render ();
87
  } else if (&b == &b_edit) {
1095 jag 88
    if (b_edit.text == "Edit") {
1120 jag 89
      b_edit.set_text ("Go back");
964 jag 90
      back_ed = uis.crved;
91
      uis.set_current (&ed);
92
    } else {
93
      uis.set_current (back_ed);
1120 jag 94
      b_edit.set_text ("Edit");
964 jag 95
    }
96
  } else if (&b == &b_mirror) {
2236 jag 97
    ed.get_picked_curve ();
1454 jag 98
    int whole_curve = 1;
99
    ed.mirror (whole_curve);
964 jag 100
  } else plugin::clicked (b);
101
}
102
 
103
void fractaliser::render () {
104
  // replace all segments of input curve with seed curve
105
  //
106
 
1453 jag 107
  curve_editor* ed = uis.crved;
108
  multi_curve& in = *ed->get_picked_curve (); // apply seed curve on this input curve
964 jag 109
 
110
  vector<crvpt> in_pts;
2158 jag 111
  int n = in.get_profile_points (in_pts); // get curve profile
112
  if (n < 2) {
113
    cons << RED << "not enough points on curve!" << eol;
114
    return;
115
  }
964 jag 116
  int m = n - 1;
117
 
118
  points.clear ();
119
  left_tangents.clear ();
120
  right_tangents.clear ();
121
 
2107 jag 122
  threshold = sp_threshold.value;
964 jag 123
 
2179 jag 124
  points_array sv = seed.vertices;
125
  points_array slt = seed.left_tangents;
126
  points_array srt = seed.right_tangents;
964 jag 127
  int q = sv.size () - 1;
2107 jag 128
  scale_seed_curve (sv, slt, srt, q+1, sp_scale.value);
964 jag 129
 
130
  point<float>& rt0 = srt[0];
131
  point<float>& ltq = slt[q];
132
  float dx=0, dy=0, pdx=0, pdy=0;
133
  crvpt vk;
134
  int subdivided=0;
135
  for (int i = 0; i < m; ++i) { // replace all segments of input curve with seed curve
1453 jag 136
    crvpt& vi = in_pts [i];  // ith vertex
137
    int j = i + 1;
138
    crvpt& vj = in_pts[j]; // jth vertex
964 jag 139
    points.push_back (point<float>(vi.x, vi.y));
1453 jag 140
    if (i == 0) left_tangents.push_back (point<float>(vi.x, vi.y));
141
    else {
142
      if (subdivided)
143
        left_tangents.push_back (point<float>(vk.x + ltq.x * dx + ltq.y * pdx, vk.y + ltq.x * dy + ltq.y * pdy));
144
      else
145
        left_tangents.push_back (point<float>(vi.x, vi.y));
146
    }
147
    dx = vj.x - vi.x; dy = vj.y - vi.y; // find vector joining i and j vertex
148
    pdx = -dy; pdy = dx; // find perpendiular vector (ie y-axis) to vector joining i and j vertices (ie x-axis)
149
    double length = magnitude (dx, dy); // find length of this vector
150
    subdivided = 0;
1457 jag 151
    if (length >= threshold) { // replace vector joining vertices with seed curve
1453 jag 152
      subdivided = 1;
153
      right_tangents.push_back (point<float>(vi.x + rt0.x * dx + rt0.y * pdx, vi.y + rt0.x * dy + rt0.y * pdy)); // = right tangent of seed curve's 1st vertex
154
      for (int p = 1; p < q; ++p) { // go thru the seed curve and replace
155
        // get a point of seed curve
156
        point<float>& pt = sv[p];
157
        point<float>& plt = slt[p];
158
        point<float>& prt = srt[p];
159
        // compute output by going along x-axis and y-axis vectors from input 
160
        // using x and y amounts from seed curve
161
        point<float> ov (vi.x + pt.x * dx + pt.y * pdx, vi.y + pt.x * dy + pt.y * pdy);
162
        point<float> olt (vi.x + plt.x * dx + plt.y * pdx, vi.y + plt.x * dy + plt.y * pdy);
163
        point<float> ort (vi.x + prt.x * dx + prt.y * pdx, vi.y + prt.x * dy + prt.y * pdy);
164
        // add vertex, left and right tangent to output curve
165
        points.push_back (ov);
166
        left_tangents.push_back (olt);
167
        right_tangents.push_back (ort);
168
      }
169
    } else right_tangents.push_back (point<float> (vi.x, vi.y));   
170
    vk = vi;
964 jag 171
  }
172
 
173
  crvpt& mv = in_pts[m];
174
  crvpt& mv1 = in_pts[m-1];
175
  points.push_back (point<float>(mv.x, mv.y));
176
  if (subdivided)
177
    left_tangents.push_back (point<float>(mv1.x + ltq.x * dx + ltq.y * pdx, mv1.y + ltq.x * dy + ltq.y * pdy));
178
  else
179
    left_tangents.push_back (point<float>(mv.x, mv.y));
180
  right_tangents.push_back (point<float>(mv.x, mv.y));
181
 
182
  ss.str("");
183
  ss << in.name << "_" << seed.name;
184
 
185
}
186
 
187
void fractaliser::draw (curve_editor* ed) {}
188
 
189
void fractaliser::scale_seed_curve (points_array& v, points_array& lt, points_array& rt, int n, float scale) {
190
  // we only scale in y, because x is normalised from 0 to 1 and cant be changed
191
  point<float> o; // origin at 0,0
192
  points_array* pa[3] = {&v, &lt, &rt};
193
  for (int i = 0; i < n; ++i) {
194
    for (int j = 0; j < 3; ++j) {
195
      points_array& p = *pa[j];
196
      point<float>& pi = p[i];
197
      point<float> dp; direction (dp, o, pi);
198
      dp.y *= scale;
199
      pi = o + dp;
200
    }
201
  }
202
}