diff --git a/pub/lib/plot.cpp b/pub/lib/plot.cpp index d7a8695ac9fd4e7103c5289cabb8335fedbdc670..ac9be1311454783b16f330e90c4a9107900b1a95 100644 --- a/pub/lib/plot.cpp +++ b/pub/lib/plot.cpp @@ -288,25 +288,37 @@ int plot_curve_refine(CPlot* plot, const COlc* fc, int k, int j, int cstyle) CP2 P; // plot point }; - auto x2p = [&](const vector<double>& x) -> vector<CPt> { - vector<double> y = PCAST<const CObjVecDbl>(fc->eval_curve(x, k, j, false))->v; - vector<int> inRange = fc->eval_prange(x, k, j)->v; - vector<CPt> ret(x.size()); - for (size_t i=0; i<x.size(); ++i) { - double xp = plot->X.pc(x[i]); - if (y[i]<plot->Y.inf) - ret[i] = {x[i], 0., 1, {xp, NAN}}; - else if (y[i]>plot->Y.sup) - ret[i] = {x[i], 0., 1, {xp, NAN}}; - else if (!inRange[i]) - ret[i] = {x[i], 0., 1, {xp, NAN}}; - else - ret[i] = {x[i], y[i], 0, {xp, plot->Y.pc(y[i])}}; - } - return ret; - }; - - auto pt_order = [](const CPt a, const CPt b) -> bool { return a.xd<=b.xd; }; + auto x2p = [&](const vector<double>& x) -> vector<CPt> + { + vector<double> y = PCAST<const CObjVecDbl>(fc->eval_curve(x, k, j, false))->v; + vector<int> inRange = fc->eval_prange(x, k, j)->v; + vector<CPt> ret(x.size()); + for (size_t i=0; i<x.size(); ++i) { + double xp = plot->X.pc(x[i]); + if (y[i]<plot->Y.inf) + ret[i] = {x[i], 0., 1, {xp, NAN}}; + else if (y[i]>plot->Y.sup) + ret[i] = {x[i], 0., 1, {xp, NAN}}; + else if (!inRange[i]) + ret[i] = {x[i], 0., 1, {xp, NAN}}; + else + ret[i] = {x[i], y[i], 0, {xp, plot->Y.pc(y[i])}}; + } + return ret; + }; + + auto pt_order = [](const CPt a, const CPt b) -> bool + { return a.xd<=b.xd; }; + + auto nonlinearity = [](const vector<CPt>::iterator b) -> double + { + auto a = b-1; + auto c = b+1; + CP2 BA = a->P-b->P; + CP2 AC = c->P-a->P; + // squared deviation from linearity: + return BA*BA - pow(BA*AC,2)/(AC*AC); + }; // start with equidistant grid: vector<double> xn; @@ -314,45 +326,47 @@ int plot_curve_refine(CPlot* plot, const COlc* fc, int k, int j, int cstyle) // refinement loop: vector<CPt> pp; - for (int iref=0; iref<47 && pp.size() < plot->maxpoints; ++iref) { + for (int iref=0; iref<49 && pp.size() < plot->maxpoints; ++iref) { vector<CPt> pn = x2p(xn); pp = triv::merge_sorted(pp, pn, pt_order); xn.clear(); auto a = pp.begin(); auto b = pp.begin()+1; - vector<CPt> po = { *a }; for (; b<pp.end(); ++a, ++b) { if (a->code!=0 || b->code!=0) { - if (a->code!=b->code) + if (a->code!=b->code) { xn.push_back( (b->xd + a->xd)/2 ); + } } else { // valid data auto c = b+1; if (c<pp.end() && c->code==0) { - CP2 BA = a->P-b->P; - CP2 AC = c->P-a->P; // squared deviation from linearity: - double delta2 = BA*BA - pow(BA*AC,2)/(AC*AC); - if ( delta2 < 1e-12 ) // it's linear - continue; // don't copy *b to po + double delta2 = nonlinearity(b); if ( delta2 > 1e-8 ) { - xn.push_back( (b->xd + a->xd)/2 ); - xn.push_back( (c->xd + b->xd)/2 ); + double dx = std::min(b->xd - a->xd, c->xd - b->xd)/2; + xn.push_back( b->xd - dx ); + xn.push_back( b->xd + dx ); } } } - po.push_back( *b ); } - pp = po; if (!xn.size()) break; xn = std::vector<double>( xn.begin(), std::unique(xn.begin(), xn.end()) ); } + // remove points in straight lines + vector<CPt> po { *pp.begin() }; + for (auto b = pp.begin()+1; b<pp.end()-1; ++b) + if (b->code!=0 || (b-1)->code!=0 | (b+1)->code!=0 || nonlinearity(b)>1e-9) + po.push_back(*b); + po.push_back( *(pp.end()-1) ); + // divide into segments vector<vector<CPt>> segments; vector<CPt> seg; - for (CPt p: pp) { + for (CPt p: po) { if (p.code==0) seg.push_back(p); else if (seg.size()) {