Code

Super duper mega (fun!) commit: replaced encoding=utf-8 with fileencoding=utf-8 in...
[inkscape.git] / src / 2geom / sbasis.h
index 118cf2c561731ca3c4f485649c7b916c8256002a..d7390c64d822b51eac3e1c7827bb124c0f33c069 100644 (file)
@@ -1,5 +1,6 @@
-/*
- *  sbasis.h - S-power basis function class
+/**
+ * \file
+ * \brief Defines S-power basis function class
  *
  *  Authors:
  *   Nathan Hurst <njh@mail.csse.monash.edu.au>
 #include <cassert>
 #include <iostream>
 
-#include "linear.h"
-#include "interval.h"
-#include "utils.h"
+#include <2geom/linear.h>
+#include <2geom/interval.h>
+#include <2geom/utils.h>
+#include <2geom/exception.h>
+
+//#define USE_SBASISN 1
+
+
+#if defined(USE_SBASIS_OF)
+
+#include "sbasis-of.h"
 
-namespace Geom {
+#elif defined(USE_SBASISN)
+
+#include "sbasisN.h"
+namespace Geom{
 
 /*** An empty SBasis is identically 0. */
-class SBasis : public std::vector<Linear>{
+class SBasis : public SBasisN<1>;
+
+};
+#else
+
+namespace Geom{
+
+/*** An empty SBasis is identically 0. */
+class SBasis{
+    std::vector<Linear> d;
+    void push_back(Linear const&l) { d.push_back(l); }
+
 public:
+    // As part of our migration away from SBasis isa vector we provide this minimal set of vector interface methods.
+    size_t size() const {return d.size();}
+    Linear operator[](unsigned i) const {
+        return d[i];
+    }
+    Linear& operator[](unsigned i) { return d.at(i); }
+    Linear const* begin() const { return (Linear const*)&*d.begin();}
+    Linear const* end() const { return (Linear const*)&*d.end();}
+    Linear* begin() { return (Linear*)&*d.begin();}
+    Linear* end() { return (Linear*)&*d.end();}
+    bool empty() const {return d.empty();}
+    Linear &back() {return d.back();}
+    Linear const &back() const {return d.back();}
+    void pop_back() { d.pop_back();}
+    void resize(unsigned n) { d.resize(n);}
+    void resize(unsigned n, Linear const& l) { d.resize(n, l);}
+    void reserve(unsigned n) { d.reserve(n);}
+    void clear() {d.clear();}
+    void insert(Linear* before, const Linear* src_begin, const Linear* src_end) { d.insert(std::vector<Linear>::iterator(before), src_begin, src_end);}
+    //void insert(Linear* aa, Linear* bb, Linear* cc} { d.insert(aa, bb, cc);}
+    Linear& at(unsigned i) { return d.at(i);}
+    //void insert(Linear* before, int& n, Linear const &l) { d.insert(std::vector<Linear>::iterator(before), n, l);}
+    bool operator==(SBasis const&B) const { return d == B.d;}
+    bool operator!=(SBasis const&B) const { return d != B.d;}
+    operator std::vector<Linear>() { return d;}
+
+    
     SBasis() {}
     explicit SBasis(double a) {
         push_back(Linear(a,a));
     }
+    explicit SBasis(double a, double b) {
+        push_back(Linear(a,b));
+    }
     SBasis(SBasis const & a) :
-        std::vector<Linear>(a)
+        d(a.d)
     {}
     SBasis(Linear const & bo) {
         push_back(bo);
     }
+    SBasis(Linear* bo) {
+        push_back(*bo);
+    }
+    explicit SBasis(size_t n, Linear const&l) : d(n, l) {}
 
     //IMPL: FragmentConcept
     typedef double output_type;
@@ -66,6 +123,14 @@ public:
         }
         return true;
     }
+    inline bool isConstant() const {
+        if (empty()) return true;
+        for (unsigned i = 0; i < size(); i++) {
+            if(!(*this)[i].isConstant()) return false;
+        }
+        return true;
+    }
+
     bool isFinite() const;
     inline double at0() const { 
         if(empty()) return 0; else return (*this)[0][0];
@@ -73,27 +138,26 @@ public:
     inline double at1() const{
         if(empty()) return 0; else return (*this)[0][1];
     }
+    
+    int degreesOfFreedom() const { return size()*2;}
 
     double valueAt(double t) const {
         double s = t*(1-t);
         double p0 = 0, p1 = 0;
-        double sk = 1;
-//TODO: rewrite as horner
-        for(unsigned k = 0; k < size(); k++) {
-            p0 += sk*(*this)[k][0];
-            p1 += sk*(*this)[k][1];
-            sk *= s;
+        for(unsigned k = size(); k > 0; k--) {
+            const Linear &lin = (*this)[k-1];
+            p0 = p0*s + lin[0];
+            p1 = p1*s + lin[1];
         }
         return (1-t)*p0 + t*p1;
     }
+    //double valueAndDerivative(double t, double &der) const {
+    //}
     double operator()(double t) const {
         return valueAt(t);
     }
 
-    std::vector<double> valueAndDerivatives(double /*t*/, unsigned /*n*/) const {
-        //TODO
-        throw NotImplemented();
-    }
+    std::vector<double> valueAndDerivatives(double t, unsigned n) const;
 
     SBasis toSBasis() const { return SBasis(*this); }
 
@@ -102,46 +166,46 @@ public:
 // compute f(g)
     SBasis operator()(SBasis const & g) const;
 
-    Linear operator[](unsigned i) const {
-        assert(i < size());
-        return std::vector<Linear>::operator[](i);
-    }
-
 //MUTATOR PRISON
-    Linear& operator[](unsigned i) { return this->at(i); }
-
     //remove extra zeros
     void normalize() {
         while(!empty() && 0 == back()[0] && 0 == back()[1])
             pop_back();
     }
+
     void truncate(unsigned k) { if(k < size()) resize(k); }
+private:
+    void derive(); // in place version
 };
 
 //TODO: figure out how to stick this in linear, while not adding an sbasis dep
 inline SBasis Linear::toSBasis() const { return SBasis(*this); }
 
 //implemented in sbasis-roots.cpp
-Interval bounds_exact(SBasis const &a);
-Interval bounds_fast(SBasis const &a, int order = 0);
-Interval bounds_local(SBasis const &a, const Interval &t, int order = 0);
+OptInterval bounds_exact(SBasis const &a);
+OptInterval bounds_fast(SBasis const &a, int order = 0);
+OptInterval bounds_local(SBasis const &a, const OptInterval &t, int order = 0);
+
+/** Returns a function which reverses the domain of a.
+ \param a sbasis function
 
+useful for reversing a parameteric curve.
+*/
 inline SBasis reverse(SBasis const &a) {
-    SBasis result;
-    result.reserve(a.size());
+    SBasis result(a.size(), Linear());
+    
     for(unsigned k = 0; k < a.size(); k++)
-       result.push_back(reverse(a[k]));
+        result[k] = reverse(a[k]);
     return result;
 }
 
 //IMPL: ScalableConcept
 inline SBasis operator-(const SBasis& p) {
     if(p.isZero()) return SBasis();
-    SBasis result;
-    result.reserve(p.size());
+    SBasis result(p.size(), Linear());
         
     for(unsigned i = 0; i < p.size(); i++) {
-        result.push_back(-p[i]);
+        result[i] = -p[i];
     }
     return result;
 }
@@ -158,7 +222,7 @@ SBasis& operator+=(SBasis& a, const SBasis& b);
 SBasis& operator-=(SBasis& a, const SBasis& b);
 
 //TODO: remove?
-inline SBasis operator+(const SBasis & a, Linear const & b) {
+/*inline SBasis operator+(const SBasis & a, Linear const & b) {
     if(b.isZero()) return a;
     if(a.isZero()) return b;
     SBasis result(a);
@@ -184,7 +248,7 @@ inline SBasis& operator-=(SBasis& a, const Linear& b) {
     else
         a[0] -= b;
     return a;
-}
+    }*/
 
 //IMPL: OffsetableConcept
 inline SBasis operator+(const SBasis & a, double b) {
@@ -201,14 +265,14 @@ inline SBasis operator-(const SBasis & a, double b) {
 }
 inline SBasis& operator+=(SBasis& a, double b) {
     if(a.isZero())
-        a.push_back(Linear(b,b));
+        a = SBasis(Linear(b,b));
     else
         a[0] += b;
     return a;
 }
 inline SBasis& operator-=(SBasis& a, double b) {
     if(a.isZero())
-        a.push_back(Linear(-b,-b));
+        a = SBasis(Linear(-b,-b));
     else
         a[0] -= b;
     return a;
@@ -224,6 +288,8 @@ inline SBasis truncate(SBasis const &a, unsigned terms) {
 }
 
 SBasis multiply(SBasis const &a, SBasis const &b);
+// This performs a multiply and accumulate operation in about the same time as multiply.  return a*b + c
+SBasis multiply_add(SBasis const &a, SBasis const &b, SBasis c);
 
 SBasis integral(SBasis const &c);
 SBasis derivative(SBasis const &a);
@@ -243,7 +309,11 @@ inline SBasis& operator*=(SBasis& a, SBasis const & b) {
     return a;
 }
 
-//valuation: degree of the first non zero coefficient.
+/** Returns the degree of the first non zero coefficient.
+ \param a sbasis function
+ \param tol largest abs val considered 0
+ \returns first non zero coefficient
+*/
 inline unsigned 
 valuation(SBasis const &a, double tol=0){
     unsigned val=0;
@@ -262,7 +332,14 @@ SBasis inverse(SBasis a, int k);
 //TODO: requires g(0)=0 & g(1)=1 atm. generalization should be obvious.
 SBasis compose_inverse(SBasis const &f, SBasis const &g, unsigned order=2, double tol=1e-3);
 
+/** Returns the sbasis on domain [0,1] that was t on [from, to]
+ \param a sbasis function
+ \param from,to interval
+ \returns sbasis
+
+*/
 inline SBasis portion(const SBasis &t, double from, double to) { return compose(t, Linear(from, to)); }
+inline SBasis portion(const SBasis &t, Interval ivl) { return compose(t, Linear(ivl[0], ivl[1])); }
 
 // compute f(g)
 inline SBasis
@@ -282,6 +359,7 @@ inline std::ostream &operator<< (std::ostream &out_file, const SBasis & p) {
     return out_file;
 }
 
+// These are deprecated, use sbasis-math.h versions if possible
 SBasis sin(Linear bo, int k);
 SBasis cos(Linear bo, int k);
 
@@ -294,6 +372,7 @@ std::vector<std::vector<double> > multi_roots(SBasis const &f,
                                  double b=1);
     
 }
+#endif
 
 /*
   Local Variables:
@@ -304,5 +383,5 @@ std::vector<std::vector<double> > multi_roots(SBasis const &f,
   fill-column:99
   End:
 */
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
 #endif