(root)/wip/src/fractaliser.cc - Rev 1524
Rev 1479 |
Rev 1713 |
Go to most recent revision |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* fractaliser.cc
* DIN Is Noise is copyright (c) 2006-2020 Jagannathan Sampath
* 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;
extern const int MILLION;
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 " << float(sp_threshold.f_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 (); // pick 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;
in.get_profile_points (in_pts); // get curve profile
int n = in_pts.size (); if (n < 2) return;
int m = n - 1;
points.clear ();
left_tangents.clear ();
right_tangents.clear ();
threshold = sp_threshold.f_value;
vector<point<float> > sv = seed.vertices;
vector<point<float> > slt = seed.left_tangents;
vector<point<float> > srt = seed.right_tangents;
int q = sv.size () - 1;
scale_seed_curve (sv, slt, srt, q+1, float(sp_scale.f_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;
}
int fractaliser::apply (multi_curve& crv) {
#ifdef __EVALUATION__
cons << RED << "Can apply plugins only in the Licensed Version of DIN Is Noise" << eol;
return 0;
#endif
render ();
int npts = points.size ();
if (npts == 0) return 0;
crv.clear (0);
if (change_curve_name) crv.set_name (ss.str());
typedef std::list< point<float> >::iterator points_list_iterator;
points_list_iterator lti = left_tangents.begin (), rti = right_tangents.begin ();
for (int i = 0; i < npts; ++i) {
point<float>& p = points[i];
point<float>& lt = *lti++;
point<float>& rt = *rti++;
crv.add_vertex (p.x, p.y);
crv.add_left_tangent (lt.x, lt.y);
crv.add_right_tangent (rt.x, rt.y);
}
if (shapeform) crv.shapeform = 1;
crv.evaluate ();
return 1;
}
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;
}
}
}