Rev 2302 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* solver.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 "solver.h"
#include "multi_curve.h"
#include "curve_editor.h"
#include <cmath>
#include "utils.h"
using namespace std;
void solver::init () {
mcrv = 0;
icurv = ncurvs = 0;
iseg = 0;
firstx = firsty = 0;
lastx = lasty = 0;
startx = starty = 0;
endx = endy = 0;
pinx = 0;
ycomp = 0;
result = 0;
}
solver::solver () {
init ();
}
solver::solver (multi_curve* c) {
init ();
operator()(c);
}
void solver::operator() (multi_curve* c) {
mcrv = c;
update ();
}
void solver::update () {
// curve valid?
vector<curve>& curv = mcrv->curv;
ncurvs = curv.size ();
last_curv = ncurvs - 1;
if (icurv > last_curv) icurv = 0;
// segment valid?
vector<crvpt>& vpts = mcrv->get_profile_points (icurv);
int nsegs = vpts.size() - 1;
if (iseg >= nsegs) iseg = 0;
setseg (icurv, iseg);
// first point
vector<crvpt>& fpts = mcrv->get_profile_points (0);
firstx = fpts[0].x;
firsty = fpts[0].y;
pinx = firstx;
// last point
vector<crvpt>& lpts = mcrv->get_profile_points (last_curv);
int last_point = lpts.size () - 1;
lastx = lpts[last_point].x;
deltax = lastx - firstx;
if (equals (deltax, 0.0f)) deltax = 0.000001f;
lasty = lpts[last_point].y;
}
// solves y for x
float solver::operator() (float x) {
float y = 0;
if (x < startx) {
if (!searchleft (x)) {
y = firsty;
return y;
}
} else if (x > endx) {
if (!searchright (x)) {
y = lasty;
return y;
}
}
y = ycomp + m * x;
return y;
}
void solver::check (float& x, float& dx, xhandler& xmin, xhandler& xmax) {
if (x < startx) {
if (!searchleft (x)) xmin (*this, x, dx);
} else if (x > endx) {
if (!searchright (x)) xmax (*this, x, dx);
}
}
float solver::operator() (float& x, float& dx, xhandler& xmin, xhandler& xmax) {
check (x, dx, xmin, xmax);
float y = ycomp + m * x;
x += dx;
return y;
}
// solves y for x with modulation of x
void solver::operator() (float& x, float& dx, int q, float* mod, float* y, xhandler& xmin, xhandler& xmax) {
for (int p = 0; p < q; ++p) {
x += (mod[p] + dx);
check (x, dx, xmin, xmax);
y[p] = ycomp + m * x;
}
}
void solver::operator() (float& x, float* pdx, int q, float* mod, float* y, xhandler& xmin, xhandler& xmax) {
float dx;
for (int p = 0; p < q; ++p) {
dx = pdx[p];
x += (mod[p] + dx);
check (x, dx, xmin, xmax);
y[p] = ycomp + m * x;
}
}
// solves y for x, constant dx
void solver::operator() (float& x, float& dx, int q, float* y, xhandler& xmin, xhandler& xmax) {
for (int p = 0; p < q; ++p) {
x += dx;
check (x, dx, xmin, xmax);
y[p] = ycomp + m * x;
}
}
// solves y for x, array of dx
void solver::operator() (float& x, float* pdx, int q, float* y, xhandler& xmin, xhandler& xmax) {
float dx;
for (int p = 0; p < q; ++p) {
dx = pdx[p];
x += dx;
check (x, dx, xmin, xmax);
y[p] = ycomp + m * x;
}
}
// solves array of x. stores solution ie y in the same array at corresponding location
void solver::operator() (float* ax, int q, xhandler& xmin, xhandler& xmax) {
float x = 0, dx = 0;
for (int p = 0; p < q; ++p) {
x = ax[p];
check (x, dx, xmin, xmax);
ax[p] = ycomp + m * x;
}
}
int solver::seg_lte_right (float x, int c, int i) {
std::vector<crvpt>& pts = mcrv->get_profile_points (c);
float rightx = pts[i+1].x;
if (rightx < pinx) {
float dpin = pinx - rightx;
rightx = pinx + dpin;
}
float xd = x;
if (xd <= rightx) {
setseg (c, i);
return 1;
}
return 0;
}
int solver::searchright (float x) {
int rseg = iseg, rcurv = icurv;
std::vector<crvpt>& pts = mcrv->get_profile_points (rcurv);
pinx = pts[rseg].x;
int rsegs = numsegs (rcurv);
while (1) {
if (++rseg < rsegs); else {
++rcurv;
if (rcurv >= ncurvs) break;
rsegs = numsegs (rcurv);
rseg = 0;
}
if (seg_lte_right (x, rcurv, rseg)) return 1;
}
return 0;
}
int solver::seg_gte_left (float x, int c, int i) {
std::vector<crvpt>& pts = mcrv->get_profile_points (c);
float leftx = pts[i].x;
if (leftx > pinx) {
float dpin = pinx - leftx;
leftx = pinx + dpin;
}
float xd = x;
if (xd >= leftx) {
setseg (c, i);
return 1;
}
return 0;
}
int solver::searchleft (float x) {
int lseg = iseg, lcurv = icurv;
std::vector<crvpt>& pts = mcrv->get_profile_points (lcurv);
pinx = pts[lseg].x;
while (1) {
if (--lseg < 0) {
--lcurv;
if (lcurv < 0) break;
lseg = lastseg (lcurv);
}
if (seg_gte_left (x, lcurv, lseg)) return 1;
}
return 0;
}
int solver::findseg (float x) {
int fcurv = 0, fseg = 0, nsegs = numsegs (fcurv);
pinx = firstx;
while (1) {
if (seg_lte_right (x, fcurv, fseg))
return 1;
else {
++fseg;
if (fseg >= nsegs) {
if (++fcurv >= ncurvs) {
// bad news
// setseg (ncurvs - 1, nsegs - 1);
// setseg (0, 0);
ycomp = 0;
m = 0;
break;
}
fseg = 0;
nsegs = numsegs (fcurv);
}
}
}
return 0;
}
void solver::setseg (int c, int i) {
std::vector<crvpt>& vpts = mcrv->get_profile_points (c);
crvpt& start = vpts[i];
crvpt& end = vpts[i+1];
startx = start.x;
starty = start.y;
endx = end.x;
endy = end.y;
m = start.m;
inf = start.inf;
if (inf == 1) ycomp = endy; else ycomp = starty - m * startx;
icurv = c;
iseg = i;
}
gotog::gotog (float gg, curve_editor* e) : ed (e) {
set (gg);
}
void gotog::set (float gg) {
g = gg;
ed->update_sustain (g);
}
void gotog::operator () (solver& s, float& x, float& dx) {
x = g;
if (!s.findseg (x)) {
x = s.lastx;
set (x);
}
}
void tomax::operator() (solver& s, float& x, float& dx) {
float xd = s.firstx - x;
float d = xd / s.deltax;
int i = d;
x = s.lastx - d + i;
s.findseg (x);
}
void atmin::operator() (solver& s, float& x, float& dx) {
x = s.firstx;
s.setseg (0, 0);
}
void atmax::operator () (solver& s, float& x, float& dx) {
x = s.lastx;
s.setseg (s.last_curv, s.lastseg (s.last_curv));
}
void tomin::operator() (solver& s, float& x, float& dx) {
float xd = (x - s.lastx);
float d = xd / s.deltax;
int i = d;
x = s.firstx + d - i;
s.findseg (x);
// called = 1;
}
void loopmin::operator() (solver& s, float& x, float& dx) {
atmin::operator() (s, x, dx);
if (dx < 0) dx = -dx;
}
void loopmax::operator() (solver& s, float& x, float& dx) {
tomin::operator() (s, x, dx);
if (dx < 0) dx = -dx;
}
void pongmax::operator () (solver& s, float& x, float& dx) {
atmax::operator() (s, x, dx);
if (dx > 0) dx = -dx;
}
void pongmin::operator () (solver& s, float& x, float& dx) {
atmin::operator() (s, x, dx);
if (dx < 0) dx = -dx;
}