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, <, &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 | } |