31#ifndef LIB2GEOM_SEEN_PIECEWISE_H
32#define LIB2GEOM_SEEN_PIECEWISE_H
37#include <boost/concept_check.hpp>
103 unsigned n =
segN(t);
117 unsigned n =
segN(t);
118 std::vector<output_type> ret, val =
segs[n].valueAndDerivatives(
segT(t, n), n_derivs);
120 for(
unsigned i = 0; i < val.size(); i++) {
121 ret.push_back(val[i] * mult);
131 inline unsigned size()
const {
return segs.size(); }
141 inline void push(
const T &s,
double to) {
142 assert(
cuts.size() -
segs.size() == 1);
146 inline void push(T &&s,
double to) {
147 assert(
cuts.size() -
segs.size() == 1);
153 ASSERT_INVARIANTS(
cuts.empty() ||
c >
cuts.back());
163 inline unsigned segN(
double t,
int low = 0,
int high = -1)
const {
164 high = (high == -1) ?
size() : high;
165 if(t <
cuts[0])
return 0;
168 int mid = (high + low) / 2;
169 double mv =
cuts[mid];
171 if(t <
cuts[mid + 1])
return mid;
else low = mid + 1;
173 if(
cuts[mid - 1] < t)
return mid - 1;
else high = mid - 1;
185 inline double segT(
double t,
int i = -1)
const {
186 if(i == -1) i =
segN(t);
197 assert(std::isfinite(o));
199 for(
unsigned i = 0; i <=
size(); i++)
210 for(
unsigned i = 0; i <=
size(); i++)
225 double cf =
cuts.front();
226 double o = dom.
min() - cf, s = dom.
extent() / (
cuts.back() - cf);
227 for(
unsigned i = 0; i <=
size(); i++)
236 if(other.
empty())
return;
244 double t =
cuts.back() - other.
cuts.front();
246 for(
unsigned i = 0; i < other.
size(); i++)
252 boost::function_requires<AddableConcept<typename T::output_type> >();
253 if(other.
empty())
return;
257 typename T::output_type y =
segs.back().at1() - other.
segs.front().at0();
258 double t =
cuts.back() - other.
cuts.front();
260 for(
unsigned i = 0; i < other.
size(); i++)
261 push(other[i] + y, other.
cuts[i + 1] + t);
270 for(
unsigned i = 0; i <
segs.size(); i++)
285 boost::function_requires<FragmentConcept<T> >();
289 for(
unsigned i = 1; i < f.
size(); i++)
301 boost::function_requires<FragmentConcept<T> >();
305 for(
unsigned i = 1; i < f.
size(); i++)
317 boost::function_requires<FragmentConcept<T> >();
329 for(
unsigned i = fi + 1; i < ti; i++)
342 assert(i < a.
size());
343 double rwidth = 1 / (a.
cuts[i+1] - a.
cuts[i]);
344 return portion( a[i], (from - a.
cuts[i]) * rwidth, (to - a.
cuts[i]) * rwidth );
368 for(
unsigned i = 0; i <
c.size() - 1; i++)
373 unsigned si = 0, ci = 0;
376 while(ci <
c.size() &&
c[ci] < pw.
cuts.front()) {
377 bool isLast = (ci ==
c.size()-1 ||
c[ci + 1] >= pw.
cuts.front());
379 ret.
push_seg( elem_portion(pw, 0,
c[ci], isLast ? pw.
cuts.front() :
c[ci + 1]) );
384 double prev = pw.
cuts[0];
387 while(si < pw.
size() && ci <=
c.size()) {
388 if(ci ==
c.size() && prev <= pw.
cuts[si]) {
392 }
else if(ci ==
c.size() ||
c[ci] >= pw.
cuts[si + 1]) {
393 if(prev > pw.
cuts[si]) {
399 prev = pw.
cuts[si + 1];
401 }
else if(
c[ci] == pw.
cuts[si]){
405 ret.
push(elem_portion(pw, si, prev,
c[ci]),
c[ci]);
412 while(ci <
c.size()) {
414 ret.
push(elem_portion(pw, pw.
size() - 1, prev,
c[ci]),
c[ci]);
433 from = std::min(from, to);
434 to = std::max(temp, to);
436 unsigned i = pw.
segN(from);
438 if(i == pw.
size() - 1 || to <= pw.
cuts[i + 1]) {
439 ret.
push(elem_portion(pw, i, from, to), to);
444 unsigned fi = pw.
segN(to, i);
446 if (to == pw.
cuts[fi]) fi-=1;
449 ret.
cuts.insert(ret.
cuts.end(), pw.
cuts.begin() + i, pw.
cuts.begin() + fi + 1);
465 if(f.
empty())
return f;
469 for(
unsigned i=0; i<f.
size(); i++){
485 if(f.
empty())
return f;
489 double last = f.
cuts[0];
490 for(
unsigned i=0; i<f.
size(); i++){
492 ret.
push(elem_portion(f, i, last, f.
cuts[i+1]), f.
cuts[i+1]);
506 std::vector<double> ret;
507 for(
unsigned i = 0; i < pw.
size(); i++) {
508 std::vector<double> sr =
roots(pw[i]);
509 for (
double & j : sr) ret.push_back(j * (pw.
cuts[i + 1] - pw.
cuts[i]) + pw.
cuts[i]);
523 boost::function_requires<OffsetableConcept<T> >();
528 for(
unsigned i = 0; i < a.
size();i++)
529 ret.push_seg(a[i] + b);
534 boost::function_requires<OffsetableConcept<T> >();
539 for(
unsigned i = 0; i < a.
size();i++)
540 ret.push_seg(a[i] - b);
545 boost::function_requires<OffsetableConcept<T> >();
549 for(
unsigned i = 0; i < a.
size();i++)
555 boost::function_requires<OffsetableConcept<T> >();
559 for(
unsigned i = 0;i < a.
size();i++)
572 boost::function_requires<ScalableConcept<T> >();
577 for(
unsigned i = 0; i < a.
size();i++)
578 ret.push_seg(- a[i]);
588 boost::function_requires<ScalableConcept<T> >();
595 for(
unsigned i = 0; i < a.
size();i++)
606 boost::function_requires<ScalableConcept<T> >();
613 for(
unsigned i = 0; i < a.
size();i++)
624 boost::function_requires<ScalableConcept<T> >();
632 for(
unsigned i = 0; i < a.
size();i++)
638 boost::function_requires<ScalableConcept<T> >();
640 for(
unsigned i = 0; i < a.
size();i++)
646 boost::function_requires<ScalableConcept<T> >();
650 for(
unsigned i = 0; i < a.
size();i++)
663 boost::function_requires<AddableConcept<T> >();
667 assert(pa.size() == pb.size());
668 ret.
segs.reserve(pa.size());
670 for (
unsigned i = 0; i < pa.size(); i++)
681 boost::function_requires<AddableConcept<T> >();
685 assert(pa.size() == pb.size());
686 ret.
segs.reserve(pa.size());
688 for (
unsigned i = 0; i < pa.size(); i++)
708template<
typename T1,
typename T2>
719 for (
unsigned i = 0; i < pa.
size(); i++)
751 std::map<double,unsigned>::iterator
const &next,
752 std::vector<double>
const &levels,
773 if (f.
cuts.front() >
bs.max() ||
bs.min() > f.
cuts.back()){
774 int idx = (
bs.max() < f.
cuts[1]) ? 0 : f.
cuts.size()-2;
779 std::vector<double> levels;
780 levels.insert(levels.begin(),f.
cuts.begin()+1,f.
cuts.end()-1);
785 result.cuts.push_back(0.);
786 std::map<double,unsigned>::iterator cut=cuts_pb.begin();
787 std::map<double,unsigned>::iterator next=cut; next++;
788 while(next!=cuts_pb.end()){
793 double t0=(*cut).first;
794 double t1=(*next).first;
818 for(
unsigned i = 0; i < g.
segs.size(); i++){
829 Piecewise<D2<SBasis> > result;
831 for(unsigned i = 0; i < pwd2sb.size(); i++){
832 result.push(compose_each(sb2d,pwd2sb[i]),i+1);
862 typename T::output_type
c = a.
segs[0].at0();
863 for(
unsigned i = 0; i < a.
segs.size(); i++){
881 for(
unsigned i = 0; i < a.
segs.size(); i++){
910 for (
unsigned i = 0; i < f.
cuts.size(); i++) {
911 double x = f.
cuts[f.
cuts.size() - 1 - i];
914 for (
unsigned i = 0; i < f.
segs.size(); i++)
931 return (pA*(1-t) + pB*t);
constexpr C extent() const
constexpr bool isSingular() const
Range of real numbers that is never empty.
Function that interpolates linearly between two values.
Range of real numbers that can be empty.
Function defined as discrete pieces.
Piecewise< T > operator+(Piecewise< T > const &a, typename T::output_type b)
...
Piecewise< T2 > operator*(Piecewise< T1 > const &a, Piecewise< T2 > const &b)
...
unsigned segN(double t, int low=0, int high=-1) const
Returns the segment index which corresponds to a 'global' piecewise time.
Piecewise< T > operator*(Piecewise< T > const &a, double b)
...
Piecewise< T > portion(const Piecewise< T > &pw, double from, double to)
Returns a Piecewise<T> with a defined domain of [min(from, to), max(from, to)].
output_type valueAt(double t) const
Piecewise< T > remove_short_cuts(Piecewise< T > const &f, double tol)
...
Piecewise< T > operator-(Piecewise< T > const &a, Piecewise< T > const &b)
...
void offsetDomain(double o)
void push(const T &s, double to)
Convenience/implementation hiding function to add segment/cut pairs.
FragmentConcept< T >::BoundsType bounds_fast(const Piecewise< T > &f)
...
Piecewise< T > partition(const Piecewise< T > &pw, std::vector< double > const &c)
Piecewise<T> partition(const Piecewise<T> &pw, std::vector<double> const &c); Further subdivides the ...
Piecewise< T > integral(Piecewise< T > const &a)
...
Piecewise(const output_type &v)
Piecewise< T > operator*(Piecewise< T > const &a, T b)
...
Piecewise< T > operator()(SBasis f)
Piecewise< T > & operator*=(Piecewise< T > &a, Piecewise< T > const &b)
...
BOOST_CLASS_REQUIRE(T, Geom, FragmentConcept)
T elem_portion(const Piecewise< T > &a, unsigned i, double from, double to)
Returns a portion of a piece of a Piecewise<T>, given the piece's index and a to/from time.
void scaleDomain(double s)
Piecewise< T > compose(Piecewise< T > const &f, Piecewise< SBasis > const &g)
...
void push_seg(const T &s)
T & operator[](unsigned i)
void push(T &&s, double to)
void continuousConcat(const Piecewise< T > &other)
output_type lastValue() const
std::vector< double > cuts
Piecewise< T > remove_short_cuts_extending(Piecewise< T > const &f, double tol)
...
Piecewise< T > compose(Piecewise< T > const &f, SBasis const &g)
...
Piecewise< T > operator()(Piecewise< SBasis >f)
Piecewise< T > derivative(Piecewise< T > const &a)
...
std::vector< double > roots(const Piecewise< T > &pw)
...
std::vector< output_type > valueAndDerivatives(double t, unsigned n_derivs) const
The size of the returned vector equals n_derivs+1.
output_type firstValue() const
Piecewise< T > operator+(Piecewise< T > const &a, Piecewise< T > const &b)
...
double segT(double t, int i=-1) const
Returns the time within a segment, given the 'global' piecewise time.
void concat(const Piecewise< T > &other)
Piecewise< T > reverse(Piecewise< T > const &f)
...
T const & operator[](unsigned i) const
FragmentConcept< T >::BoundsType bounds_local(const Piecewise< T > &f, const OptInterval &_m)
...
FragmentConcept< T >::BoundsType bounds_exact(const Piecewise< T > &f)
...
Piecewise< T > operator/(Piecewise< T > const &a, double b)
...
void setDomain(Interval dom)
output_type operator()(double t) const
double mapToDomain(double t, unsigned i) const
Piecewise< T > lerp(double t, Piecewise< T > const &a, Piecewise< T > b)
Interpolates between a and b.
T::output_type output_type
Piecewise< T > operator-(Piecewise< T > const &a)
...
Polynomial in symmetric power basis.
bool isZero(double eps=EPSILON) const
Template concepts used by 2Geom.
constexpr Coord EPSILON
Default "acceptably small" value.
Low level math functions and compatibility wrappers.
Various utility functions.
OptInterval bounds_exact(Bezier const &b)
Bezier reverse(const Bezier &a)
SBasisN< n > divide(SBasisN< n > const &a, SBasisN< n > const &b, int k)
OptInterval bounds_local(Bezier const &b, OptInterval const &i)
int compose_findSegIdx(std::map< double, unsigned >::iterator const &cut, std::map< double, unsigned >::iterator const &next, std::vector< double > const &levels, SBasis const &g)
D2< T > operator+=(D2< T > &a, D2< T > const &b)
D2< T > operator-(D2< T > const &a, D2< T > const &b)
D2< T > operator*=(D2< T > &a, Point const &b)
D2< T > operator-=(D2< T > &a, D2< T > const &b)
D2< T > compose(D2< T > const &a, T const &b)
std::vector< double > roots(SBasis const &s)
Bezier portion(const Bezier &a, double from, double to)
Bezier integral(Bezier const &a)
Bezier derivative(Bezier const &a)
Piecewise< SBasis > pw_compose_inverse(SBasis const &f, SBasis const &g, unsigned order, double zero)
std::vector< std::vector< double > > multi_roots(SBasis const &f, std::vector< double > const &levels, double htol=1e-7, double vtol=1e-7, double a=0, double b=1)
std::map< double, unsigned > compose_pullback(std::vector< double > const &cuts, SBasis const &g)
OptInterval bounds_fast(Bezier const &b)
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
std::vector< Interval > level_set(D2< SBasis > const &f, Rect region)
D2< T > operator/=(D2< T > &a, Point const &b)
Polynomial in symmetric power basis (S-basis)
ResultTraits< OutputType >::bounds_type BoundsType