Rev 2236 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* fractaliser.cc
* DIN Is Noise is copyright (c) 2006-2025 Jagannathan Sampath
* DIN Is Noise is released under GNU Public License 2.0
* For more information, please visit https://dinisnoise.org/
*/
#include "fractaliser.h"
#include "vector2d.h"
#include "ui_list.h"
#include "console.h"
#include <vector>
#include <fstream>
using namespace std;
fractaliser::fractaliser () : seed ("seed.crv"), ed ("seed.ed"), lib ("seed.lib") {
name = "Fractaliser";
ed.add (&seed, &lis);
ed.attach_library (&lib);
threshold = 0;
back_ed = 0;
load_params ();
}
fractaliser::~fractaliser () {
seed.save ("seed.crv");
widget_save ("d_fractaliser", ctrls);
save_params ();
}
void fractaliser::load_params () {
ifstream f (make_fname().c_str(), ios::in);
string ignore;
f >> ignore >> threshold;
}
void fractaliser::save_params () {
ofstream f (make_fname().c_str(), ios::out);
string ignore;
f << "threshold " << sp_threshold.value << endl;
}
void fractaliser::setup () {
plugin::setup ();
widget* _ctrls [] = {&sp_threshold, &cd_seed, &ab_left, &ab_right, &l_seed, &b_edit, &b_mirror, &sp_scale};
for (int i = 0; i < 8; ++i) ctrls.push_back (_ctrls[i]);
num_ctrls = ctrls.size ();
sp_threshold.set ("Threshold", 0.01f, 0, MILLION, 0, 0);
sp_threshold.set_value (threshold);
sp_scale.set ("Scale", 0.01f, -MILLION, MILLION, 0, 0);
sp_scale.set_value (1.0f);
l_seed.set_text ("Seed");
b_edit.set_text ("Edit");
b_mirror.set_text ("Flip");
cd_seed.crv = &seed;
cd_seed.unit_bbox ();
ab_left.set_dir (arrow_button::left);
ab_right.set_dir (arrow_button::right);
ab_left.click_repeat = 1;
ab_right.click_repeat = 1;
widget_load ("d_fractaliser", ctrls);
button* btn [] = {&ab_left, &ab_right, &b_edit, &b_mirror};
for (int i = 0; i < 4; ++i) btn[i]->set_listener (this);
}
void fractaliser::clicked (button& b) {
if (&b == &ab_left) {
ed.win.calc ();
ed.load_curve (-1);
render ();
} else if (&b == &ab_right) {
ed.win.calc ();
ed.load_curve (+1);
render ();
} else if (&b == &b_edit) {
if (b_edit.text == "Edit") {
b_edit.set_text ("Go back");
back_ed = uis.crved;
uis.set_current (&ed);
} else {
uis.set_current (back_ed);
b_edit.set_text ("Edit");
}
} else if (&b == &b_mirror) {
ed.get_picked_curve ();
int whole_curve = 1;
ed.mirror (whole_curve);
} else plugin::clicked (b);
}
void fractaliser::render () {
// replace all segments of input curve with seed curve
//
curve_editor* ed = uis.crved;
multi_curve& in = *ed->get_picked_curve (); // apply seed curve on this input curve
vector<crvpt> in_pts;
int n = in.get_profile_points (in_pts); // get curve profile
if (n < 2) {
cons << RED << "not enough points on curve!" << eol;
return;
}
int m = n - 1;
points.clear ();
left_tangents.clear ();
right_tangents.clear ();
threshold = sp_threshold.value;
points_array sv = seed.vertices;
points_array slt = seed.left_tangents;
points_array srt = seed.right_tangents;
int q = sv.size () - 1;
scale_seed_curve (sv, slt, srt, q+1, sp_scale.value);
point<float>& rt0 = srt[0];
point<float>& ltq = slt[q];
float dx=0, dy=0, pdx=0, pdy=0;
crvpt vk;
int subdivided=0;
for (int i = 0; i < m; ++i) { // replace all segments of input curve with seed curve
crvpt& vi = in_pts [i]; // ith vertex
int j = i + 1;
crvpt& vj = in_pts[j]; // jth vertex
points.push_back (point<float>(vi.x, vi.y));
if (i == 0) left_tangents.push_back (point<float>(vi.x, vi.y));
else {
if (subdivided)
left_tangents.push_back (point<float>(vk.x + ltq.x * dx + ltq.y * pdx, vk.y + ltq.x * dy + ltq.y * pdy));
else
left_tangents.push_back (point<float>(vi.x, vi.y));
}
dx = vj.x - vi.x; dy = vj.y - vi.y; // find vector joining i and j vertex
pdx = -dy; pdy = dx; // find perpendiular vector (ie y-axis) to vector joining i and j vertices (ie x-axis)
double length = magnitude (dx, dy); // find length of this vector
subdivided = 0;
if (length >= threshold) { // replace vector joining vertices with seed curve
subdivided = 1;
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
for (int p = 1; p < q; ++p) { // go thru the seed curve and replace
// get a point of seed curve
point<float>& pt = sv[p];
point<float>& plt = slt[p];
point<float>& prt = srt[p];
// compute output by going along x-axis and y-axis vectors from input
// using x and y amounts from seed curve
point<float> ov (vi.x + pt.x * dx + pt.y * pdx, vi.y + pt.x * dy + pt.y * pdy);
point<float> olt (vi.x + plt.x * dx + plt.y * pdx, vi.y + plt.x * dy + plt.y * pdy);
point<float> ort (vi.x + prt.x * dx + prt.y * pdx, vi.y + prt.x * dy + prt.y * pdy);
// add vertex, left and right tangent to output curve
points.push_back (ov);
left_tangents.push_back (olt);
right_tangents.push_back (ort);
}
} else right_tangents.push_back (point<float> (vi.x, vi.y));
vk = vi;
}
crvpt& mv = in_pts[m];
crvpt& mv1 = in_pts[m-1];
points.push_back (point<float>(mv.x, mv.y));
if (subdivided)
left_tangents.push_back (point<float>(mv1.x + ltq.x * dx + ltq.y * pdx, mv1.y + ltq.x * dy + ltq.y * pdy));
else
left_tangents.push_back (point<float>(mv.x, mv.y));
right_tangents.push_back (point<float>(mv.x, mv.y));
ss.str("");
ss << in.name << "_" << seed.name;
}
void fractaliser::draw (curve_editor* ed) {}
void fractaliser::scale_seed_curve (points_array& v, points_array& lt, points_array& rt, int n, float scale) {
// we only scale in y, because x is normalised from 0 to 1 and cant be changed
point<float> o; // origin at 0,0
points_array* pa[3] = {&v, <, &rt};
for (int i = 0; i < n; ++i) {
for (int j = 0; j < 3; ++j) {
points_array& p = *pa[j];
point<float>& pi = p[i];
point<float> dp; direction (dp, o, pi);
dp.y *= scale;
pi = o + dp;
}
}
}