Code

CRLF fix
authorjoncruz <joncruz@users.sourceforge.net>
Mon, 17 Dec 2007 06:59:40 +0000 (06:59 +0000)
committerjoncruz <joncruz@users.sourceforge.net>
Mon, 17 Dec 2007 06:59:40 +0000 (06:59 +0000)
src/2geom/ord.h
src/2geom/piecewise.h
src/2geom/poly-dk-solve.cpp
src/2geom/poly-laguerre-solve.cpp
src/2geom/quadtree.h
src/2geom/sbasis.cpp
src/2geom/sweep.cpp
src/live_effects/lpe-pathalongpath.cpp
src/live_effects/lpe-pathalongpath.h

index d0e348aece9778f44180d5602494281a1b0bd521..735de6a3ade5cef8d7f4ce4fd263d32e512dba7f 100644 (file)
@@ -4,11 +4,11 @@
 
 namespace {
 
-enum Cmp {\r
-  LESS_THAN=-1,\r
-  GREATER_THAN=1,\r
-  EQUAL_TO=0\r
-};\r
+enum Cmp {
+  LESS_THAN=-1,
+  GREATER_THAN=1,
+  EQUAL_TO=0
+};
 
 inline Cmp operator-(Cmp x) {
   switch(x) {
@@ -20,16 +20,16 @@ inline Cmp operator-(Cmp x) {
     return EQUAL_TO;
   }
 }
-\r
-template <typename T1, typename T2>\r
-inline Cmp cmp(T1 const &a, T2 const &b) {\r
-  if ( a < b ) {\r
-    return LESS_THAN;\r
-  } else if ( b < a ) {\r
-    return GREATER_THAN;\r
-  } else {\r
-    return EQUAL_TO;\r
-  }\r
+
+template <typename T1, typename T2>
+inline Cmp cmp(T1 const &a, T2 const &b) {
+  if ( a < b ) {
+    return LESS_THAN;
+  } else if ( b < a ) {
+    return GREATER_THAN;
+  } else {
+    return EQUAL_TO;
+  }
 }
 
 }
index c70ecd42cb69be42e8bfd2e4ef846dc190e0ea81..1715997684cec7c7ccff95f8e893c0cd5fe9cdbf 100644 (file)
-/*\r
- * piecewise.h - Piecewise function class\r
- *\r
- * Copyright 2007 Michael Sloan <mgsloan@gmail.com>\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it either under the terms of the GNU Lesser General Public\r
- * License version 2.1 as published by the Free Software Foundation\r
- * (the "LGPL") or, at your option, under the terms of the Mozilla\r
- * Public License Version 1.1 (the "MPL"). If you do not alter this\r
- * notice, a recipient may use your version of this file under either\r
- * the MPL or the LGPL.\r
- *\r
- * You should have received a copy of the LGPL along with this library\r
- * in the file COPYING-LGPL-2.1; if not, output to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
- * You should have received a copy of the MPL along with this library\r
- * in the file COPYING-MPL-1.1\r
- *\r
- * The contents of this file are subject to the Mozilla Public License\r
- * Version 1.1 (the "License"); you may not use this file except in\r
- * compliance with the License. You may obtain a copy of the License at\r
- * http://www.mozilla.org/MPL/\r
- *\r
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY\r
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for\r
- * the specific language governing rights and limitations.\r
- *\r
- */\r
-\r
-#ifndef SEEN_GEOM_PW_SB_H\r
-#define SEEN_GEOM_PW_SB_H\r
-\r
-#include "sbasis.h"\r
-#include <vector>\r
-#include <map>\r
-\r
-#include "concepts.h"\r
-#include "isnan.h"\r
-#include <boost/concept_check.hpp>\r
-\r
-namespace Geom {\r
-\r
-template <typename T>\r
-class Piecewise {\r
-  BOOST_CLASS_REQUIRE(T, Geom, FragmentConcept);\r
-\r
-  public:\r
-    std::vector<double> cuts;\r
-    std::vector<T> segs;\r
-    //segs[i] stretches from cuts[i] to cuts[i+1].\r
-\r
-    Piecewise() {}\r
-\r
-    explicit Piecewise(const T &s) {\r
-        push_cut(0.);\r
-        push_seg(s);\r
-        push_cut(1.);\r
-    }\r
-\r
-    typedef typename T::output_type output_type;\r
-\r
-    explicit Piecewise(const output_type & v) {\r
-        push_cut(0.);\r
-        push_seg(T(v));\r
-        push_cut(1.);\r
-    }\r
-\r
-    inline T operator[](unsigned i) const { return segs[i]; }\r
-    inline T &operator[](unsigned i) { return segs[i]; }\r
-    inline output_type operator()(double t) const { return valueAt(t); }\r
-    inline output_type valueAt(double t) const {\r
-        unsigned n = segN(t);\r
-        return segs[n](segT(t, n));\r
-    }\r
-    //TODO: maybe it is not a good idea to have this?\r
-    Piecewise<T> operator()(SBasis f);\r
-    Piecewise<T> operator()(Piecewise<SBasis>f);\r
-\r
-    inline unsigned size() const { return segs.size(); }\r
-    inline bool empty() const { return segs.empty(); }\r
-\r
-    /**Convenience/implementation hiding function to add segment/cut pairs.\r
-     * Asserts that basic size and order invariants are correct\r
-     */\r
-    inline void push(const T &s, double to) {\r
-        assert(cuts.size() - segs.size() == 1);\r
-        push_seg(s);\r
-        push_cut(to);\r
-    }\r
-    //Convenience/implementation hiding function to add cuts.\r
-    inline void push_cut(double c) {\r
-        assert_invariants(cuts.empty() || c > cuts.back()); \r
-        cuts.push_back(c);\r
-    }\r
-    //Convenience/implementation hiding function to add segments.\r
-    inline void push_seg(const T &s) { segs.push_back(s); }\r
-\r
-    /**Returns the segment index which corresponds to a 'global' piecewise time.\r
-     * Also takes optional low/high parameters to expedite the search for the segment.\r
-     */\r
-    inline unsigned segN(double t, int low = 0, int high = -1) const {\r
-        high = (high == -1) ? size() : high;\r
-        if(t < cuts[0]) return 0;\r
-        if(t >= cuts[size()]) return size() - 1;\r
-        while(low < high) {\r
-            int mid = (high + low) / 2; //Lets not plan on having huge (> INT_MAX / 2) cut sequences\r
-            double mv = cuts[mid];\r
-            if(mv < t) {\r
-                if(t < cuts[mid + 1]) return mid; else low = mid + 1;\r
-            } else if(t < mv) {\r
-                if(cuts[mid - 1] < t) return mid - 1; else high = mid - 1;\r
-            } else {\r
-                return mid;\r
-            }\r
-        }\r
-        return low;\r
-    }\r
-\r
-    /**Returns the time within a segment, given the 'global' piecewise time.\r
-     * Also takes an optional index parameter which may be used for efficiency or to find the time on a\r
-     * segment outside its range.  If it is left to its default, -1, it will call segN to find the index.\r
-     */\r
-    inline double segT(double t, int i = -1) const {\r
-        if(i == -1) i = segN(t);\r
-        assert(i >= 0);\r
-        return (t - cuts[i]) / (cuts[i+1] - cuts[i]);\r
-    }\r
-\r
-    inline double mapToDomain(double t, unsigned i) const {\r
-        return (1-t)*cuts[i] + t*cuts[i+1]; //same as: t * (cuts[i+1] - cuts[i]) + cuts[i]\r
-    }    \r
-\r
-    //Offsets the piecewise domain\r
-    inline void offsetDomain(double o) {\r
-        assert(is_finite(o));\r
-        if(o != 0)\r
-            for(unsigned i = 0; i <= size(); i++)\r
-                cuts[i] += o;\r
-    }\r
-\r
-    //Scales the domain of the function by a value. 0 will result in an empty Piecewise.\r
-    inline void scaleDomain(double s) {\r
-        assert(s > 0);\r
-        if(s == 0) {\r
-            cuts.clear(); segs.clear();\r
-            return;\r
-        }\r
-        for(unsigned i = 0; i <= size(); i++)\r
-            cuts[i] *= s;\r
-    }\r
-\r
-    //Retrieves the domain in interval form\r
-    inline Interval domain() const { return Interval(cuts.front(), cuts.back()); }\r
-\r
-    //Transforms the domain into another interval\r
-    inline void setDomain(Interval dom) {\r
-        if(empty()) return;\r
-        if(dom.isEmpty()) {\r
-            cuts.clear(); segs.clear();\r
-            return;\r
-        }\r
-        double cf = cuts.front();\r
-        double o = dom.min() - cf, s = dom.extent() / (cuts.back() - cf);\r
-        for(unsigned i = 0; i <= size(); i++)\r
-            cuts[i] = (cuts[i] - cf) * s + o;\r
-    }\r
-\r
-    //Concatenates this Piecewise function with another, offseting time of the other to match the end.\r
-    inline void concat(const Piecewise<T> &other) {\r
-        if(other.empty()) return;\r
-\r
-        if(empty()) { \r
-            cuts = other.cuts; segs = other.segs;\r
-            return;\r
-        }\r
-\r
-        segs.insert(segs.end(), other.segs.begin(), other.segs.end());\r
-        double t = cuts.back() - other.cuts.front();        \r
-        for(unsigned i = 0; i < other.size(); i++)\r
-            push_cut(other.cuts[i + 1] + t);\r
-    }\r
-\r
-    //Like concat, but ensures continuity.\r
-    inline void continuousConcat(const Piecewise<T> &other) {\r
-        boost::function_requires<AddableConcept<typename T::output_type> >();\r
-        if(other.empty()) return;\r
-        typename T::output_type y = segs.back().at1() - other.segs.front().at0();\r
-\r
-        if(empty()) {\r
-            for(unsigned i = 0; i < other.size(); i++)\r
-                push_seg(other[i] + y);\r
-            cuts = other.cuts;\r
-            return;\r
-        }\r
-\r
-        double t = cuts.back() - other.cuts.front();\r
-        for(unsigned i = 0; i < other.size(); i++)\r
-            push(other[i] + y, other.cuts[i + 1] + t);\r
-    }\r
-\r
-    //returns true if the Piecewise<T> meets some basic invariants.\r
-    inline bool invariants() const {\r
-        // segs between cuts\r
-        if(!(segs.size() + 1 == cuts.size() || (segs.empty() && cuts.empty())))\r
-            return false;\r
-        // cuts in order\r
-        for(unsigned i = 0; i < segs.size(); i++)\r
-            if(cuts[i] >= cuts[i+1])\r
-                return false;\r
-        return true;\r
-    }\r
-\r
-};\r
-\r
-template<typename T>\r
-inline typename FragmentConcept<T>::BoundsType bounds_fast(const Piecewise<T> &f) {\r
-    boost::function_requires<FragmentConcept<T> >();\r
-    \r
-    if(f.empty()) return typename FragmentConcept<T>::BoundsType();\r
-    typename FragmentConcept<T>::BoundsType ret(bounds_fast(f[0]));\r
-    for(unsigned i = 1; i < f.size(); i++)\r
-        ret.unionWith(bounds_fast(f[i])); \r
-    return ret;\r
-}\r
-\r
-template<typename T>\r
-inline typename FragmentConcept<T>::BoundsType bounds_exact(const Piecewise<T> &f) {\r
-    boost::function_requires<FragmentConcept<T> >();\r
-    \r
-    if(f.empty()) return typename FragmentConcept<T>::BoundsType();\r
-    typename FragmentConcept<T>::BoundsType ret(bounds_exact(f[0]));\r
-    for(unsigned i = 1; i < f.size(); i++)\r
-        ret.unionWith(bounds_exact(f[i])); \r
-    return ret;\r
-}\r
-\r
-template<typename T>\r
-inline typename FragmentConcept<T>::BoundsType bounds_local(const Piecewise<T> &f, const Interval &m) {\r
-    boost::function_requires<FragmentConcept<T> >();\r
-    \r
-    if(f.empty()) return typename FragmentConcept<T>::BoundsType();\r
-    if(m.isEmpty()) return typename FragmentConcept<T>::BoundsType(f(m.min()));\r
-    \r
-    unsigned fi = f.segN(m.min()), ti = f.segN(m.max());\r
-    double ft = f.segT(m.min(), fi), tt = f.segT(m.max(), ti);\r
-    \r
-    if(fi == ti) return bounds_local(f[fi], Interval(ft, tt));\r
-    \r
-    typename FragmentConcept<T>::BoundsType ret(bounds_local(f[fi], Interval(ft, 1.)));\r
-    for(unsigned i = fi + 1; i < ti; i++)\r
-        ret.unionWith(bounds_exact(f[i]));\r
-    if(tt != 0.) ret.unionWith(bounds_local(f[ti], Interval(0., tt)));\r
-    \r
-    return ret;\r
-}\r
-\r
-//returns a portion of a piece of a Piecewise<T>, given the piece's index and a to/from time.\r
-template<typename T>\r
-T elem_portion(const Piecewise<T> &a, unsigned i, double from, double to) {\r
-    assert(i < a.size());\r
-    double rwidth = 1 / (a.cuts[i+1] - a.cuts[i]);\r
-    return portion( a[i], (from - a.cuts[i]) * rwidth, (to - a.cuts[i]) * rwidth );\r
-}\r
-\r
-/**Piecewise<T> partition(const Piecewise<T> &pw, std::vector<double> const &c);\r
- * Further subdivides the Piecewise<T> such that there is a cut at every value in c.\r
- * Precondition: c sorted lower to higher.\r
- * \r
- * //Given Piecewise<T> a and b:\r
- * Piecewise<T> ac = a.partition(b.cuts);\r
- * Piecewise<T> bc = b.partition(a.cuts);\r
- * //ac.cuts should be equivalent to bc.cuts\r
- */\r
-template<typename T>\r
-Piecewise<T> partition(const Piecewise<T> &pw, std::vector<double> const &c) {\r
-    assert(pw.invariants());\r
-    if(c.empty()) return Piecewise<T>(pw);\r
-\r
-    Piecewise<T> ret = Piecewise<T>();\r
-    ret.cuts.reserve(c.size() + pw.cuts.size());\r
-    ret.segs.reserve(c.size() + pw.cuts.size() - 1);\r
-\r
-    if(pw.empty()) {\r
-        ret.cuts = c;\r
-        for(unsigned i = 0; i < c.size() - 1; i++)\r
-            ret.push_seg(T());\r
-        return ret;\r
-    }\r
-\r
-    unsigned si = 0, ci = 0;     //Segment index, Cut index\r
-\r
-    //if the cuts have something earlier than the Piecewise<T>, add portions of the first segment\r
-    while(c[ci] < pw.cuts.front() && ci < c.size()) {\r
-        bool isLast = (ci == c.size()-1 || c[ci + 1] >= pw.cuts.front());\r
-        ret.push_cut(c[ci]);\r
-        ret.push_seg( elem_portion(pw, 0, c[ci], isLast ? pw.cuts.front() : c[ci + 1]) );\r
-        ci++;\r
-    }\r
-\r
-    ret.push_cut(pw.cuts[0]);\r
-    double prev = pw.cuts[0];    //previous cut\r
-    //Loop which handles cuts within the Piecewise<T> domain\r
-    //Should have the cuts = segs + 1 invariant\r
-    while(si < pw.size() && ci <= c.size()) {\r
-        if(ci == c.size() && prev <= pw.cuts[si]) { //cuts exhausted, straight copy the rest\r
-            ret.segs.insert(ret.segs.end(), pw.segs.begin() + si, pw.segs.end());\r
-            ret.cuts.insert(ret.cuts.end(), pw.cuts.begin() + si + 1, pw.cuts.end());\r
-            return ret;\r
-        }else if(ci == c.size() || c[ci] >= pw.cuts[si + 1]) {  //no more cuts within this segment, finalize\r
-            if(prev > pw.cuts[si]) {      //segment already has cuts, so portion is required\r
-                ret.push_seg(portion(pw[si], pw.segT(prev, si), 1.0));\r
-            } else {                     //plain copy is fine\r
-                ret.push_seg(pw[si]);\r
-            }\r
-            ret.push_cut(pw.cuts[si + 1]);\r
-            prev = pw.cuts[si + 1];\r
-            si++;\r
-        } else if(c[ci] == pw.cuts[si]){                  //coincident\r
-            //Already finalized the seg with the code immediately above\r
-            ci++;\r
-        } else {                                         //plain old subdivision\r
-            ret.push(elem_portion(pw, si, prev, c[ci]), c[ci]);\r
-            prev = c[ci];\r
-            ci++;\r
-        }\r
-    }\r
-    \r
-    //input cuts extend further than this Piecewise<T>, extend the last segment.\r
-    while(ci < c.size()) {\r
-        if(c[ci] > prev) {\r
-            ret.push(elem_portion(pw, pw.size() - 1, prev, c[ci]), c[ci]);\r
-            prev = c[ci];\r
-        }\r
-        ci++;\r
-    }\r
-    return ret;\r
-}\r
-\r
-/**Piecewise<T> portion(const Piecewise<T> &pw, double from, double to);\r
- * Returns a Piecewise<T> with a defined domain of [min(from, to), max(from, to)].\r
- */\r
-template<typename T>\r
-Piecewise<T> portion(const Piecewise<T> &pw, double from, double to) {\r
-    if(pw.empty() || from == to) return Piecewise<T>();\r
-\r
-    Piecewise<T> ret;\r
-\r
-    double temp = from;\r
-    from = std::min(from, to);\r
-    to = std::max(temp, to);\r
-    \r
-    unsigned i = pw.segN(from);\r
-    ret.push_cut(from);\r
-    if(i == pw.size() - 1 || to < pw.cuts[i + 1]) {    //to/from inhabit the same segment\r
-        ret.push(elem_portion(pw, i, from, to), to);\r
-        return ret;\r
-    }\r
-    ret.push_seg(portion( pw[i], pw.segT(from, i), 1.0 ));\r
-    i++;\r
-    unsigned fi = pw.segN(to, i);\r
-\r
-    ret.segs.insert(ret.segs.end(), pw.segs.begin() + i, pw.segs.begin() + fi);  //copy segs\r
-    ret.cuts.insert(ret.cuts.end(), pw.cuts.begin() + i, pw.cuts.begin() + fi + 1);  //and their cuts\r
-\r
-    ret.push_seg( portion(pw[fi], 0.0, pw.segT(to, fi)));\r
-    if(to != ret.cuts.back()) ret.push_cut(to);\r
-    ret.invariants();\r
-    return ret;\r
-}\r
-\r
-template<typename T>\r
-Piecewise<T> remove_short_cuts(Piecewise<T> const &f, double tol) {\r
-    if(f.empty()) return f;\r
-    Piecewise<T> ret;\r
-    ret.push_cut(f.cuts[0]);\r
-    for(unsigned i=0; i<f.size(); i++){\r
-        if (f.cuts[i+1]-f.cuts[i] >= tol || i==f.size()-1) {\r
-            ret.push(f[i], f.cuts[i+1]);\r
-        }\r
-    }\r
-    return ret;\r
-}\r
-\r
-template<typename T>\r
-Piecewise<T> remove_short_cuts_extending(Piecewise<T> const &f, double tol) {\r
-    if(f.empty()) return f;\r
-    Piecewise<T> ret;\r
-    ret.push_cut(f.cuts[0]);\r
-    double last = f.cuts[0]; // last cut included\r
-    for(unsigned i=0; i<f.size(); i++){\r
-        if (f.cuts[i+1]-f.cuts[i] >= tol) {\r
-            ret.push(elem_portion(f, i, last, f.cuts[i+1]), f.cuts[i+1]);\r
-            last = f.cuts[i+1];\r
-        }\r
-    }\r
-    return ret;\r
-}\r
-\r
-template<typename T>\r
-std::vector<double> roots(const Piecewise<T> &pw) {\r
-    std::vector<double> ret;\r
-    for(unsigned i = 0; i < pw.size(); i++) {\r
-        std::vector<double> sr = roots(pw[i]);\r
-        for (unsigned j = 0; j < sr.size(); j++) ret.push_back(sr[j] * (pw.cuts[i + 1] - pw.cuts[i]) + pw.cuts[i]);\r
-\r
-    }\r
-    return ret;\r
-}\r
-\r
-//IMPL: OffsetableConcept\r
-template<typename T>\r
-Piecewise<T> operator+(Piecewise<T> const &a, typename T::output_type b) {\r
-    boost::function_requires<OffsetableConcept<T> >();\r
-//TODO:empty\r
-    Piecewise<T> ret = Piecewise<T>();\r
-    ret.cuts = a.cuts;\r
-    for(unsigned i = 0; i < a.size();i++)\r
-        ret.push_seg(a[i] + b);\r
-    return ret;\r
-}\r
-template<typename T>\r
-Piecewise<T> operator-(Piecewise<T> const &a, typename T::output_type b) {\r
-    boost::function_requires<OffsetableConcept<T> >();\r
-//TODO: empty\r
-    Piecewise<T> ret = Piecewise<T>();\r
-    ret.cuts = a.cuts;\r
-    for(unsigned i = 0; i < a.size();i++)\r
-        ret.push_seg(a[i] - b);\r
-    return ret;\r
-}\r
-template<typename T>\r
-Piecewise<T> operator+=(Piecewise<T>& a, typename T::output_type b) {\r
-    boost::function_requires<OffsetableConcept<T> >();\r
-\r
-    if(a.empty()) { a.push_cut(0.); a.push(T(b), 1.); return a; }\r
-\r
-    for(unsigned i = 0; i < a.size();i++)\r
-        a[i] += b;\r
-    return a;\r
-}\r
-template<typename T>\r
-Piecewise<T> operator-=(Piecewise<T>& a, typename T::output_type b) {\r
-    boost::function_requires<OffsetableConcept<T> >();\r
-\r
-    if(a.empty()) { a.push_cut(0.); a.push(T(b), 1.); return a; }\r
-\r
-    for(unsigned i = 0;i < a.size();i++)\r
-        a[i] -= b;\r
-    return a;\r
-}\r
-\r
-//IMPL: ScalableConcept\r
-template<typename T>\r
-Piecewise<T> operator-(Piecewise<T> const &a) {\r
-    boost::function_requires<ScalableConcept<T> >();\r
-\r
-    Piecewise<T> ret;\r
-    ret.cuts = a.cuts;\r
-    for(unsigned i = 0; i < a.size();i++)\r
-        ret.push_seg(- a[i]);\r
-    return ret;\r
-}\r
-template<typename T>\r
-Piecewise<T> operator*(Piecewise<T> const &a, double b) {\r
-    boost::function_requires<ScalableConcept<T> >();\r
-\r
-    if(a.empty()) return Piecewise<T>();\r
-\r
-    Piecewise<T> ret;\r
-    ret.cuts = a.cuts;\r
-    for(unsigned i = 0; i < a.size();i++)\r
-        ret.push_seg(a[i] * b);\r
-    return ret;\r
-}\r
-template<typename T>\r
-Piecewise<T> operator/(Piecewise<T> const &a, double b) {\r
-    boost::function_requires<ScalableConcept<T> >();\r
-\r
-    //FIXME: b == 0?\r
-    if(a.empty()) return Piecewise<T>();\r
-\r
-    Piecewise<T> ret;\r
-    ret.cuts = a.cuts;\r
-    for(unsigned i = 0; i < a.size();i++)\r
-        ret.push_seg(a[i] / b);\r
-    return ret;\r
-}\r
-template<typename T>\r
-Piecewise<T> operator*=(Piecewise<T>& a, double b) {\r
-    boost::function_requires<ScalableConcept<T> >();\r
-\r
-    if(a.empty()) return Piecewise<T>();\r
-\r
-    for(unsigned i = 0; i < a.size();i++)\r
-        a[i] *= b;\r
-    return a;\r
-}\r
-template<typename T>\r
-Piecewise<T> operator/=(Piecewise<T>& a, double b) {\r
-    boost::function_requires<ScalableConcept<T> >();\r
-\r
-    //FIXME: b == 0?\r
-    if(a.empty()) return Piecewise<T>();\r
-\r
-    for(unsigned i = 0; i < a.size();i++)\r
-        a[i] /= b;\r
-    return a;\r
-}\r
-\r
-//IMPL: AddableConcept\r
-template<typename T>\r
-Piecewise<T> operator+(Piecewise<T> const &a, Piecewise<T> const &b) {\r
-    boost::function_requires<AddableConcept<T> >();\r
-\r
-    Piecewise<T> pa = partition(a, b.cuts), pb = partition(b, a.cuts);\r
-    Piecewise<T> ret = Piecewise<T>();\r
-    assert(pa.size() == pb.size());\r
-    ret.cuts = pa.cuts;\r
-    for (unsigned i = 0; i < pa.size(); i++)\r
-        ret.push_seg(pa[i] + pb[i]);\r
-    return ret;\r
-}\r
-template<typename T>\r
-Piecewise<T> operator-(Piecewise<T> const &a, Piecewise<T> const &b) {\r
-    boost::function_requires<AddableConcept<T> >();\r
-\r
-    Piecewise<T> pa = partition(a, b.cuts), pb = partition(b, a.cuts);\r
-    Piecewise<T> ret = Piecewise<T>();\r
-    assert(pa.size() == pb.size());\r
-    ret.cuts = pa.cuts;\r
-    for (unsigned i = 0; i < pa.size(); i++)\r
-        ret.push_seg(pa[i] - pb[i]);\r
-    return ret;\r
-}\r
-template<typename T>\r
-inline Piecewise<T> operator+=(Piecewise<T> &a, Piecewise<T> const &b) {\r
-    a = a+b;\r
-    return a;\r
-}\r
-template<typename T>\r
-inline Piecewise<T> operator-=(Piecewise<T> &a, Piecewise<T> const &b) {\r
-    a = a-b;\r
-    return a;\r
-}\r
-\r
-template<typename T1,typename T2>\r
-Piecewise<T2> operator*(Piecewise<T1> const &a, Piecewise<T2> const &b) {\r
-    //function_requires<MultiplicableConcept<T1> >();\r
-    //function_requires<MultiplicableConcept<T2> >();\r
-\r
-    Piecewise<T1> pa = partition(a, b.cuts);\r
-    Piecewise<T2> pb = partition(b, a.cuts);\r
-    Piecewise<T2> ret = Piecewise<T2>();\r
-    assert(pa.size() == pb.size());\r
-    ret.cuts = pa.cuts;\r
-    for (unsigned i = 0; i < pa.size(); i++)\r
-        ret.push_seg(pa[i] * pb[i]);\r
-    return ret;\r
-}\r
-\r
-template<typename T>\r
-inline Piecewise<T> operator*=(Piecewise<T> &a, Piecewise<T> const &b) {\r
-    a = a * b;\r
-    return a;\r
-}\r
-\r
-Piecewise<SBasis> divide(Piecewise<SBasis> const &a, Piecewise<SBasis> const &b, unsigned k);\r
-//TODO: replace divide(a,b,k) by divide(a,b,tol,k)?\r
-//TODO: atm, relative error is ~(tol/a)%. Find a way to make it independant of a.\r
-//Nota: the result is 'truncated' where b is smaller than 'zero': ~ a/max(b,zero). \r
-Piecewise<SBasis> \r
-divide(Piecewise<SBasis> const &a, Piecewise<SBasis> const &b, double tol, unsigned k, double zero=1.e-3);\r
-Piecewise<SBasis> \r
-divide(SBasis const &a, Piecewise<SBasis> const &b, double tol, unsigned k, double zero=1.e-3);\r
-Piecewise<SBasis> \r
-divide(Piecewise<SBasis> const &a, SBasis const &b, double tol, unsigned k, double zero=1.e-3);\r
-Piecewise<SBasis> \r
-divide(SBasis const &a, SBasis const &b, double tol, unsigned k, double zero=1.e-3);\r
-\r
-//Composition: functions called compose_* are pieces of compose that are factored out in pw.cpp.\r
-std::map<double,unsigned> compose_pullback(std::vector<double> const &cuts, SBasis const &g);\r
-int compose_findSegIdx(std::map<double,unsigned>::iterator  const &cut,\r
-                       std::map<double,unsigned>::iterator  const &next,\r
-                       std::vector<double>  const &levels,\r
-                       SBasis const &g);\r
-\r
-//TODO: add concept check\r
-template<typename T>\r
-Piecewise<T> compose(Piecewise<T> const &f, SBasis const &g){\r
-    Piecewise<T> result;\r
-    if (f.empty()) return result;\r
-    if (g.isZero()) return Piecewise<T>(f(0));\r
-    if (f.size()==1){\r
-        double t0 = f.cuts[0], width = f.cuts[1] - t0;\r
-        return (Piecewise<T>) compose(f.segs[0],compose(Linear(-t0 / width, (1-t0) / width), g));\r
-    }\r
-    \r
-    //first check bounds...\r
-    Interval bs = bounds_fast(g);\r
-    if (f.cuts.front() > bs.max()  || bs.min() > f.cuts.back()){\r
-        int idx = (bs.max() < f.cuts[1]) ? 0 : f.cuts.size()-2;\r
-        double t0 = f.cuts[idx], width = f.cuts[idx+1] - t0;\r
-        return (Piecewise<T>) compose(f.segs[idx],compose(Linear(-t0 / width, (1-t0) / width), g));  \r
-    }\r
-    \r
-    std::vector<double> levels;//we can forget first and last cuts...\r
-    levels.insert(levels.begin(),f.cuts.begin()+1,f.cuts.end()-1);\r
-    //TODO: use a std::vector<pairs<double,unsigned> > instead of a map<double,unsigned>.\r
-    std::map<double,unsigned> cuts_pb = compose_pullback(levels,g);\r
-    \r
-    //-- Compose each piece of g with the relevant seg of f.\r
-    result.cuts.push_back(0.);\r
-    std::map<double,unsigned>::iterator cut=cuts_pb.begin();\r
-    std::map<double,unsigned>::iterator next=cut; next++;\r
-    while(next!=cuts_pb.end()){\r
-        //assert(std::abs(int((*cut).second-(*next).second))<1);\r
-        //TODO: find a way to recover from this error? the root finder missed some root;\r
-        //  the levels/variations of f might be too close/fast...\r
-        int idx = compose_findSegIdx(cut,next,levels,g);\r
-        double t0=(*cut).first;\r
-        double t1=(*next).first;\r
-        \r
-        SBasis sub_g=compose(g, Linear(t0,t1));\r
-        sub_g=compose(Linear(-f.cuts[idx]/(f.cuts[idx+1]-f.cuts[idx]),\r
-                             (1-f.cuts[idx])/(f.cuts[idx+1]-f.cuts[idx])),sub_g);\r
-        result.push(compose(f[idx],sub_g),t1);\r
-        cut++;\r
-        next++;\r
-    }\r
-    return(result);\r
-} \r
-\r
-//TODO: add concept check for following composition functions\r
-template<typename T>\r
-Piecewise<T> compose(Piecewise<T> const &f, Piecewise<SBasis> const &g){\r
-  Piecewise<T> result;\r
-  for(unsigned i = 0; i < g.segs.size(); i++){\r
-      Piecewise<T> fgi=compose(f, g.segs[i]);\r
-      fgi.setDomain(Interval(g.cuts[i], g.cuts[i+1]));\r
-      result.concat(fgi);\r
-  }\r
-  return result;\r
-}\r
-\r
-template <typename T>\r
-Piecewise<T> Piecewise<T>::operator()(SBasis f){return compose((*this),f);}\r
-template <typename T>\r
-Piecewise<T> Piecewise<T>::operator()(Piecewise<SBasis>f){return compose((*this),f);}\r
-\r
-template<typename T>\r
-Piecewise<T> integral(Piecewise<T> const &a) {\r
-    Piecewise<T> result;\r
-    result.segs.resize(a.segs.size());\r
-    result.cuts = a.cuts;\r
-    typename T::output_type c = a.segs[0].at0();\r
-    for(unsigned i = 0; i < a.segs.size(); i++){\r
-        result.segs[i] = integral(a.segs[i])*(a.cuts[i+1]-a.cuts[i]);\r
-        result.segs[i]+= c-result.segs[i].at0();\r
-        c = result.segs[i].at1();\r
-    }\r
-    return result;\r
-}\r
-\r
-template<typename T>\r
-Piecewise<T> derivative(Piecewise<T> const &a) {\r
-    Piecewise<T> result;\r
-    result.segs.resize(a.segs.size());\r
-    result.cuts = a.cuts;\r
-    for(unsigned i = 0; i < a.segs.size(); i++){\r
-        result.segs[i] = derivative(a.segs[i])/(a.cuts[i+1]-a.cuts[i]);\r
-    }\r
-    return result;\r
-}\r
-\r
-std::vector<double> roots(Piecewise<SBasis> const &f);\r
-\r
-}\r
-\r
-#endif //SEEN_GEOM_PW_SB_H\r
-/*\r
-  Local Variables:\r
-  mode:c++\r
-  c-file-style:"stroustrup"\r
-  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
-  indent-tabs-mode:nil\r
-  fill-column:99\r
-  End:\r
-*/\r
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :\r
+/*
+ * piecewise.h - Piecewise function class
+ *
+ * Copyright 2007 Michael Sloan <mgsloan@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, output to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ */
+
+#ifndef SEEN_GEOM_PW_SB_H
+#define SEEN_GEOM_PW_SB_H
+
+#include "sbasis.h"
+#include <vector>
+#include <map>
+
+#include "concepts.h"
+#include "isnan.h"
+#include <boost/concept_check.hpp>
+
+namespace Geom {
+
+template <typename T>
+class Piecewise {
+  BOOST_CLASS_REQUIRE(T, Geom, FragmentConcept);
+
+  public:
+    std::vector<double> cuts;
+    std::vector<T> segs;
+    //segs[i] stretches from cuts[i] to cuts[i+1].
+
+    Piecewise() {}
+
+    explicit Piecewise(const T &s) {
+        push_cut(0.);
+        push_seg(s);
+        push_cut(1.);
+    }
+
+    typedef typename T::output_type output_type;
+
+    explicit Piecewise(const output_type & v) {
+        push_cut(0.);
+        push_seg(T(v));
+        push_cut(1.);
+    }
+
+    inline T operator[](unsigned i) const { return segs[i]; }
+    inline T &operator[](unsigned i) { return segs[i]; }
+    inline output_type operator()(double t) const { return valueAt(t); }
+    inline output_type valueAt(double t) const {
+        unsigned n = segN(t);
+        return segs[n](segT(t, n));
+    }
+    //TODO: maybe it is not a good idea to have this?
+    Piecewise<T> operator()(SBasis f);
+    Piecewise<T> operator()(Piecewise<SBasis>f);
+
+    inline unsigned size() const { return segs.size(); }
+    inline bool empty() const { return segs.empty(); }
+
+    /**Convenience/implementation hiding function to add segment/cut pairs.
+     * Asserts that basic size and order invariants are correct
+     */
+    inline void push(const T &s, double to) {
+        assert(cuts.size() - segs.size() == 1);
+        push_seg(s);
+        push_cut(to);
+    }
+    //Convenience/implementation hiding function to add cuts.
+    inline void push_cut(double c) {
+        assert_invariants(cuts.empty() || c > cuts.back());
+        cuts.push_back(c);
+    }
+    //Convenience/implementation hiding function to add segments.
+    inline void push_seg(const T &s) { segs.push_back(s); }
+
+    /**Returns the segment index which corresponds to a 'global' piecewise time.
+     * Also takes optional low/high parameters to expedite the search for the segment.
+     */
+    inline unsigned segN(double t, int low = 0, int high = -1) const {
+        high = (high == -1) ? size() : high;
+        if(t < cuts[0]) return 0;
+        if(t >= cuts[size()]) return size() - 1;
+        while(low < high) {
+            int mid = (high + low) / 2; //Lets not plan on having huge (> INT_MAX / 2) cut sequences
+            double mv = cuts[mid];
+            if(mv < t) {
+                if(t < cuts[mid + 1]) return mid; else low = mid + 1;
+            } else if(t < mv) {
+                if(cuts[mid - 1] < t) return mid - 1; else high = mid - 1;
+            } else {
+                return mid;
+            }
+        }
+        return low;
+    }
+
+    /**Returns the time within a segment, given the 'global' piecewise time.
+     * Also takes an optional index parameter which may be used for efficiency or to find the time on a
+     * segment outside its range.  If it is left to its default, -1, it will call segN to find the index.
+     */
+    inline double segT(double t, int i = -1) const {
+        if(i == -1) i = segN(t);
+        assert(i >= 0);
+        return (t - cuts[i]) / (cuts[i+1] - cuts[i]);
+    }
+
+    inline double mapToDomain(double t, unsigned i) const {
+        return (1-t)*cuts[i] + t*cuts[i+1]; //same as: t * (cuts[i+1] - cuts[i]) + cuts[i]
+    }
+
+    //Offsets the piecewise domain
+    inline void offsetDomain(double o) {
+        assert(is_finite(o));
+        if(o != 0)
+            for(unsigned i = 0; i <= size(); i++)
+                cuts[i] += o;
+    }
+
+    //Scales the domain of the function by a value. 0 will result in an empty Piecewise.
+    inline void scaleDomain(double s) {
+        assert(s > 0);
+        if(s == 0) {
+            cuts.clear(); segs.clear();
+            return;
+        }
+        for(unsigned i = 0; i <= size(); i++)
+            cuts[i] *= s;
+    }
+
+    //Retrieves the domain in interval form
+    inline Interval domain() const { return Interval(cuts.front(), cuts.back()); }
+
+    //Transforms the domain into another interval
+    inline void setDomain(Interval dom) {
+        if(empty()) return;
+        if(dom.isEmpty()) {
+            cuts.clear(); segs.clear();
+            return;
+        }
+        double cf = cuts.front();
+        double o = dom.min() - cf, s = dom.extent() / (cuts.back() - cf);
+        for(unsigned i = 0; i <= size(); i++)
+            cuts[i] = (cuts[i] - cf) * s + o;
+    }
+
+    //Concatenates this Piecewise function with another, offseting time of the other to match the end.
+    inline void concat(const Piecewise<T> &other) {
+        if(other.empty()) return;
+
+        if(empty()) {
+            cuts = other.cuts; segs = other.segs;
+            return;
+        }
+
+        segs.insert(segs.end(), other.segs.begin(), other.segs.end());
+        double t = cuts.back() - other.cuts.front();
+        for(unsigned i = 0; i < other.size(); i++)
+            push_cut(other.cuts[i + 1] + t);
+    }
+
+    //Like concat, but ensures continuity.
+    inline void continuousConcat(const Piecewise<T> &other) {
+        boost::function_requires<AddableConcept<typename T::output_type> >();
+        if(other.empty()) return;
+        typename T::output_type y = segs.back().at1() - other.segs.front().at0();
+
+        if(empty()) {
+            for(unsigned i = 0; i < other.size(); i++)
+                push_seg(other[i] + y);
+            cuts = other.cuts;
+            return;
+        }
+
+        double t = cuts.back() - other.cuts.front();
+        for(unsigned i = 0; i < other.size(); i++)
+            push(other[i] + y, other.cuts[i + 1] + t);
+    }
+
+    //returns true if the Piecewise<T> meets some basic invariants.
+    inline bool invariants() const {
+        // segs between cuts
+        if(!(segs.size() + 1 == cuts.size() || (segs.empty() && cuts.empty())))
+            return false;
+        // cuts in order
+        for(unsigned i = 0; i < segs.size(); i++)
+            if(cuts[i] >= cuts[i+1])
+                return false;
+        return true;
+    }
+
+};
+
+template<typename T>
+inline typename FragmentConcept<T>::BoundsType bounds_fast(const Piecewise<T> &f) {
+    boost::function_requires<FragmentConcept<T> >();
+
+    if(f.empty()) return typename FragmentConcept<T>::BoundsType();
+    typename FragmentConcept<T>::BoundsType ret(bounds_fast(f[0]));
+    for(unsigned i = 1; i < f.size(); i++)
+        ret.unionWith(bounds_fast(f[i]));
+    return ret;
+}
+
+template<typename T>
+inline typename FragmentConcept<T>::BoundsType bounds_exact(const Piecewise<T> &f) {
+    boost::function_requires<FragmentConcept<T> >();
+
+    if(f.empty()) return typename FragmentConcept<T>::BoundsType();
+    typename FragmentConcept<T>::BoundsType ret(bounds_exact(f[0]));
+    for(unsigned i = 1; i < f.size(); i++)
+        ret.unionWith(bounds_exact(f[i]));
+    return ret;
+}
+
+template<typename T>
+inline typename FragmentConcept<T>::BoundsType bounds_local(const Piecewise<T> &f, const Interval &m) {
+    boost::function_requires<FragmentConcept<T> >();
+
+    if(f.empty()) return typename FragmentConcept<T>::BoundsType();
+    if(m.isEmpty()) return typename FragmentConcept<T>::BoundsType(f(m.min()));
+
+    unsigned fi = f.segN(m.min()), ti = f.segN(m.max());
+    double ft = f.segT(m.min(), fi), tt = f.segT(m.max(), ti);
+
+    if(fi == ti) return bounds_local(f[fi], Interval(ft, tt));
+
+    typename FragmentConcept<T>::BoundsType ret(bounds_local(f[fi], Interval(ft, 1.)));
+    for(unsigned i = fi + 1; i < ti; i++)
+        ret.unionWith(bounds_exact(f[i]));
+    if(tt != 0.) ret.unionWith(bounds_local(f[ti], Interval(0., tt)));
+
+    return ret;
+}
+
+//returns a portion of a piece of a Piecewise<T>, given the piece's index and a to/from time.
+template<typename T>
+T elem_portion(const Piecewise<T> &a, unsigned i, double from, double to) {
+    assert(i < a.size());
+    double rwidth = 1 / (a.cuts[i+1] - a.cuts[i]);
+    return portion( a[i], (from - a.cuts[i]) * rwidth, (to - a.cuts[i]) * rwidth );
+}
+
+/**Piecewise<T> partition(const Piecewise<T> &pw, std::vector<double> const &c);
+ * Further subdivides the Piecewise<T> such that there is a cut at every value in c.
+ * Precondition: c sorted lower to higher.
+ *
+ * //Given Piecewise<T> a and b:
+ * Piecewise<T> ac = a.partition(b.cuts);
+ * Piecewise<T> bc = b.partition(a.cuts);
+ * //ac.cuts should be equivalent to bc.cuts
+ */
+template<typename T>
+Piecewise<T> partition(const Piecewise<T> &pw, std::vector<double> const &c) {
+    assert(pw.invariants());
+    if(c.empty()) return Piecewise<T>(pw);
+
+    Piecewise<T> ret = Piecewise<T>();
+    ret.cuts.reserve(c.size() + pw.cuts.size());
+    ret.segs.reserve(c.size() + pw.cuts.size() - 1);
+
+    if(pw.empty()) {
+        ret.cuts = c;
+        for(unsigned i = 0; i < c.size() - 1; i++)
+            ret.push_seg(T());
+        return ret;
+    }
+
+    unsigned si = 0, ci = 0;     //Segment index, Cut index
+
+    //if the cuts have something earlier than the Piecewise<T>, add portions of the first segment
+    while(c[ci] < pw.cuts.front() && ci < c.size()) {
+        bool isLast = (ci == c.size()-1 || c[ci + 1] >= pw.cuts.front());
+        ret.push_cut(c[ci]);
+        ret.push_seg( elem_portion(pw, 0, c[ci], isLast ? pw.cuts.front() : c[ci + 1]) );
+        ci++;
+    }
+
+    ret.push_cut(pw.cuts[0]);
+    double prev = pw.cuts[0];    //previous cut
+    //Loop which handles cuts within the Piecewise<T> domain
+    //Should have the cuts = segs + 1 invariant
+    while(si < pw.size() && ci <= c.size()) {
+        if(ci == c.size() && prev <= pw.cuts[si]) { //cuts exhausted, straight copy the rest
+            ret.segs.insert(ret.segs.end(), pw.segs.begin() + si, pw.segs.end());
+            ret.cuts.insert(ret.cuts.end(), pw.cuts.begin() + si + 1, pw.cuts.end());
+            return ret;
+        }else if(ci == c.size() || c[ci] >= pw.cuts[si + 1]) {  //no more cuts within this segment, finalize
+            if(prev > pw.cuts[si]) {      //segment already has cuts, so portion is required
+                ret.push_seg(portion(pw[si], pw.segT(prev, si), 1.0));
+            } else {                     //plain copy is fine
+                ret.push_seg(pw[si]);
+            }
+            ret.push_cut(pw.cuts[si + 1]);
+            prev = pw.cuts[si + 1];
+            si++;
+        } else if(c[ci] == pw.cuts[si]){                  //coincident
+            //Already finalized the seg with the code immediately above
+            ci++;
+        } else {                                         //plain old subdivision
+            ret.push(elem_portion(pw, si, prev, c[ci]), c[ci]);
+            prev = c[ci];
+            ci++;
+        }
+    }
+
+    //input cuts extend further than this Piecewise<T>, extend the last segment.
+    while(ci < c.size()) {
+        if(c[ci] > prev) {
+            ret.push(elem_portion(pw, pw.size() - 1, prev, c[ci]), c[ci]);
+            prev = c[ci];
+        }
+        ci++;
+    }
+    return ret;
+}
+
+/**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)].
+ */
+template<typename T>
+Piecewise<T> portion(const Piecewise<T> &pw, double from, double to) {
+    if(pw.empty() || from == to) return Piecewise<T>();
+
+    Piecewise<T> ret;
+
+    double temp = from;
+    from = std::min(from, to);
+    to = std::max(temp, to);
+
+    unsigned i = pw.segN(from);
+    ret.push_cut(from);
+    if(i == pw.size() - 1 || to < pw.cuts[i + 1]) {    //to/from inhabit the same segment
+        ret.push(elem_portion(pw, i, from, to), to);
+        return ret;
+    }
+    ret.push_seg(portion( pw[i], pw.segT(from, i), 1.0 ));
+    i++;
+    unsigned fi = pw.segN(to, i);
+
+    ret.segs.insert(ret.segs.end(), pw.segs.begin() + i, pw.segs.begin() + fi);  //copy segs
+    ret.cuts.insert(ret.cuts.end(), pw.cuts.begin() + i, pw.cuts.begin() + fi + 1);  //and their cuts
+
+    ret.push_seg( portion(pw[fi], 0.0, pw.segT(to, fi)));
+    if(to != ret.cuts.back()) ret.push_cut(to);
+    ret.invariants();
+    return ret;
+}
+
+template<typename T>
+Piecewise<T> remove_short_cuts(Piecewise<T> const &f, double tol) {
+    if(f.empty()) return f;
+    Piecewise<T> ret;
+    ret.push_cut(f.cuts[0]);
+    for(unsigned i=0; i<f.size(); i++){
+        if (f.cuts[i+1]-f.cuts[i] >= tol || i==f.size()-1) {
+            ret.push(f[i], f.cuts[i+1]);
+        }
+    }
+    return ret;
+}
+
+template<typename T>
+Piecewise<T> remove_short_cuts_extending(Piecewise<T> const &f, double tol) {
+    if(f.empty()) return f;
+    Piecewise<T> ret;
+    ret.push_cut(f.cuts[0]);
+    double last = f.cuts[0]; // last cut included
+    for(unsigned i=0; i<f.size(); i++){
+        if (f.cuts[i+1]-f.cuts[i] >= tol) {
+            ret.push(elem_portion(f, i, last, f.cuts[i+1]), f.cuts[i+1]);
+            last = f.cuts[i+1];
+        }
+    }
+    return ret;
+}
+
+template<typename T>
+std::vector<double> roots(const Piecewise<T> &pw) {
+    std::vector<double> ret;
+    for(unsigned i = 0; i < pw.size(); i++) {
+        std::vector<double> sr = roots(pw[i]);
+        for (unsigned j = 0; j < sr.size(); j++) ret.push_back(sr[j] * (pw.cuts[i + 1] - pw.cuts[i]) + pw.cuts[i]);
+
+    }
+    return ret;
+}
+
+//IMPL: OffsetableConcept
+template<typename T>
+Piecewise<T> operator+(Piecewise<T> const &a, typename T::output_type b) {
+    boost::function_requires<OffsetableConcept<T> >();
+//TODO:empty
+    Piecewise<T> ret = Piecewise<T>();
+    ret.cuts = a.cuts;
+    for(unsigned i = 0; i < a.size();i++)
+        ret.push_seg(a[i] + b);
+    return ret;
+}
+template<typename T>
+Piecewise<T> operator-(Piecewise<T> const &a, typename T::output_type b) {
+    boost::function_requires<OffsetableConcept<T> >();
+//TODO: empty
+    Piecewise<T> ret = Piecewise<T>();
+    ret.cuts = a.cuts;
+    for(unsigned i = 0; i < a.size();i++)
+        ret.push_seg(a[i] - b);
+    return ret;
+}
+template<typename T>
+Piecewise<T> operator+=(Piecewise<T>& a, typename T::output_type b) {
+    boost::function_requires<OffsetableConcept<T> >();
+
+    if(a.empty()) { a.push_cut(0.); a.push(T(b), 1.); return a; }
+
+    for(unsigned i = 0; i < a.size();i++)
+        a[i] += b;
+    return a;
+}
+template<typename T>
+Piecewise<T> operator-=(Piecewise<T>& a, typename T::output_type b) {
+    boost::function_requires<OffsetableConcept<T> >();
+
+    if(a.empty()) { a.push_cut(0.); a.push(T(b), 1.); return a; }
+
+    for(unsigned i = 0;i < a.size();i++)
+        a[i] -= b;
+    return a;
+}
+
+//IMPL: ScalableConcept
+template<typename T>
+Piecewise<T> operator-(Piecewise<T> const &a) {
+    boost::function_requires<ScalableConcept<T> >();
+
+    Piecewise<T> ret;
+    ret.cuts = a.cuts;
+    for(unsigned i = 0; i < a.size();i++)
+        ret.push_seg(- a[i]);
+    return ret;
+}
+template<typename T>
+Piecewise<T> operator*(Piecewise<T> const &a, double b) {
+    boost::function_requires<ScalableConcept<T> >();
+
+    if(a.empty()) return Piecewise<T>();
+
+    Piecewise<T> ret;
+    ret.cuts = a.cuts;
+    for(unsigned i = 0; i < a.size();i++)
+        ret.push_seg(a[i] * b);
+    return ret;
+}
+template<typename T>
+Piecewise<T> operator/(Piecewise<T> const &a, double b) {
+    boost::function_requires<ScalableConcept<T> >();
+
+    //FIXME: b == 0?
+    if(a.empty()) return Piecewise<T>();
+
+    Piecewise<T> ret;
+    ret.cuts = a.cuts;
+    for(unsigned i = 0; i < a.size();i++)
+        ret.push_seg(a[i] / b);
+    return ret;
+}
+template<typename T>
+Piecewise<T> operator*=(Piecewise<T>& a, double b) {
+    boost::function_requires<ScalableConcept<T> >();
+
+    if(a.empty()) return Piecewise<T>();
+
+    for(unsigned i = 0; i < a.size();i++)
+        a[i] *= b;
+    return a;
+}
+template<typename T>
+Piecewise<T> operator/=(Piecewise<T>& a, double b) {
+    boost::function_requires<ScalableConcept<T> >();
+
+    //FIXME: b == 0?
+    if(a.empty()) return Piecewise<T>();
+
+    for(unsigned i = 0; i < a.size();i++)
+        a[i] /= b;
+    return a;
+}
+
+//IMPL: AddableConcept
+template<typename T>
+Piecewise<T> operator+(Piecewise<T> const &a, Piecewise<T> const &b) {
+    boost::function_requires<AddableConcept<T> >();
+
+    Piecewise<T> pa = partition(a, b.cuts), pb = partition(b, a.cuts);
+    Piecewise<T> ret = Piecewise<T>();
+    assert(pa.size() == pb.size());
+    ret.cuts = pa.cuts;
+    for (unsigned i = 0; i < pa.size(); i++)
+        ret.push_seg(pa[i] + pb[i]);
+    return ret;
+}
+template<typename T>
+Piecewise<T> operator-(Piecewise<T> const &a, Piecewise<T> const &b) {
+    boost::function_requires<AddableConcept<T> >();
+
+    Piecewise<T> pa = partition(a, b.cuts), pb = partition(b, a.cuts);
+    Piecewise<T> ret = Piecewise<T>();
+    assert(pa.size() == pb.size());
+    ret.cuts = pa.cuts;
+    for (unsigned i = 0; i < pa.size(); i++)
+        ret.push_seg(pa[i] - pb[i]);
+    return ret;
+}
+template<typename T>
+inline Piecewise<T> operator+=(Piecewise<T> &a, Piecewise<T> const &b) {
+    a = a+b;
+    return a;
+}
+template<typename T>
+inline Piecewise<T> operator-=(Piecewise<T> &a, Piecewise<T> const &b) {
+    a = a-b;
+    return a;
+}
+
+template<typename T1,typename T2>
+Piecewise<T2> operator*(Piecewise<T1> const &a, Piecewise<T2> const &b) {
+    //function_requires<MultiplicableConcept<T1> >();
+    //function_requires<MultiplicableConcept<T2> >();
+
+    Piecewise<T1> pa = partition(a, b.cuts);
+    Piecewise<T2> pb = partition(b, a.cuts);
+    Piecewise<T2> ret = Piecewise<T2>();
+    assert(pa.size() == pb.size());
+    ret.cuts = pa.cuts;
+    for (unsigned i = 0; i < pa.size(); i++)
+        ret.push_seg(pa[i] * pb[i]);
+    return ret;
+}
+
+template<typename T>
+inline Piecewise<T> operator*=(Piecewise<T> &a, Piecewise<T> const &b) {
+    a = a * b;
+    return a;
+}
+
+Piecewise<SBasis> divide(Piecewise<SBasis> const &a, Piecewise<SBasis> const &b, unsigned k);
+//TODO: replace divide(a,b,k) by divide(a,b,tol,k)?
+//TODO: atm, relative error is ~(tol/a)%. Find a way to make it independant of a.
+//Nota: the result is 'truncated' where b is smaller than 'zero': ~ a/max(b,zero).
+Piecewise<SBasis>
+divide(Piecewise<SBasis> const &a, Piecewise<SBasis> const &b, double tol, unsigned k, double zero=1.e-3);
+Piecewise<SBasis>
+divide(SBasis const &a, Piecewise<SBasis> const &b, double tol, unsigned k, double zero=1.e-3);
+Piecewise<SBasis>
+divide(Piecewise<SBasis> const &a, SBasis const &b, double tol, unsigned k, double zero=1.e-3);
+Piecewise<SBasis>
+divide(SBasis const &a, SBasis const &b, double tol, unsigned k, double zero=1.e-3);
+
+//Composition: functions called compose_* are pieces of compose that are factored out in pw.cpp.
+std::map<double,unsigned> compose_pullback(std::vector<double> const &cuts, SBasis const &g);
+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);
+
+//TODO: add concept check
+template<typename T>
+Piecewise<T> compose(Piecewise<T> const &f, SBasis const &g){
+    Piecewise<T> result;
+    if (f.empty()) return result;
+    if (g.isZero()) return Piecewise<T>(f(0));
+    if (f.size()==1){
+        double t0 = f.cuts[0], width = f.cuts[1] - t0;
+        return (Piecewise<T>) compose(f.segs[0],compose(Linear(-t0 / width, (1-t0) / width), g));
+    }
+
+    //first check bounds...
+    Interval bs = bounds_fast(g);
+    if (f.cuts.front() > bs.max()  || bs.min() > f.cuts.back()){
+        int idx = (bs.max() < f.cuts[1]) ? 0 : f.cuts.size()-2;
+        double t0 = f.cuts[idx], width = f.cuts[idx+1] - t0;
+        return (Piecewise<T>) compose(f.segs[idx],compose(Linear(-t0 / width, (1-t0) / width), g));
+    }
+
+    std::vector<double> levels;//we can forget first and last cuts...
+    levels.insert(levels.begin(),f.cuts.begin()+1,f.cuts.end()-1);
+    //TODO: use a std::vector<pairs<double,unsigned> > instead of a map<double,unsigned>.
+    std::map<double,unsigned> cuts_pb = compose_pullback(levels,g);
+
+    //-- Compose each piece of g with the relevant seg of f.
+    result.cuts.push_back(0.);
+    std::map<double,unsigned>::iterator cut=cuts_pb.begin();
+    std::map<double,unsigned>::iterator next=cut; next++;
+    while(next!=cuts_pb.end()){
+        //assert(std::abs(int((*cut).second-(*next).second))<1);
+        //TODO: find a way to recover from this error? the root finder missed some root;
+        //  the levels/variations of f might be too close/fast...
+        int idx = compose_findSegIdx(cut,next,levels,g);
+        double t0=(*cut).first;
+        double t1=(*next).first;
+
+        SBasis sub_g=compose(g, Linear(t0,t1));
+        sub_g=compose(Linear(-f.cuts[idx]/(f.cuts[idx+1]-f.cuts[idx]),
+                             (1-f.cuts[idx])/(f.cuts[idx+1]-f.cuts[idx])),sub_g);
+        result.push(compose(f[idx],sub_g),t1);
+        cut++;
+        next++;
+    }
+    return(result);
+}
+
+//TODO: add concept check for following composition functions
+template<typename T>
+Piecewise<T> compose(Piecewise<T> const &f, Piecewise<SBasis> const &g){
+  Piecewise<T> result;
+  for(unsigned i = 0; i < g.segs.size(); i++){
+      Piecewise<T> fgi=compose(f, g.segs[i]);
+      fgi.setDomain(Interval(g.cuts[i], g.cuts[i+1]));
+      result.concat(fgi);
+  }
+  return result;
+}
+
+template <typename T>
+Piecewise<T> Piecewise<T>::operator()(SBasis f){return compose((*this),f);}
+template <typename T>
+Piecewise<T> Piecewise<T>::operator()(Piecewise<SBasis>f){return compose((*this),f);}
+
+template<typename T>
+Piecewise<T> integral(Piecewise<T> const &a) {
+    Piecewise<T> result;
+    result.segs.resize(a.segs.size());
+    result.cuts = a.cuts;
+    typename T::output_type c = a.segs[0].at0();
+    for(unsigned i = 0; i < a.segs.size(); i++){
+        result.segs[i] = integral(a.segs[i])*(a.cuts[i+1]-a.cuts[i]);
+        result.segs[i]+= c-result.segs[i].at0();
+        c = result.segs[i].at1();
+    }
+    return result;
+}
+
+template<typename T>
+Piecewise<T> derivative(Piecewise<T> const &a) {
+    Piecewise<T> result;
+    result.segs.resize(a.segs.size());
+    result.cuts = a.cuts;
+    for(unsigned i = 0; i < a.segs.size(); i++){
+        result.segs[i] = derivative(a.segs[i])/(a.cuts[i+1]-a.cuts[i]);
+    }
+    return result;
+}
+
+std::vector<double> roots(Piecewise<SBasis> const &f);
+
+}
+
+#endif //SEEN_GEOM_PW_SB_H
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+  indent-tabs-mode:nil
+  fill-column:99
+  End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
index 136687ae87c8fa518080f5945240e65652284521..fdc1cefe55a585d2205a63fcf925b1a74a587058 100644 (file)
@@ -1,64 +1,64 @@
-#include "poly-dk-solve.h"\r
-#include <iterator>\r
-\r
-/*** implementation of the Durand-Kerner method.  seems buggy*/\r
-\r
-std::complex<double> evalu(Poly const & p, std::complex<double> x) {\r
-    std::complex<double> result = 0;\r
-    std::complex<double> xx = 1;\r
-    \r
-    for(unsigned i = 0; i < p.size(); i++) {\r
-        result += p[i]*xx;\r
-        xx *= x;\r
-    }\r
-    return result;\r
-}\r
-\r
-std::vector<std::complex<double> > DK(Poly const & ply, const double tol) {\r
-    std::vector<std::complex<double> > roots;\r
-    const int N = ply.degree();\r
-    \r
-    std::complex<double> b(0.4, 0.9);\r
-    std::complex<double> p = 1;\r
-    for(int i = 0; i < N; i++) {\r
-        roots.push_back(p);\r
-        p *= b;\r
-    }\r
-    assert(roots.size() == ply.degree());\r
-    \r
-    double error = 0;\r
-    int i;\r
-    for( i = 0; i < 30; i++) {\r
-        error = 0;\r
-        for(int r_i = 0; r_i < N; r_i++) {\r
-            std::complex<double> denom = 1;\r
-            std::complex<double> R = roots[r_i];\r
-            for(int d_i = 0; d_i < N; d_i++) {\r
-                if(r_i != d_i)\r
-                    denom *= R-roots[d_i];\r
-            }\r
-            assert(norm(denom) != 0);\r
-           std::complex<double> dr = evalu(ply, R)/denom;\r
-            error += norm(dr);\r
-            roots[r_i] = R - dr;\r
-        }\r
-        /*std::copy(roots.begin(), roots.end(), std::ostream_iterator<std::complex<double> >(std::cout, ",\t"));\r
-          std::cout << std::endl;*/\r
-        if(error < tol)\r
-            break;\r
-    }\r
-    //std::cout << error << ", " << i<< std::endl;\r
-    return roots;\r
-}\r
-\r
-\r
-/*\r
-  Local Variables:\r
-  mode:c++\r
-  c-file-style:"stroustrup"\r
-  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
-  indent-tabs-mode:nil\r
-  fill-column:99\r
-  End:\r
-*/\r
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :\r
+#include "poly-dk-solve.h"
+#include <iterator>
+
+/*** implementation of the Durand-Kerner method.  seems buggy*/
+
+std::complex<double> evalu(Poly const & p, std::complex<double> x) {
+    std::complex<double> result = 0;
+    std::complex<double> xx = 1;
+
+    for(unsigned i = 0; i < p.size(); i++) {
+        result += p[i]*xx;
+        xx *= x;
+    }
+    return result;
+}
+
+std::vector<std::complex<double> > DK(Poly const & ply, const double tol) {
+    std::vector<std::complex<double> > roots;
+    const int N = ply.degree();
+
+    std::complex<double> b(0.4, 0.9);
+    std::complex<double> p = 1;
+    for(int i = 0; i < N; i++) {
+        roots.push_back(p);
+        p *= b;
+    }
+    assert(roots.size() == ply.degree());
+
+    double error = 0;
+    int i;
+    for( i = 0; i < 30; i++) {
+        error = 0;
+        for(int r_i = 0; r_i < N; r_i++) {
+            std::complex<double> denom = 1;
+            std::complex<double> R = roots[r_i];
+            for(int d_i = 0; d_i < N; d_i++) {
+                if(r_i != d_i)
+                    denom *= R-roots[d_i];
+            }
+            assert(norm(denom) != 0);
+            std::complex<double> dr = evalu(ply, R)/denom;
+            error += norm(dr);
+            roots[r_i] = R - dr;
+        }
+        /*std::copy(roots.begin(), roots.end(), std::ostream_iterator<std::complex<double> >(std::cout, ",\t"));
+          std::cout << std::endl;*/
+        if(error < tol)
+            break;
+    }
+    //std::cout << error << ", " << i<< std::endl;
+    return roots;
+}
+
+
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+  indent-tabs-mode:nil
+  fill-column:99
+  End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
index fb3c2075b213da13d21d01a9793d675d3e9934f5..766f16edafa1e2621e9d7e24bfa0c3da9cb2f3a1 100644 (file)
-#include "poly-laguerre-solve.h"\r
-#include <iterator>\r
-\r
-typedef std::complex<double> cdouble;\r
-\r
-cdouble laguerre_internal_complex(Poly const & p,\r
-                                  double x0,\r
-                                  double tol,\r
-                                  bool & quad_root) {\r
-    cdouble a = 2*tol;\r
-    cdouble xk = x0;\r
-    double n = p.degree();\r
-    quad_root = false;\r
-    const unsigned shuffle_rate = 10;\r
-    static double shuffle[] = {0, 0.5, 0.25, 0.75, 0.125, 0.375, 0.625, 0.875, 1.0};\r
-    unsigned shuffle_counter = 0;\r
-    while(std::norm(a) > (tol*tol)) {\r
-        //std::cout << "xk = " << xk << std::endl;\r
-        cdouble b = p.back();\r
-        cdouble d = 0, f = 0;\r
-        double err = abs(b);\r
-        double abx = abs(xk);\r
-        for(int j = p.size()-2; j >= 0; j--) {\r
-            f = xk*f + d;\r
-            d = xk*d + b;\r
-            b = xk*b + p[j];\r
-            err = abs(b) + abx*err;\r
-        }\r
-        \r
-        err *= 1e-7; // magic epsilon for convergence, should be computed from tol\r
-        \r
-        cdouble px = b;\r
-        if(abs(b) < err)\r
-            return xk;\r
-        //if(std::norm(px) < tol*tol)\r
-        //    return xk;\r
-        cdouble G = d / px;\r
-        cdouble H = G*G - f / px;\r
-        \r
-        //std::cout << "G = " << G << "H = " << H;\r
-        cdouble radicand = (n - 1)*(n*H-G*G);\r
-        //assert(radicand.real() > 0);\r
-        if(radicand.real() < 0)\r
-            quad_root = true;\r
-        //std::cout << "radicand = " << radicand << std::endl;\r
-        if(G.real() < 0) // here we try to maximise the denominator avoiding cancellation\r
-            a = - sqrt(radicand);\r
-        else\r
-            a = sqrt(radicand);\r
-        //std::cout << "a = " << a << std::endl;\r
-        a = n / (a + G);\r
-        //std::cout << "a = " << a << std::endl;\r
-        if(shuffle_counter % shuffle_rate == 0)\r
-            ;//a *= shuffle[shuffle_counter / shuffle_rate];\r
-        xk -= a;\r
-        shuffle_counter++;\r
-        if(shuffle_counter >= 90)\r
-            break;\r
-    }\r
-    //std::cout << "xk = " << xk << std::endl;\r
-    return xk;\r
-}\r
-\r
-double laguerre_internal(Poly const & p,\r
-                         Poly const & pp,\r
-                         Poly const & ppp,\r
-                         double x0,\r
-                         double tol,\r
-                         bool & quad_root) {\r
-    double a = 2*tol;\r
-    double xk = x0;\r
-    double n = p.degree();\r
-    quad_root = false;\r
-    while(a*a > (tol*tol)) {\r
-        //std::cout << "xk = " << xk << std::endl;\r
-        double px = p(xk);\r
-        if(px*px < tol*tol)\r
-            return xk;\r
-        double G = pp(xk) / px;\r
-        double H = G*G - ppp(xk) / px;\r
-        \r
-        //std::cout << "G = " << G << "H = " << H;\r
-        double radicand = (n - 1)*(n*H-G*G);\r
-        assert(radicand > 0);\r
-        //std::cout << "radicand = " << radicand << std::endl;\r
-        if(G < 0) // here we try to maximise the denominator avoiding cancellation\r
-            a = - sqrt(radicand);\r
-        else\r
-            a = sqrt(radicand);\r
-        //std::cout << "a = " << a << std::endl;\r
-        a = n / (a + G);\r
-        //std::cout << "a = " << a << std::endl;\r
-        xk -= a;\r
-    }\r
-    //std::cout << "xk = " << xk << std::endl;\r
-    return xk;\r
-}\r
-\r
-\r
-std::vector<cdouble > \r
-laguerre(Poly p, const double tol) {\r
-    std::vector<cdouble > solutions;\r
-    //std::cout << "p = " << p << " = ";\r
-    while(p.size() > 1)\r
-    {\r
-        double x0 = 0;\r
-        bool quad_root = false;\r
-        cdouble sol = laguerre_internal_complex(p, x0, tol, quad_root);\r
-        //if(abs(sol) > 1) break;\r
-        Poly dvs;\r
-        if(quad_root) {\r
-            dvs.push_back((sol*conj(sol)).real());\r
-            dvs.push_back(-(sol + conj(sol)).real());\r
-            dvs.push_back(1.0);\r
-            //std::cout << "(" <<  dvs << ")";\r
-           //solutions.push_back(sol);\r
-           //solutions.push_back(conj(sol));\r
-        } else {\r
-            //std::cout << sol << std::endl;\r
-            dvs.push_back(-sol.real());\r
-            dvs.push_back(1.0);\r
-           solutions.push_back(sol);\r
-            //std::cout << "(" <<  dvs << ")";\r
-        }\r
-        Poly r;\r
-        p = divide(p, dvs, r);\r
-        //std::cout << r << std::endl;\r
-    }\r
-    return solutions;\r
-}\r
-\r
-std::vector<double> \r
-laguerre_real_interval(Poly const & ply, \r
-                      const double lo, const double hi,\r
-                      const double tol) {\r
-}\r
-\r
-/*\r
-  Local Variables:\r
-  mode:c++\r
-  c-file-style:"stroustrup"\r
-  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
-  indent-tabs-mode:nil\r
-  fill-column:99\r
-  End:\r
-*/\r
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :\r
+#include "poly-laguerre-solve.h"
+#include <iterator>
+
+typedef std::complex<double> cdouble;
+
+cdouble laguerre_internal_complex(Poly const & p,
+                                  double x0,
+                                  double tol,
+                                  bool & quad_root) {
+    cdouble a = 2*tol;
+    cdouble xk = x0;
+    double n = p.degree();
+    quad_root = false;
+    const unsigned shuffle_rate = 10;
+    static double shuffle[] = {0, 0.5, 0.25, 0.75, 0.125, 0.375, 0.625, 0.875, 1.0};
+    unsigned shuffle_counter = 0;
+    while(std::norm(a) > (tol*tol)) {
+        //std::cout << "xk = " << xk << std::endl;
+        cdouble b = p.back();
+        cdouble d = 0, f = 0;
+        double err = abs(b);
+        double abx = abs(xk);
+        for(int j = p.size()-2; j >= 0; j--) {
+            f = xk*f + d;
+            d = xk*d + b;
+            b = xk*b + p[j];
+            err = abs(b) + abx*err;
+        }
+
+        err *= 1e-7; // magic epsilon for convergence, should be computed from tol
+
+        cdouble px = b;
+        if(abs(b) < err)
+            return xk;
+        //if(std::norm(px) < tol*tol)
+        //    return xk;
+        cdouble G = d / px;
+        cdouble H = G*G - f / px;
+
+        //std::cout << "G = " << G << "H = " << H;
+        cdouble radicand = (n - 1)*(n*H-G*G);
+        //assert(radicand.real() > 0);
+        if(radicand.real() < 0)
+            quad_root = true;
+        //std::cout << "radicand = " << radicand << std::endl;
+        if(G.real() < 0) // here we try to maximise the denominator avoiding cancellation
+            a = - sqrt(radicand);
+        else
+            a = sqrt(radicand);
+        //std::cout << "a = " << a << std::endl;
+        a = n / (a + G);
+        //std::cout << "a = " << a << std::endl;
+        if(shuffle_counter % shuffle_rate == 0)
+            ;//a *= shuffle[shuffle_counter / shuffle_rate];
+        xk -= a;
+        shuffle_counter++;
+        if(shuffle_counter >= 90)
+            break;
+    }
+    //std::cout << "xk = " << xk << std::endl;
+    return xk;
+}
+
+double laguerre_internal(Poly const & p,
+                         Poly const & pp,
+                         Poly const & ppp,
+                         double x0,
+                         double tol,
+                         bool & quad_root) {
+    double a = 2*tol;
+    double xk = x0;
+    double n = p.degree();
+    quad_root = false;
+    while(a*a > (tol*tol)) {
+        //std::cout << "xk = " << xk << std::endl;
+        double px = p(xk);
+        if(px*px < tol*tol)
+            return xk;
+        double G = pp(xk) / px;
+        double H = G*G - ppp(xk) / px;
+
+        //std::cout << "G = " << G << "H = " << H;
+        double radicand = (n - 1)*(n*H-G*G);
+        assert(radicand > 0);
+        //std::cout << "radicand = " << radicand << std::endl;
+        if(G < 0) // here we try to maximise the denominator avoiding cancellation
+            a = - sqrt(radicand);
+        else
+            a = sqrt(radicand);
+        //std::cout << "a = " << a << std::endl;
+        a = n / (a + G);
+        //std::cout << "a = " << a << std::endl;
+        xk -= a;
+    }
+    //std::cout << "xk = " << xk << std::endl;
+    return xk;
+}
+
+
+std::vector<cdouble >
+laguerre(Poly p, const double tol) {
+    std::vector<cdouble > solutions;
+    //std::cout << "p = " << p << " = ";
+    while(p.size() > 1)
+    {
+        double x0 = 0;
+        bool quad_root = false;
+        cdouble sol = laguerre_internal_complex(p, x0, tol, quad_root);
+        //if(abs(sol) > 1) break;
+        Poly dvs;
+        if(quad_root) {
+            dvs.push_back((sol*conj(sol)).real());
+            dvs.push_back(-(sol + conj(sol)).real());
+            dvs.push_back(1.0);
+            //std::cout << "(" <<  dvs << ")";
+            //solutions.push_back(sol);
+            //solutions.push_back(conj(sol));
+        } else {
+            //std::cout << sol << std::endl;
+            dvs.push_back(-sol.real());
+            dvs.push_back(1.0);
+            solutions.push_back(sol);
+            //std::cout << "(" <<  dvs << ")";
+        }
+        Poly r;
+        p = divide(p, dvs, r);
+        //std::cout << r << std::endl;
+    }
+    return solutions;
+}
+
+std::vector<double>
+laguerre_real_interval(Poly const & ply,
+                       const double lo, const double hi,
+                       const double tol) {
+}
+
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+  indent-tabs-mode:nil
+  fill-column:99
+  End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
index ef583c0b56fdd5a5653ff08ea8cf99ed8676fe1e..62c769c8bae5b13683e1832bf87f0ec157edc5b6 100644 (file)
@@ -1,4 +1,4 @@
-#include <vector>\r
+#include <vector>
 #include <cassert>
 
 class Quad{
@@ -20,7 +20,7 @@ public:
     double by0, by1;
 
     QuadTree() : root(0), scale(1) {}
-    
+
     Quad* search(double x0, double y0, double x1, double y1);
     void insert(double x0, double y0, double x1, double y1, int shape);
     void erase(Quad *q, int shape);
index 5bf0d2876d14c02bd444cd637d4319c92b47b626..7157bc8856313021f405feee0f10371719ff86d2 100644 (file)
-/*\r
- *  sbasis.cpp - S-power basis function class + supporting classes\r
- *\r
- *  Authors:\r
- *   Nathan Hurst <njh@mail.csse.monash.edu.au>\r
- *   Michael Sloan <mgsloan@gmail.com>\r
- *\r
- * Copyright (C) 2006-2007 authors\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it either under the terms of the GNU Lesser General Public\r
- * License version 2.1 as published by the Free Software Foundation\r
- * (the "LGPL") or, at your option, under the terms of the Mozilla\r
- * Public License Version 1.1 (the "MPL"). If you do not alter this\r
- * notice, a recipient may use your version of this file under either\r
- * the MPL or the LGPL.\r
- *\r
- * You should have received a copy of the LGPL along with this library\r
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
- * You should have received a copy of the MPL along with this library\r
- * in the file COPYING-MPL-1.1\r
- *\r
- * The contents of this file are subject to the Mozilla Public License\r
- * Version 1.1 (the "License"); you may not use this file except in\r
- * compliance with the License. You may obtain a copy of the License at\r
- * http://www.mozilla.org/MPL/\r
- *\r
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY\r
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for\r
- * the specific language governing rights and limitations.\r
- */\r
-\r
-#include <cmath>\r
-\r
-#include "sbasis.h"\r
-#include "isnan.h"\r
-\r
-namespace Geom{\r
-\r
-/*** At some point we should work on tighter bounds for the error.  It is clear that the error is\r
- * bounded by the L1 norm over the tail of the series, but this is very loose, leading to far too\r
- * many cubic beziers.  I've changed this to be \sum _i=tail ^\infty |hat a_i| 2^-i but I have no\r
- * evidence that this is correct.\r
- */\r
-\r
-/*\r
-double SBasis::tail_error(unsigned tail) const {\r
-    double err = 0, s = 1./(1<<(2*tail)); // rough\r
-    for(unsigned i = tail; i < size(); i++) {\r
-        err += (fabs((*this)[i][0]) + fabs((*this)[i][1]))*s;\r
-        s /= 4;\r
-    }\r
-    return err;\r
-}\r
+/*
+ *  sbasis.cpp - S-power basis function class + supporting classes
+ *
+ *  Authors:
+ *   Nathan Hurst <njh@mail.csse.monash.edu.au>
+ *   Michael Sloan <mgsloan@gmail.com>
+ *
+ * Copyright (C) 2006-2007 authors
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ */
+
+#include <cmath>
+
+#include "sbasis.h"
+#include "isnan.h"
+
+namespace Geom{
+
+/*** At some point we should work on tighter bounds for the error.  It is clear that the error is
+ * bounded by the L1 norm over the tail of the series, but this is very loose, leading to far too
+ * many cubic beziers.  I've changed this to be \sum _i=tail ^\infty |hat a_i| 2^-i but I have no
+ * evidence that this is correct.
+ */
+
+/*
+double SBasis::tail_error(unsigned tail) const {
+    double err = 0, s = 1./(1<<(2*tail)); // rough
+    for(unsigned i = tail; i < size(); i++) {
+        err += (fabs((*this)[i][0]) + fabs((*this)[i][1]))*s;
+        s /= 4;
+    }
+    return err;
+}
 */
-\r
-double SBasis::tailError(unsigned tail) const {\r
-  Interval bs = bounds_fast(*this, tail);\r
-  return std::max(fabs(bs.min()),fabs(bs.max()));\r
-}\r
-\r
-bool SBasis::isFinite() const {\r
-    for(unsigned i = 0; i < size(); i++) {\r
-        if(!(*this)[i].isFinite())\r
-            return false;\r
-    }\r
-    return true;\r
-}\r
-\r
-SBasis operator+(const SBasis& a, const SBasis& b) {\r
-    SBasis result;\r
-    const unsigned out_size = std::max(a.size(), b.size());\r
-    const unsigned min_size = std::min(a.size(), b.size());\r
-    result.reserve(out_size);\r
-    \r
-    for(unsigned i = 0; i < min_size; i++) {\r
-        result.push_back(a[i] + b[i]);\r
-    }\r
-    for(unsigned i = min_size; i < a.size(); i++)\r
-        result.push_back(a[i]);\r
-    for(unsigned i = min_size; i < b.size(); i++)\r
-        result.push_back(b[i]);\r
-\r
-    assert(result.size() == out_size);\r
-    return result;\r
-}\r
-\r
-SBasis operator-(const SBasis& a, const SBasis& b) {\r
-    SBasis result;\r
-    const unsigned out_size = std::max(a.size(), b.size());\r
-    const unsigned min_size = std::min(a.size(), b.size());\r
-    result.reserve(out_size);\r
-    \r
-    for(unsigned i = 0; i < min_size; i++) {\r
-        result.push_back(a[i] - b[i]);\r
-    }\r
-    for(unsigned i = min_size; i < a.size(); i++)\r
-        result.push_back(a[i]);\r
-    for(unsigned i = min_size; i < b.size(); i++)\r
-        result.push_back(-b[i]);\r
-\r
-    assert(result.size() == out_size);\r
-    return result;\r
-}\r
-\r
-SBasis& operator+=(SBasis& a, const SBasis& b) {\r
-    const unsigned out_size = std::max(a.size(), b.size());\r
-    const unsigned min_size = std::min(a.size(), b.size());\r
-    a.reserve(out_size);\r
-        \r
-    for(unsigned i = 0; i < min_size; i++)\r
-        a[i] += b[i];\r
-    for(unsigned i = min_size; i < b.size(); i++)\r
-        a.push_back(b[i]);\r
-    \r
-    assert(a.size() == out_size);\r
-    return a;\r
-}\r
-\r
-SBasis& operator-=(SBasis& a, const SBasis& b) {\r
-    const unsigned out_size = std::max(a.size(), b.size());\r
-    const unsigned min_size = std::min(a.size(), b.size());\r
-    a.reserve(out_size);\r
-        \r
-    for(unsigned i = 0; i < min_size; i++)\r
-        a[i] -= b[i];\r
-    for(unsigned i = min_size; i < b.size(); i++)\r
-        a.push_back(-b[i]);\r
-    \r
-    assert(a.size() == out_size);\r
-    return a;\r
-}\r
-\r
-SBasis operator*(SBasis const &a, double k) {\r
-    SBasis c;\r
-    c.reserve(a.size());\r
-    for(unsigned i = 0; i < a.size(); i++)\r
-        c.push_back(a[i] * k);\r
-    return c;\r
-}\r
-\r
-SBasis& operator*=(SBasis& a, double b) {\r
-    if (a.isZero()) return a;\r
-    if (b == 0)\r
-        a.clear();\r
-    else\r
-        for(unsigned i = 0; i < a.size(); i++)\r
-            a[i] *= b;\r
-    return a;\r
-}\r
-\r
-SBasis shift(SBasis const &a, int sh) {\r
-    SBasis c = a;\r
-    if(sh > 0) {\r
-        c.insert(c.begin(), sh, Linear(0,0));\r
-    } else {\r
-        //TODO: truncate\r
-    }\r
-    return c;\r
-}\r
-\r
-SBasis shift(Linear const &a, int sh) {\r
-    SBasis c;\r
-    if(sh > 0) {\r
-        c.insert(c.begin(), sh, Linear(0,0));\r
-        c.push_back(a);\r
-    }\r
-    return c;\r
-}\r
-\r
-SBasis multiply(SBasis const &a, SBasis const &b) {\r
-    // c = {a0*b0 - shift(1, a.Tri*b.Tri), a1*b1 - shift(1, a.Tri*b.Tri)}\r
-    \r
-    // shift(1, a.Tri*b.Tri)\r
-    SBasis c;\r
-    if(a.isZero() || b.isZero())\r
-        return c;\r
-    c.resize(a.size() + b.size(), Linear(0,0));\r
-    c[0] = Linear(0,0);\r
-    for(unsigned j = 0; j < b.size(); j++) {\r
-        for(unsigned i = j; i < a.size()+j; i++) {\r
-            double tri = Tri(b[j])*Tri(a[i-j]);\r
-            c[i+1/*shift*/] += Linear(Hat(-tri));\r
-        }\r
-    }\r
-    for(unsigned j = 0; j < b.size(); j++) {\r
-        for(unsigned i = j; i < a.size()+j; i++) {\r
-            for(unsigned dim = 0; dim < 2; dim++)\r
-                c[i][dim] += b[j][dim]*a[i-j][dim];\r
-        }\r
-    }\r
-    c.normalize();\r
-    //assert(!(0 == c.back()[0] && 0 == c.back()[1]));\r
-    return c;\r
-}\r
-\r
-SBasis integral(SBasis const &c) {\r
-    SBasis a;\r
-    a.resize(c.size() + 1, Linear(0,0));\r
-    a[0] = Linear(0,0);\r
-    \r
-    for(unsigned k = 1; k < c.size() + 1; k++) {\r
-        double ahat = -Tri(c[k-1])/(2*k);\r
-        a[k] = Hat(ahat);\r
-    }\r
-    double aTri = 0;\r
-    for(int k = c.size()-1; k >= 0; k--) {\r
-        aTri = (Hat(c[k]).d + (k+1)*aTri/2)/(2*k+1);\r
-        a[k][0] -= aTri/2;\r
-        a[k][1] += aTri/2;\r
-    }\r
-    a.normalize();\r
-    return a;\r
-}\r
-\r
-SBasis derivative(SBasis const &a) {\r
-    SBasis c;\r
-    c.resize(a.size(), Linear(0,0));\r
-    \r
-    for(unsigned k = 0; k < a.size(); k++) {\r
-        double d = (2*k+1)*Tri(a[k]);\r
-        \r
-        for(unsigned dim = 0; dim < 2; dim++) {\r
-            c[k][dim] = d;\r
-            if(k+1 < a.size()) {\r
-                if(dim)\r
-                    c[k][dim] = d - (k+1)*a[k+1][dim];\r
-                else\r
-                    c[k][dim] = d + (k+1)*a[k+1][dim];\r
-            }\r
-        }\r
-    }\r
-    \r
-    return c;\r
-}\r
-\r
-//TODO: convert int k to unsigned k, and remove cast\r
-SBasis sqrt(SBasis const &a, int k) {\r
-    SBasis c;\r
-    if(a.isZero() || k == 0)\r
-        return c;\r
-    c.resize(k, Linear(0,0));\r
-    c[0] = Linear(std::sqrt(a[0][0]), std::sqrt(a[0][1]));\r
-    SBasis r = a - multiply(c, c); // remainder\r
-    \r
-    for(unsigned i = 1; i <= (unsigned)k and i<r.size(); i++) {\r
-        Linear ci(r[i][0]/(2*c[0][0]), r[i][1]/(2*c[0][1]));\r
-        SBasis cisi = shift(ci, i);\r
-        r -= multiply(shift((c*2 + cisi), i), SBasis(ci));\r
-        r.truncate(k+1);\r
-        c += cisi;\r
-        if(r.tailError(i) == 0) // if exact\r
-            break;\r
-    }\r
-    \r
-    return c;\r
-}\r
-\r
-// return a kth order approx to 1/a)\r
-SBasis reciprocal(Linear const &a, int k) {\r
-    SBasis c;\r
-    assert(!a.isZero());\r
-    c.resize(k, Linear(0,0));\r
-    double r_s0 = (Tri(a)*Tri(a))/(-a[0]*a[1]);\r
-    double r_s0k = 1;\r
-    for(unsigned i = 0; i < (unsigned)k; i++) {\r
-        c[i] = Linear(r_s0k/a[0], r_s0k/a[1]);\r
-        r_s0k *= r_s0;\r
-    }\r
-    return c;\r
-}\r
-\r
-SBasis divide(SBasis const &a, SBasis const &b, int k) {\r
-    SBasis c;\r
-    assert(!a.isZero());\r
-    SBasis r = a; // remainder\r
-    \r
-    k++;\r
-    r.resize(k, Linear(0,0));\r
-    c.resize(k, Linear(0,0));\r
-\r
-    for(unsigned i = 0; i < (unsigned)k; i++) {\r
-        Linear ci(r[i][0]/b[0][0], r[i][1]/b[0][1]); //H0\r
-        c[i] += ci;\r
-        r -= shift(multiply(ci,b), i);\r
-        r.truncate(k+1);\r
-        if(r.tailError(i) == 0) // if exact\r
-            break;\r
-    }\r
-    \r
-    return c;\r
-}\r
-\r
-// a(b)\r
-// return a0 + s(a1 + s(a2 +...  where s = (1-u)u; ak =(1 - u)a^0_k + ua^1_k\r
-SBasis compose(SBasis const &a, SBasis const &b) {\r
-    SBasis s = multiply((SBasis(Linear(1,1))-b), b);\r
-    SBasis r;\r
-    \r
-    for(int i = a.size()-1; i >= 0; i--) {\r
-        r = SBasis(Linear(Hat(a[i][0]))) - b*a[i][0] + b*a[i][1] + multiply(r,s);\r
-    }\r
-    return r;\r
-}\r
-\r
-// a(b)\r
-// return a0 + s(a1 + s(a2 +...  where s = (1-u)u; ak =(1 - u)a^0_k + ua^1_k\r
-SBasis compose(SBasis const &a, SBasis const &b, unsigned k) {\r
-    SBasis s = multiply((SBasis(Linear(1,1))-b), b);\r
-    SBasis r;\r
-    \r
-    for(int i = a.size()-1; i >= 0; i--) {\r
-        r = SBasis(Linear(Hat(a[i][0]))) - b*a[i][0] + b*a[i][1] + multiply(r,s);\r
-    }\r
-    r.truncate(k);\r
-    return r;\r
-}\r
-\r
-/*\r
-Inversion algorithm. The notation is certainly very misleading. The\r
-pseudocode should say:\r
-\r
-c(v) := 0\r
-r(u) := r_0(u) := u\r
-for i:=0 to k do\r
-  c_i(v) := H_0(r_i(u)/(t_1)^i; u)\r
-  c(v) := c(v) + c_i(v)*t^i\r
-  r(u) := r(u) ? c_i(u)*(t(u))^i\r
-endfor\r
-*/\r
-\r
-//#define DEBUG_INVERSION 1 \r
-\r
-SBasis inverse(SBasis a, int k) {\r
-    assert(a.size() > 0);\r
-// the function should have 'unit range'("a00 = 0 and a01 = 1") and be monotonic.\r
-    double a0 = a[0][0];\r
-    if(a0 != 0) {\r
-        a -= a0;\r
-    }\r
-    double a1 = a[0][1];\r
-    assert(a1 != 0); // not invertable.\r
-    \r
-    if(a1 != 1) {\r
-        a /= a1;\r
-    }\r
-    SBasis c;                           // c(v) := 0\r
-    if(a.size() >= 2 && k == 2) {\r
-        c.push_back(Linear(0,1));\r
-        Linear t1(1+a[1][0], 1-a[1][1]);    // t_1\r
-        c.push_back(Linear(-a[1][0]/t1[0], -a[1][1]/t1[1]));\r
-    } else if(a.size() >= 2) {                      // non linear\r
-        SBasis r = Linear(0,1);             // r(u) := r_0(u) := u\r
-        Linear t1(1./(1+a[1][0]), 1./(1-a[1][1]));    // 1./t_1\r
-        Linear one(1,1);\r
-        Linear t1i = one;                   // t_1^0\r
-        SBasis one_minus_a = SBasis(one) - a;\r
-        SBasis t = multiply(one_minus_a, a); // t(u)\r
-        SBasis ti(one);                     // t(u)^0\r
-#ifdef DEBUG_INVERSION\r
-        std::cout << "a=" << a << std::endl;\r
-        std::cout << "1-a=" << one_minus_a << std::endl;\r
-        std::cout << "t1=" << t1 << std::endl;\r
-        //assert(t1 == t[1]);\r
-#endif\r
-    \r
-        c.resize(k+1, Linear(0,0));\r
-        for(unsigned i = 0; i < (unsigned)k; i++) {   // for i:=0 to k do\r
-#ifdef DEBUG_INVERSION\r
-            std::cout << "-------" << i << ": ---------" <<std::endl;\r
-            std::cout << "r=" << r << std::endl\r
-                      << "c=" << c << std::endl\r
-                      << "ti=" << ti << std::endl\r
-                      << std::endl;\r
-#endif\r
-            if(r.size() <= i)                // ensure enough space in the remainder, probably not needed\r
-                r.resize(i+1, Linear(0,0));\r
-            Linear ci(r[i][0]*t1i[0], r[i][1]*t1i[1]); // c_i(v) := H_0(r_i(u)/(t_1)^i; u)\r
-#ifdef DEBUG_INVERSION\r
-            std::cout << "t1i=" << t1i << std::endl;\r
-            std::cout << "ci=" << ci << std::endl;\r
-#endif\r
-            for(int dim = 0; dim < 2; dim++) // t1^-i *= 1./t1\r
-                t1i[dim] *= t1[dim];\r
-            c[i] = ci; // c(v) := c(v) + c_i(v)*t^i\r
-            // change from v to u parameterisation\r
-            SBasis civ = one_minus_a*ci[0] + a*ci[1]; \r
-            // r(u) := r(u) - c_i(u)*(t(u))^i\r
-            // We can truncate this to the number of final terms, as no following terms can\r
-            // contribute to the result.\r
-            r -= multiply(civ,ti);\r
-            r.truncate(k);\r
-            if(r.tailError(i) == 0)\r
-                break; // yay!\r
-            ti = multiply(ti,t);\r
-        }\r
-#ifdef DEBUG_INVERSION\r
-        std::cout << "##########################" << std::endl;\r
-#endif\r
-    } else\r
-        c = Linear(0,1); // linear\r
-    c -= a0; // invert the offset\r
-    c /= a1; // invert the slope\r
-    return c;\r
-}\r
-\r
-SBasis sin(Linear b, int k) {\r
-    SBasis s = Linear(std::sin(b[0]), std::sin(b[1]));\r
-    Tri tr(s[0]);\r
-    double t2 = Tri(b);\r
-    s.push_back(Linear(std::cos(b[0])*t2 - tr, -std::cos(b[1])*t2 + tr));\r
-    \r
-    t2 *= t2;\r
-    for(int i = 0; i < k; i++) {\r
-        Linear bo(4*(i+1)*s[i+1][0] - 2*s[i+1][1],\r
-                  -2*s[i+1][0] + 4*(i+1)*s[i+1][1]);\r
-        bo -= s[i]*(t2/(i+1));\r
-        \r
-        \r
-        s.push_back(bo/double(i+2));\r
-    }\r
-    \r
-    return s;\r
-}\r
-\r
-SBasis cos(Linear bo, int k) {\r
-    return sin(Linear(bo[0] + M_PI/2,\r
-                      bo[1] + M_PI/2),\r
-               k);\r
-}\r
-\r
-//compute fog^-1. ("zero" = double comparison threshold. *!*we might divide by "zero"*!*)\r
-//TODO: compute order according to tol?\r
-//TODO: requires g(0)=0 & g(1)=1 atm... adaptation to other cases should be obvious!\r
-SBasis compose_inverse(SBasis const &f, SBasis const &g, unsigned order, double zero){\r
-    SBasis result; //result\r
-    SBasis r=f; //remainder\r
-    SBasis Pk=Linear(1)-g,Qk=g,sg=Pk*Qk;\r
-    Pk.truncate(order);\r
-    Qk.truncate(order);\r
-    Pk.resize(order,Linear(0.));\r
-    Qk.resize(order,Linear(0.));\r
-    r.resize(order,Linear(0.));\r
-\r
-    int vs= valuation(sg,zero);\r
-    \r
-    for (unsigned k=0; k<order; k+=vs){\r
-        double p10 = Pk.at(k)[0];// we have to solve the linear system:\r
-        double p01 = Pk.at(k)[1];//\r
-        double q10 = Qk.at(k)[0];//   p10*a + q10*b = r10\r
-        double q01 = Qk.at(k)[1];// &                    \r
-        double r10 =  r.at(k)[0];//   p01*a + q01*b = r01\r
-        double r01 =  r.at(k)[1];//\r
-        double a,b;\r
-        double det = p10*q01-p01*q10;\r
-\r
-        //TODO: handle det~0!! \r
-        if (fabs(det)<zero){\r
-            det = zero;\r
-            a=b=0;\r
-        }else{\r
-            a=( q01*r10-q10*r01)/det;\r
-            b=(-p01*r10+p10*r01)/det;\r
-        }\r
-        result.push_back(Linear(a,b));\r
-        r=r-Pk*a-Qk*b;\r
-        \r
-        Pk=Pk*sg;\r
-        Qk=Qk*sg;\r
-        Pk.truncate(order);\r
-        Qk.truncate(order);\r
-        r.truncate(order);\r
-    }\r
-    result.normalize();\r
-    return result;\r
-}\r
-\r
-}\r
-\r
-/*\r
-  Local Variables:\r
-  mode:c++\r
-  c-file-style:"stroustrup"\r
-  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
-  indent-tabs-mode:nil\r
-  fill-column:99\r
-  End:\r
-*/\r
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :\r
+
+double SBasis::tailError(unsigned tail) const {
+  Interval bs = bounds_fast(*this, tail);
+  return std::max(fabs(bs.min()),fabs(bs.max()));
+}
+
+bool SBasis::isFinite() const {
+    for(unsigned i = 0; i < size(); i++) {
+        if(!(*this)[i].isFinite())
+            return false;
+    }
+    return true;
+}
+
+SBasis operator+(const SBasis& a, const SBasis& b) {
+    SBasis result;
+    const unsigned out_size = std::max(a.size(), b.size());
+    const unsigned min_size = std::min(a.size(), b.size());
+    result.reserve(out_size);
+
+    for(unsigned i = 0; i < min_size; i++) {
+        result.push_back(a[i] + b[i]);
+    }
+    for(unsigned i = min_size; i < a.size(); i++)
+        result.push_back(a[i]);
+    for(unsigned i = min_size; i < b.size(); i++)
+        result.push_back(b[i]);
+
+    assert(result.size() == out_size);
+    return result;
+}
+
+SBasis operator-(const SBasis& a, const SBasis& b) {
+    SBasis result;
+    const unsigned out_size = std::max(a.size(), b.size());
+    const unsigned min_size = std::min(a.size(), b.size());
+    result.reserve(out_size);
+
+    for(unsigned i = 0; i < min_size; i++) {
+        result.push_back(a[i] - b[i]);
+    }
+    for(unsigned i = min_size; i < a.size(); i++)
+        result.push_back(a[i]);
+    for(unsigned i = min_size; i < b.size(); i++)
+        result.push_back(-b[i]);
+
+    assert(result.size() == out_size);
+    return result;
+}
+
+SBasis& operator+=(SBasis& a, const SBasis& b) {
+    const unsigned out_size = std::max(a.size(), b.size());
+    const unsigned min_size = std::min(a.size(), b.size());
+    a.reserve(out_size);
+
+    for(unsigned i = 0; i < min_size; i++)
+        a[i] += b[i];
+    for(unsigned i = min_size; i < b.size(); i++)
+        a.push_back(b[i]);
+
+    assert(a.size() == out_size);
+    return a;
+}
+
+SBasis& operator-=(SBasis& a, const SBasis& b) {
+    const unsigned out_size = std::max(a.size(), b.size());
+    const unsigned min_size = std::min(a.size(), b.size());
+    a.reserve(out_size);
+
+    for(unsigned i = 0; i < min_size; i++)
+        a[i] -= b[i];
+    for(unsigned i = min_size; i < b.size(); i++)
+        a.push_back(-b[i]);
+
+    assert(a.size() == out_size);
+    return a;
+}
+
+SBasis operator*(SBasis const &a, double k) {
+    SBasis c;
+    c.reserve(a.size());
+    for(unsigned i = 0; i < a.size(); i++)
+        c.push_back(a[i] * k);
+    return c;
+}
+
+SBasis& operator*=(SBasis& a, double b) {
+    if (a.isZero()) return a;
+    if (b == 0)
+        a.clear();
+    else
+        for(unsigned i = 0; i < a.size(); i++)
+            a[i] *= b;
+    return a;
+}
+
+SBasis shift(SBasis const &a, int sh) {
+    SBasis c = a;
+    if(sh > 0) {
+        c.insert(c.begin(), sh, Linear(0,0));
+    } else {
+        //TODO: truncate
+    }
+    return c;
+}
+
+SBasis shift(Linear const &a, int sh) {
+    SBasis c;
+    if(sh > 0) {
+        c.insert(c.begin(), sh, Linear(0,0));
+        c.push_back(a);
+    }
+    return c;
+}
+
+SBasis multiply(SBasis const &a, SBasis const &b) {
+    // c = {a0*b0 - shift(1, a.Tri*b.Tri), a1*b1 - shift(1, a.Tri*b.Tri)}
+
+    // shift(1, a.Tri*b.Tri)
+    SBasis c;
+    if(a.isZero() || b.isZero())
+        return c;
+    c.resize(a.size() + b.size(), Linear(0,0));
+    c[0] = Linear(0,0);
+    for(unsigned j = 0; j < b.size(); j++) {
+        for(unsigned i = j; i < a.size()+j; i++) {
+            double tri = Tri(b[j])*Tri(a[i-j]);
+            c[i+1/*shift*/] += Linear(Hat(-tri));
+        }
+    }
+    for(unsigned j = 0; j < b.size(); j++) {
+        for(unsigned i = j; i < a.size()+j; i++) {
+            for(unsigned dim = 0; dim < 2; dim++)
+                c[i][dim] += b[j][dim]*a[i-j][dim];
+        }
+    }
+    c.normalize();
+    //assert(!(0 == c.back()[0] && 0 == c.back()[1]));
+    return c;
+}
+
+SBasis integral(SBasis const &c) {
+    SBasis a;
+    a.resize(c.size() + 1, Linear(0,0));
+    a[0] = Linear(0,0);
+
+    for(unsigned k = 1; k < c.size() + 1; k++) {
+        double ahat = -Tri(c[k-1])/(2*k);
+        a[k] = Hat(ahat);
+    }
+    double aTri = 0;
+    for(int k = c.size()-1; k >= 0; k--) {
+        aTri = (Hat(c[k]).d + (k+1)*aTri/2)/(2*k+1);
+        a[k][0] -= aTri/2;
+        a[k][1] += aTri/2;
+    }
+    a.normalize();
+    return a;
+}
+
+SBasis derivative(SBasis const &a) {
+    SBasis c;
+    c.resize(a.size(), Linear(0,0));
+
+    for(unsigned k = 0; k < a.size(); k++) {
+        double d = (2*k+1)*Tri(a[k]);
+
+        for(unsigned dim = 0; dim < 2; dim++) {
+            c[k][dim] = d;
+            if(k+1 < a.size()) {
+                if(dim)
+                    c[k][dim] = d - (k+1)*a[k+1][dim];
+                else
+                    c[k][dim] = d + (k+1)*a[k+1][dim];
+            }
+        }
+    }
+
+    return c;
+}
+
+//TODO: convert int k to unsigned k, and remove cast
+SBasis sqrt(SBasis const &a, int k) {
+    SBasis c;
+    if(a.isZero() || k == 0)
+        return c;
+    c.resize(k, Linear(0,0));
+    c[0] = Linear(std::sqrt(a[0][0]), std::sqrt(a[0][1]));
+    SBasis r = a - multiply(c, c); // remainder
+
+    for(unsigned i = 1; i <= (unsigned)k and i<r.size(); i++) {
+        Linear ci(r[i][0]/(2*c[0][0]), r[i][1]/(2*c[0][1]));
+        SBasis cisi = shift(ci, i);
+        r -= multiply(shift((c*2 + cisi), i), SBasis(ci));
+        r.truncate(k+1);
+        c += cisi;
+        if(r.tailError(i) == 0) // if exact
+            break;
+    }
+
+    return c;
+}
+
+// return a kth order approx to 1/a)
+SBasis reciprocal(Linear const &a, int k) {
+    SBasis c;
+    assert(!a.isZero());
+    c.resize(k, Linear(0,0));
+    double r_s0 = (Tri(a)*Tri(a))/(-a[0]*a[1]);
+    double r_s0k = 1;
+    for(unsigned i = 0; i < (unsigned)k; i++) {
+        c[i] = Linear(r_s0k/a[0], r_s0k/a[1]);
+        r_s0k *= r_s0;
+    }
+    return c;
+}
+
+SBasis divide(SBasis const &a, SBasis const &b, int k) {
+    SBasis c;
+    assert(!a.isZero());
+    SBasis r = a; // remainder
+
+    k++;
+    r.resize(k, Linear(0,0));
+    c.resize(k, Linear(0,0));
+
+    for(unsigned i = 0; i < (unsigned)k; i++) {
+        Linear ci(r[i][0]/b[0][0], r[i][1]/b[0][1]); //H0
+        c[i] += ci;
+        r -= shift(multiply(ci,b), i);
+        r.truncate(k+1);
+        if(r.tailError(i) == 0) // if exact
+            break;
+    }
+
+    return c;
+}
+
+// a(b)
+// return a0 + s(a1 + s(a2 +...  where s = (1-u)u; ak =(1 - u)a^0_k + ua^1_k
+SBasis compose(SBasis const &a, SBasis const &b) {
+    SBasis s = multiply((SBasis(Linear(1,1))-b), b);
+    SBasis r;
+
+    for(int i = a.size()-1; i >= 0; i--) {
+        r = SBasis(Linear(Hat(a[i][0]))) - b*a[i][0] + b*a[i][1] + multiply(r,s);
+    }
+    return r;
+}
+
+// a(b)
+// return a0 + s(a1 + s(a2 +...  where s = (1-u)u; ak =(1 - u)a^0_k + ua^1_k
+SBasis compose(SBasis const &a, SBasis const &b, unsigned k) {
+    SBasis s = multiply((SBasis(Linear(1,1))-b), b);
+    SBasis r;
+
+    for(int i = a.size()-1; i >= 0; i--) {
+        r = SBasis(Linear(Hat(a[i][0]))) - b*a[i][0] + b*a[i][1] + multiply(r,s);
+    }
+    r.truncate(k);
+    return r;
+}
+
+/*
+Inversion algorithm. The notation is certainly very misleading. The
+pseudocode should say:
+
+c(v) := 0
+r(u) := r_0(u) := u
+for i:=0 to k do
+  c_i(v) := H_0(r_i(u)/(t_1)^i; u)
+  c(v) := c(v) + c_i(v)*t^i
+  r(u) := r(u) ? c_i(u)*(t(u))^i
+endfor
+*/
+
+//#define DEBUG_INVERSION 1
+
+SBasis inverse(SBasis a, int k) {
+    assert(a.size() > 0);
+// the function should have 'unit range'("a00 = 0 and a01 = 1") and be monotonic.
+    double a0 = a[0][0];
+    if(a0 != 0) {
+        a -= a0;
+    }
+    double a1 = a[0][1];
+    assert(a1 != 0); // not invertable.
+
+    if(a1 != 1) {
+        a /= a1;
+    }
+    SBasis c;                           // c(v) := 0
+    if(a.size() >= 2 && k == 2) {
+        c.push_back(Linear(0,1));
+        Linear t1(1+a[1][0], 1-a[1][1]);    // t_1
+        c.push_back(Linear(-a[1][0]/t1[0], -a[1][1]/t1[1]));
+    } else if(a.size() >= 2) {                      // non linear
+        SBasis r = Linear(0,1);             // r(u) := r_0(u) := u
+        Linear t1(1./(1+a[1][0]), 1./(1-a[1][1]));    // 1./t_1
+        Linear one(1,1);
+        Linear t1i = one;                   // t_1^0
+        SBasis one_minus_a = SBasis(one) - a;
+        SBasis t = multiply(one_minus_a, a); // t(u)
+        SBasis ti(one);                     // t(u)^0
+#ifdef DEBUG_INVERSION
+        std::cout << "a=" << a << std::endl;
+        std::cout << "1-a=" << one_minus_a << std::endl;
+        std::cout << "t1=" << t1 << std::endl;
+        //assert(t1 == t[1]);
+#endif
+
+        c.resize(k+1, Linear(0,0));
+        for(unsigned i = 0; i < (unsigned)k; i++) {   // for i:=0 to k do
+#ifdef DEBUG_INVERSION
+            std::cout << "-------" << i << ": ---------" <<std::endl;
+            std::cout << "r=" << r << std::endl
+                      << "c=" << c << std::endl
+                      << "ti=" << ti << std::endl
+                      << std::endl;
+#endif
+            if(r.size() <= i)                // ensure enough space in the remainder, probably not needed
+                r.resize(i+1, Linear(0,0));
+            Linear ci(r[i][0]*t1i[0], r[i][1]*t1i[1]); // c_i(v) := H_0(r_i(u)/(t_1)^i; u)
+#ifdef DEBUG_INVERSION
+            std::cout << "t1i=" << t1i << std::endl;
+            std::cout << "ci=" << ci << std::endl;
+#endif
+            for(int dim = 0; dim < 2; dim++) // t1^-i *= 1./t1
+                t1i[dim] *= t1[dim];
+            c[i] = ci; // c(v) := c(v) + c_i(v)*t^i
+            // change from v to u parameterisation
+            SBasis civ = one_minus_a*ci[0] + a*ci[1];
+            // r(u) := r(u) - c_i(u)*(t(u))^i
+            // We can truncate this to the number of final terms, as no following terms can
+            // contribute to the result.
+            r -= multiply(civ,ti);
+            r.truncate(k);
+            if(r.tailError(i) == 0)
+                break; // yay!
+            ti = multiply(ti,t);
+        }
+#ifdef DEBUG_INVERSION
+        std::cout << "##########################" << std::endl;
+#endif
+    } else
+        c = Linear(0,1); // linear
+    c -= a0; // invert the offset
+    c /= a1; // invert the slope
+    return c;
+}
+
+SBasis sin(Linear b, int k) {
+    SBasis s = Linear(std::sin(b[0]), std::sin(b[1]));
+    Tri tr(s[0]);
+    double t2 = Tri(b);
+    s.push_back(Linear(std::cos(b[0])*t2 - tr, -std::cos(b[1])*t2 + tr));
+
+    t2 *= t2;
+    for(int i = 0; i < k; i++) {
+        Linear bo(4*(i+1)*s[i+1][0] - 2*s[i+1][1],
+                  -2*s[i+1][0] + 4*(i+1)*s[i+1][1]);
+        bo -= s[i]*(t2/(i+1));
+
+
+        s.push_back(bo/double(i+2));
+    }
+
+    return s;
+}
+
+SBasis cos(Linear bo, int k) {
+    return sin(Linear(bo[0] + M_PI/2,
+                      bo[1] + M_PI/2),
+               k);
+}
+
+//compute fog^-1. ("zero" = double comparison threshold. *!*we might divide by "zero"*!*)
+//TODO: compute order according to tol?
+//TODO: requires g(0)=0 & g(1)=1 atm... adaptation to other cases should be obvious!
+SBasis compose_inverse(SBasis const &f, SBasis const &g, unsigned order, double zero){
+    SBasis result; //result
+    SBasis r=f; //remainder
+    SBasis Pk=Linear(1)-g,Qk=g,sg=Pk*Qk;
+    Pk.truncate(order);
+    Qk.truncate(order);
+    Pk.resize(order,Linear(0.));
+    Qk.resize(order,Linear(0.));
+    r.resize(order,Linear(0.));
+
+    int vs= valuation(sg,zero);
+
+    for (unsigned k=0; k<order; k+=vs){
+        double p10 = Pk.at(k)[0];// we have to solve the linear system:
+        double p01 = Pk.at(k)[1];//
+        double q10 = Qk.at(k)[0];//   p10*a + q10*b = r10
+        double q01 = Qk.at(k)[1];// &
+        double r10 =  r.at(k)[0];//   p01*a + q01*b = r01
+        double r01 =  r.at(k)[1];//
+        double a,b;
+        double det = p10*q01-p01*q10;
+
+        //TODO: handle det~0!!
+        if (fabs(det)<zero){
+            det = zero;
+            a=b=0;
+        }else{
+            a=( q01*r10-q10*r01)/det;
+            b=(-p01*r10+p10*r01)/det;
+        }
+        result.push_back(Linear(a,b));
+        r=r-Pk*a-Qk*b;
+
+        Pk=Pk*sg;
+        Qk=Qk*sg;
+        Pk.truncate(order);
+        Qk.truncate(order);
+        r.truncate(order);
+    }
+    result.normalize();
+    return result;
+}
+
+}
+
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+  indent-tabs-mode:nil
+  fill-column:99
+  End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
index 4329bc55925ea8eaf055672807d13121bd94f169..08674ab2fa872395a2c69da985b4e101a018e4d0 100644 (file)
-#include "sweep.h"\r
-\r
-#include <algorithm>\r
-\r
-namespace Geom {\r
-\r
-std::vector<std::vector<unsigned> > sweep_bounds(std::vector<Rect> rs) {\r
-    std::vector<Event> events; events.reserve(rs.size()*2);\r
-    std::vector<std::vector<unsigned> > pairs(rs.size());\r
-    \r
-    for(unsigned i = 0; i < rs.size(); i++) {\r
-        events.push_back(Event(rs[i].left(), i, false));\r
-        events.push_back(Event(rs[i].right(), i, true));\r
-    }\r
-    std::sort(events.begin(), events.end());\r
-\r
-    std::vector<unsigned> open;\r
-    for(unsigned i = 0; i < events.size(); i++) {\r
-        unsigned ix = events[i].ix;\r
-        if(events[i].closing) {\r
-            std::vector<unsigned>::iterator iter = std::find(open.begin(), open.end(), ix);\r
-            //if(iter != open.end())\r
-            open.erase(iter);\r
-        } else {\r
-            for(unsigned j = 0; j < open.size(); j++) {\r
-                unsigned jx = open[j];\r
-                if(rs[jx][Y].intersects(rs[ix][Y])) {\r
-                    pairs[jx].push_back(ix);\r
-                }\r
-            }\r
-            open.push_back(ix);\r
-        }\r
-    }\r
-    return pairs;\r
-}\r
-\r
-std::vector<std::vector<unsigned> > sweep_bounds(std::vector<Rect> a, std::vector<Rect> b) {\r
-    std::vector<std::vector<unsigned> > pairs(a.size());\r
-    if(a.empty() || b.empty()) return pairs;\r
-    std::vector<Event> events[2];\r
-    events[0].reserve(a.size()*2);\r
-    events[1].reserve(b.size()*2);\r
-    \r
-    for(unsigned n = 0; n < 2; n++) {\r
-        unsigned sz = n ? b.size() : a.size();\r
-        events[n].reserve(sz*2);\r
-        for(unsigned i = 0; i < sz; i++) {\r
-            events[n].push_back(Event(n ? b[i].left() : a[i].left(), i, false));\r
-            events[n].push_back(Event(n ? b[i].right() : a[i].right(), i, true));\r
-        }\r
-        std::sort(events[n].begin(), events[n].end());\r
-    }\r
-\r
-    std::vector<unsigned> open[2];\r
-    bool n = events[1].front() < events[0].front();\r
-    for(unsigned i[] = {0,0}; i[n] < events[n].size();) {\r
-        unsigned ix = events[n][i[n]].ix;\r
-        bool closing = events[n][i[n]].closing;\r
-        //std::cout << n << "[" << ix << "] - " << (closing ? "closer" : "opener") << "\n";\r
-        if(closing) {\r
-            open[n].erase(std::find(open[n].begin(), open[n].end(), ix));\r
-        } else {\r
-            if(n) {\r
-                //n = 1\r
-                //opening a B, add to all open a\r
-                for(unsigned j = 0; j < open[0].size(); j++) {\r
-                    unsigned jx = open[0][j];\r
-                    if(a[jx][Y].intersects(b[ix][Y])) {\r
-                        pairs[jx].push_back(ix);\r
-                    }\r
-                }\r
-            } else {\r
-                //n = 0\r
-                //opening an A, add all open b\r
-                for(unsigned j = 0; j < open[1].size(); j++) {\r
-                    unsigned jx = open[1][j];\r
-                    if(b[jx][Y].intersects(a[ix][Y])) {\r
-                        pairs[ix].push_back(jx);\r
-                    }\r
-                }\r
-            }\r
-            open[n].push_back(ix);\r
-        }\r
-        i[n]++;\r
-        n = (events[!n][i[!n]] < events[n][i[n]]) ? !n : n;\r
-    }\r
-    return pairs;\r
-}\r
-\r
-//Fake cull, until the switch to the real sweep is made.\r
-std::vector<std::vector<unsigned> > fake_cull(unsigned a, unsigned b) {\r
-    std::vector<std::vector<unsigned> > ret;\r
-    \r
-    std::vector<unsigned> all;\r
-    for(unsigned j = 0; j < b; j++)\r
-        all.push_back(j);\r
-    \r
-    for(unsigned i = 0; i < a; i++)\r
-        ret.push_back(all);\r
-    \r
-    return ret;\r
-}\r
-\r
-}\r
+#include "sweep.h"
+
+#include <algorithm>
+
+namespace Geom {
+
+std::vector<std::vector<unsigned> > sweep_bounds(std::vector<Rect> rs) {
+    std::vector<Event> events; events.reserve(rs.size()*2);
+    std::vector<std::vector<unsigned> > pairs(rs.size());
+
+    for(unsigned i = 0; i < rs.size(); i++) {
+        events.push_back(Event(rs[i].left(), i, false));
+        events.push_back(Event(rs[i].right(), i, true));
+    }
+    std::sort(events.begin(), events.end());
+
+    std::vector<unsigned> open;
+    for(unsigned i = 0; i < events.size(); i++) {
+        unsigned ix = events[i].ix;
+        if(events[i].closing) {
+            std::vector<unsigned>::iterator iter = std::find(open.begin(), open.end(), ix);
+            //if(iter != open.end())
+            open.erase(iter);
+        } else {
+            for(unsigned j = 0; j < open.size(); j++) {
+                unsigned jx = open[j];
+                if(rs[jx][Y].intersects(rs[ix][Y])) {
+                    pairs[jx].push_back(ix);
+                }
+            }
+            open.push_back(ix);
+        }
+    }
+    return pairs;
+}
+
+std::vector<std::vector<unsigned> > sweep_bounds(std::vector<Rect> a, std::vector<Rect> b) {
+    std::vector<std::vector<unsigned> > pairs(a.size());
+    if(a.empty() || b.empty()) return pairs;
+    std::vector<Event> events[2];
+    events[0].reserve(a.size()*2);
+    events[1].reserve(b.size()*2);
+
+    for(unsigned n = 0; n < 2; n++) {
+        unsigned sz = n ? b.size() : a.size();
+        events[n].reserve(sz*2);
+        for(unsigned i = 0; i < sz; i++) {
+            events[n].push_back(Event(n ? b[i].left() : a[i].left(), i, false));
+            events[n].push_back(Event(n ? b[i].right() : a[i].right(), i, true));
+        }
+        std::sort(events[n].begin(), events[n].end());
+    }
+
+    std::vector<unsigned> open[2];
+    bool n = events[1].front() < events[0].front();
+    for(unsigned i[] = {0,0}; i[n] < events[n].size();) {
+        unsigned ix = events[n][i[n]].ix;
+        bool closing = events[n][i[n]].closing;
+        //std::cout << n << "[" << ix << "] - " << (closing ? "closer" : "opener") << "\n";
+        if(closing) {
+            open[n].erase(std::find(open[n].begin(), open[n].end(), ix));
+        } else {
+            if(n) {
+                //n = 1
+                //opening a B, add to all open a
+                for(unsigned j = 0; j < open[0].size(); j++) {
+                    unsigned jx = open[0][j];
+                    if(a[jx][Y].intersects(b[ix][Y])) {
+                        pairs[jx].push_back(ix);
+                    }
+                }
+            } else {
+                //n = 0
+                //opening an A, add all open b
+                for(unsigned j = 0; j < open[1].size(); j++) {
+                    unsigned jx = open[1][j];
+                    if(b[jx][Y].intersects(a[ix][Y])) {
+                        pairs[ix].push_back(jx);
+                    }
+                }
+            }
+            open[n].push_back(ix);
+        }
+        i[n]++;
+        n = (events[!n][i[!n]] < events[n][i[n]]) ? !n : n;
+    }
+    return pairs;
+}
+
+//Fake cull, until the switch to the real sweep is made.
+std::vector<std::vector<unsigned> > fake_cull(unsigned a, unsigned b) {
+    std::vector<std::vector<unsigned> > ret;
+
+    std::vector<unsigned> all;
+    for(unsigned j = 0; j < b; j++)
+        all.push_back(j);
+
+    for(unsigned i = 0; i < a; i++)
+        ret.push_back(all);
+
+    return ret;
+}
+
+}
index 4837317bfb903d1f7caf2cffd523e21cc89e8048..9ac75cb3cb491a29e475b31c84b8416bb48471ed 100644 (file)
-#define INKSCAPE_LPE_PATHALONGPATH_CPP\r
-\r
-/*\r
- * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>\r
- *\r
- * Released under GNU GPL, read the file 'COPYING' for more information\r
- */\r
-\r
-#include "live_effects/lpe-pathalongpath.h"\r
-#include "sp-shape.h"\r
-#include "sp-item.h"\r
-#include "sp-path.h"\r
-#include "display/curve.h"\r
-#include <libnr/n-art-bpath.h>\r
-#include <libnr/nr-matrix-fns.h>\r
-#include "live_effects/n-art-bpath-2geom.h"\r
-#include "svg/svg.h"\r
-#include "ui/widget/scalar.h"\r
-\r
-#include <2geom/sbasis.h>\r
-#include <2geom/sbasis-geometric.h>\r
-#include <2geom/bezier-to-sbasis.h>\r
-#include <2geom/sbasis-to-bezier.h>\r
-#include <2geom/d2.h>\r
-#include <2geom/piecewise.h>\r
-\r
-#include <algorithm>\r
-using std::vector;\r
-\r
-\r
-/* Theory in e-mail from J.F. Barraud\r
-Let B be the skeleton path, and P the pattern (the path to be deformed).\r
-\r
-P is a map t --> P(t) = ( x(t), y(t) ).\r
-B is a map t --> B(t) = ( a(t), b(t) ).\r
-\r
-The first step is to re-parametrize B by its arc length: this is the parametrization in which a point p on B is located by its distance s from start. One obtains a new map s --> U(s) = (a'(s),b'(s)), that still describes the same path B, but where the distance along B from start to\r
-U(s) is s itself.\r
-\r
-We also need a unit normal to the path. This can be obtained by computing a unit tangent vector, and rotate it by 90°. Call this normal vector N(s).\r
-\r
-The basic deformation associated to B is then given by:\r
-\r
-   (x,y) --> U(x)+y*N(x)\r
-\r
-(i.e. we go for distance x along the path, and then for distance y along the normal)\r
-\r
-Of course this formula needs some minor adaptations (as is it depends on the absolute position of P for instance, so a little translation is needed\r
-first) but I think we can first forget about them.\r
-*/\r
-\r
-namespace Inkscape {\r
-namespace LivePathEffect {\r
-\r
-static const Util::EnumData<PAPCopyType> PAPCopyTypeData[PAPCT_END] = {\r
-    {PAPCT_SINGLE,               N_("Single"),               "single"},\r
-    {PAPCT_SINGLE_STRETCHED,     N_("Single, stretched"),    "single_stretched"},\r
-    {PAPCT_REPEATED,             N_("Repeated"),             "repeated"},\r
-    {PAPCT_REPEATED_STRETCHED,   N_("Repeated, stretched"),  "repeated_stretched"}\r
-};\r
-static const Util::EnumDataConverter<PAPCopyType> PAPCopyTypeConverter(PAPCopyTypeData, PAPCT_END);\r
-\r
-LPEPathAlongPath::LPEPathAlongPath(LivePathEffectObject *lpeobject) :\r
-    Effect(lpeobject),\r
-    bend_path(_("Bend path"), _("Path along which to bend the original path"), "bendpath", &wr, this, "M0,0 L1,0"),\r
-/* Delayed until 0.47\r
-    width_path(_("Width path"), _("..."), "widthpath", &wr, this, "M0,0 L1,0"),\r
-    width_path_range(_("Width path range"), _("Range of widthpath parameter"), "widthpath_range", &wr, this, 1),\r
-*/\r
-    copytype(_("Path copies"), _("How many copies to place along the skeleton path"), "copytype", PAPCopyTypeConverter, &wr, this, PAPCT_SINGLE_STRETCHED),\r
-    prop_scale(_("Width"), _("Width of the path"), "prop_scale", &wr, this, 1),\r
-    scale_y_rel(_("Width in units of length"), _("Scale the width of the path in units of its length"), "scale_y_rel", &wr, this, false),\r
-    vertical_pattern(_("Original path is vertical"), "", "vertical", &wr, this, false)\r
-{\r
-    registerParameter( dynamic_cast<Parameter *>(&bend_path) );\r
-/* Delayed until 0.47\r
-    registerParameter( dynamic_cast<Parameter *>(&width_path) );\r
-    registerParameter( dynamic_cast<Parameter *>(&width_path_range) );\r
-*/\r
-    registerParameter( dynamic_cast<Parameter *>(&copytype) );\r
-    registerParameter( dynamic_cast<Parameter *>(&prop_scale) );\r
-    registerParameter( dynamic_cast<Parameter *>(&scale_y_rel) );\r
-    registerParameter( dynamic_cast<Parameter *>(&vertical_pattern) );\r
-\r
-    prop_scale.param_set_digits(3);\r
-    prop_scale.param_set_increments(0.01, 0.10);\r
-}\r
-\r
-LPEPathAlongPath::~LPEPathAlongPath()\r
-{\r
-\r
-}\r
-\r
-\r
-Geom::Piecewise<Geom::D2<Geom::SBasis> >\r
-LPEPathAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > & pwd2_in)\r
-{\r
-    using namespace Geom;\r
-\r
-/* Much credit should go to jfb and mgsloan of lib2geom development for the code below! */\r
-\r
-    PAPCopyType type = copytype.get_value();\r
-\r
-    Piecewise<D2<SBasis> > uskeleton = arc_length_parametrization(Piecewise<D2<SBasis> >(bend_path),2,.1);\r
-    uskeleton = remove_short_cuts(uskeleton,.01);\r
-    Rect uskeletonbounds = bounds_exact(uskeleton);\r
-    uskeleton -= uskeletonbounds.midpoint();\r
-\r
-    Piecewise<D2<SBasis> > n = rot90(derivative(uskeleton));\r
-    n = force_continuity(remove_short_cuts(n,.1));\r
-\r
-    D2<Piecewise<SBasis> > patternd2 = make_cuts_independant(pwd2_in);\r
-    Piecewise<SBasis> x = vertical_pattern.get_value() ? Piecewise<SBasis>(patternd2[1]) : Piecewise<SBasis>(patternd2[0]);\r
-    Piecewise<SBasis> y = vertical_pattern.get_value() ? Piecewise<SBasis>(patternd2[0]) : Piecewise<SBasis>(patternd2[1]);\r
-    Interval pattBnds = bounds_exact(x);\r
-    x -= pattBnds.min();\r
-    Interval pattBndsY = bounds_exact(y);\r
-    y -= pattBndsY.middle();\r
-\r
-    int nbCopies = int(uskeleton.cuts.back()/pattBnds.extent());\r
-    double scaling = 1;\r
-\r
-    switch(type) {\r
-        case PAPCT_REPEATED:\r
-            break;\r
-\r
-        case PAPCT_SINGLE:\r
-            nbCopies = (nbCopies > 0) ? 1 : 0;\r
-            break;\r
-\r
-        case PAPCT_SINGLE_STRETCHED:\r
-            nbCopies = 1;\r
-            scaling = uskeleton.cuts.back()/pattBnds.extent();\r
-            break;\r
-\r
-        case PAPCT_REPEATED_STRETCHED:\r
-             scaling = uskeleton.cuts.back()/(((double)nbCopies)*pattBnds.extent());\r
-            break;\r
-\r
-        default:\r
-            return pwd2_in;\r
-    };\r
-\r
-    double pattWidth = pattBnds.extent() * scaling;\r
-\r
-    if (scaling != 1.0) {\r
-        x*=scaling;\r
-    }\r
-    if ( scale_y_rel.get_value() ) {\r
-        y*=(scaling*prop_scale);\r
-    } else {\r
-        if (prop_scale != 1.0) y *= prop_scale;\r
-    }\r
-\r
-/* Delayed until 0.47\r
-    Piecewise<D2<SBasis> > widthpwd2 = arc_length_parametrization(Piecewise<D2<SBasis> >(width_path),2,.1);\r
-    D2<Piecewise<SBasis> > widthd2pw = make_cuts_independant(widthpwd2);\r
-    Piecewise<SBasis> width = (Piecewise<SBasis>(widthd2pw[Y]) - uskeletonbounds[Y].middle()) / width_path_range;\r
-*/\r
-\r
-    double offs = 0;\r
-    Piecewise<D2<SBasis> > output;\r
-    for (int i=0; i<nbCopies; i++){\r
-        output.concat(compose(uskeleton,x+offs) + y*/*compose(width,x+offs)**/compose(n,x+offs));\r
-        offs+=pattWidth;\r
-    }\r
-\r
-    output += Point(pattBnds.middle(), pattBndsY.middle());\r
-\r
-    return output;\r
-}\r
-\r
-void\r
-LPEPathAlongPath::resetDefaults(SPItem * item)\r
-{\r
-    if (!SP_IS_PATH(item)) return;\r
-\r
-    using namespace Geom;\r
-\r
-    // set the bend path to run horizontally in the middle of the bounding box of the original path\r
-    Piecewise<D2<SBasis> > pwd2;\r
-    std::vector<Path> temppath = SVGD_to_2GeomPath( SP_OBJECT_REPR(item)->attribute("inkscape:original-d"));\r
-    for (unsigned int i=0; i < temppath.size(); i++) {\r
-        pwd2.concat( temppath[i].toPwSb() );\r
-    }\r
-\r
-    D2<Piecewise<SBasis> > d2pw = make_cuts_independant(pwd2);\r
-    Interval bndsX = bounds_exact(d2pw[0]);\r
-    Interval bndsY = bounds_exact(d2pw[1]);\r
-    Point start(bndsX.min(), (bndsY.max()+bndsY.min())/2);\r
-    Point end(bndsX.max(), (bndsY.max()+bndsY.min())/2);\r
-\r
-    Geom::Path path;\r
-    path.start( start );\r
-    path.appendNew<Geom::LineSegment>( end );\r
-    bend_path.param_set_and_write_new_value( path.toPwSb() );\r
-\r
-/* Delayed until 0.47\r
-    Point startw(bndsX.min(), bndsY.max());\r
-    Point endw(bndsX.max(), bndsY.max());\r
-    Geom::Path pathw;\r
-    pathw.start( startw );\r
-    pathw.appendNew<Geom::LineSegment>( endw );\r
-    width_path.param_set_and_write_new_value( pathw.toPwSb() );\r
-    width_path_range.param_set_value(startw[Y]-start[Y]);\r
-*/\r
-}\r
-\r
-} // namespace LivePathEffect\r
-} /* namespace Inkscape */\r
-\r
-/*\r
-  Local Variables:\r
-  mode:c++\r
-  c-file-style:"stroustrup"\r
-  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
-  indent-tabs-mode:nil\r
-  fill-column:99\r
-  End:\r
-*/\r
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :\r
+#define INKSCAPE_LPE_PATHALONGPATH_CPP
+
+/*
+ * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "live_effects/lpe-pathalongpath.h"
+#include "sp-shape.h"
+#include "sp-item.h"
+#include "sp-path.h"
+#include "display/curve.h"
+#include <libnr/n-art-bpath.h>
+#include <libnr/nr-matrix-fns.h>
+#include "live_effects/n-art-bpath-2geom.h"
+#include "svg/svg.h"
+#include "ui/widget/scalar.h"
+
+#include <2geom/sbasis.h>
+#include <2geom/sbasis-geometric.h>
+#include <2geom/bezier-to-sbasis.h>
+#include <2geom/sbasis-to-bezier.h>
+#include <2geom/d2.h>
+#include <2geom/piecewise.h>
+
+#include <algorithm>
+using std::vector;
+
+
+/* Theory in e-mail from J.F. Barraud
+Let B be the skeleton path, and P the pattern (the path to be deformed).
+
+P is a map t --> P(t) = ( x(t), y(t) ).
+B is a map t --> B(t) = ( a(t), b(t) ).
+
+The first step is to re-parametrize B by its arc length: this is the parametrization in which a point p on B is located by its distance s from start. One obtains a new map s --> U(s) = (a'(s),b'(s)), that still describes the same path B, but where the distance along B from start to
+U(s) is s itself.
+
+We also need a unit normal to the path. This can be obtained by computing a unit tangent vector, and rotate it by 90°. Call this normal vector N(s).
+
+The basic deformation associated to B is then given by:
+
+   (x,y) --> U(x)+y*N(x)
+
+(i.e. we go for distance x along the path, and then for distance y along the normal)
+
+Of course this formula needs some minor adaptations (as is it depends on the absolute position of P for instance, so a little translation is needed
+first) but I think we can first forget about them.
+*/
+
+namespace Inkscape {
+namespace LivePathEffect {
+
+static const Util::EnumData<PAPCopyType> PAPCopyTypeData[PAPCT_END] = {
+    {PAPCT_SINGLE,               N_("Single"),               "single"},
+    {PAPCT_SINGLE_STRETCHED,     N_("Single, stretched"),    "single_stretched"},
+    {PAPCT_REPEATED,             N_("Repeated"),             "repeated"},
+    {PAPCT_REPEATED_STRETCHED,   N_("Repeated, stretched"),  "repeated_stretched"}
+};
+static const Util::EnumDataConverter<PAPCopyType> PAPCopyTypeConverter(PAPCopyTypeData, PAPCT_END);
+
+LPEPathAlongPath::LPEPathAlongPath(LivePathEffectObject *lpeobject) :
+    Effect(lpeobject),
+    bend_path(_("Bend path"), _("Path along which to bend the original path"), "bendpath", &wr, this, "M0,0 L1,0"),
+/* Delayed until 0.47
+    width_path(_("Width path"), _("..."), "widthpath", &wr, this, "M0,0 L1,0"),
+    width_path_range(_("Width path range"), _("Range of widthpath parameter"), "widthpath_range", &wr, this, 1),
+*/
+    copytype(_("Path copies"), _("How many copies to place along the skeleton path"), "copytype", PAPCopyTypeConverter, &wr, this, PAPCT_SINGLE_STRETCHED),
+    prop_scale(_("Width"), _("Width of the path"), "prop_scale", &wr, this, 1),
+    scale_y_rel(_("Width in units of length"), _("Scale the width of the path in units of its length"), "scale_y_rel", &wr, this, false),
+    vertical_pattern(_("Original path is vertical"), "", "vertical", &wr, this, false)
+{
+    registerParameter( dynamic_cast<Parameter *>(&bend_path) );
+/* Delayed until 0.47
+    registerParameter( dynamic_cast<Parameter *>(&width_path) );
+    registerParameter( dynamic_cast<Parameter *>(&width_path_range) );
+*/
+    registerParameter( dynamic_cast<Parameter *>(&copytype) );
+    registerParameter( dynamic_cast<Parameter *>(&prop_scale) );
+    registerParameter( dynamic_cast<Parameter *>(&scale_y_rel) );
+    registerParameter( dynamic_cast<Parameter *>(&vertical_pattern) );
+
+    prop_scale.param_set_digits(3);
+    prop_scale.param_set_increments(0.01, 0.10);
+}
+
+LPEPathAlongPath::~LPEPathAlongPath()
+{
+
+}
+
+
+Geom::Piecewise<Geom::D2<Geom::SBasis> >
+LPEPathAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > & pwd2_in)
+{
+    using namespace Geom;
+
+/* Much credit should go to jfb and mgsloan of lib2geom development for the code below! */
+
+    PAPCopyType type = copytype.get_value();
+
+    Piecewise<D2<SBasis> > uskeleton = arc_length_parametrization(Piecewise<D2<SBasis> >(bend_path),2,.1);
+    uskeleton = remove_short_cuts(uskeleton,.01);
+    Rect uskeletonbounds = bounds_exact(uskeleton);
+    uskeleton -= uskeletonbounds.midpoint();
+
+    Piecewise<D2<SBasis> > n = rot90(derivative(uskeleton));
+    n = force_continuity(remove_short_cuts(n,.1));
+
+    D2<Piecewise<SBasis> > patternd2 = make_cuts_independant(pwd2_in);
+    Piecewise<SBasis> x = vertical_pattern.get_value() ? Piecewise<SBasis>(patternd2[1]) : Piecewise<SBasis>(patternd2[0]);
+    Piecewise<SBasis> y = vertical_pattern.get_value() ? Piecewise<SBasis>(patternd2[0]) : Piecewise<SBasis>(patternd2[1]);
+    Interval pattBnds = bounds_exact(x);
+    x -= pattBnds.min();
+    Interval pattBndsY = bounds_exact(y);
+    y -= pattBndsY.middle();
+
+    int nbCopies = int(uskeleton.cuts.back()/pattBnds.extent());
+    double scaling = 1;
+
+    switch(type) {
+        case PAPCT_REPEATED:
+            break;
+
+        case PAPCT_SINGLE:
+            nbCopies = (nbCopies > 0) ? 1 : 0;
+            break;
+
+        case PAPCT_SINGLE_STRETCHED:
+            nbCopies = 1;
+            scaling = uskeleton.cuts.back()/pattBnds.extent();
+            break;
+
+        case PAPCT_REPEATED_STRETCHED:
+             scaling = uskeleton.cuts.back()/(((double)nbCopies)*pattBnds.extent());
+            break;
+
+        default:
+            return pwd2_in;
+    };
+
+    double pattWidth = pattBnds.extent() * scaling;
+
+    if (scaling != 1.0) {
+        x*=scaling;
+    }
+    if ( scale_y_rel.get_value() ) {
+        y*=(scaling*prop_scale);
+    } else {
+        if (prop_scale != 1.0) y *= prop_scale;
+    }
+
+/* Delayed until 0.47
+    Piecewise<D2<SBasis> > widthpwd2 = arc_length_parametrization(Piecewise<D2<SBasis> >(width_path),2,.1);
+    D2<Piecewise<SBasis> > widthd2pw = make_cuts_independant(widthpwd2);
+    Piecewise<SBasis> width = (Piecewise<SBasis>(widthd2pw[Y]) - uskeletonbounds[Y].middle()) / width_path_range;
+*/
+
+    double offs = 0;
+    Piecewise<D2<SBasis> > output;
+    for (int i=0; i<nbCopies; i++){
+        output.concat(compose(uskeleton,x+offs) + y*/*compose(width,x+offs)**/compose(n,x+offs));
+        offs+=pattWidth;
+    }
+
+    output += Point(pattBnds.middle(), pattBndsY.middle());
+
+    return output;
+}
+
+void
+LPEPathAlongPath::resetDefaults(SPItem * item)
+{
+    if (!SP_IS_PATH(item)) return;
+
+    using namespace Geom;
+
+    // set the bend path to run horizontally in the middle of the bounding box of the original path
+    Piecewise<D2<SBasis> > pwd2;
+    std::vector<Path> temppath = SVGD_to_2GeomPath( SP_OBJECT_REPR(item)->attribute("inkscape:original-d"));
+    for (unsigned int i=0; i < temppath.size(); i++) {
+        pwd2.concat( temppath[i].toPwSb() );
+    }
+
+    D2<Piecewise<SBasis> > d2pw = make_cuts_independant(pwd2);
+    Interval bndsX = bounds_exact(d2pw[0]);
+    Interval bndsY = bounds_exact(d2pw[1]);
+    Point start(bndsX.min(), (bndsY.max()+bndsY.min())/2);
+    Point end(bndsX.max(), (bndsY.max()+bndsY.min())/2);
+
+    Geom::Path path;
+    path.start( start );
+    path.appendNew<Geom::LineSegment>( end );
+    bend_path.param_set_and_write_new_value( path.toPwSb() );
+
+/* Delayed until 0.47
+    Point startw(bndsX.min(), bndsY.max());
+    Point endw(bndsX.max(), bndsY.max());
+    Geom::Path pathw;
+    pathw.start( startw );
+    pathw.appendNew<Geom::LineSegment>( endw );
+    width_path.param_set_and_write_new_value( pathw.toPwSb() );
+    width_path_range.param_set_value(startw[Y]-start[Y]);
+*/
+}
+
+} // namespace LivePathEffect
+} /* namespace Inkscape */
+
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+  indent-tabs-mode:nil
+  fill-column:99
+  End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
index be064dd044b3d79d3783b646a8572b4a1da360a4..b556efd88fd30f612d33ca351b40f0de4aa144b6 100644 (file)
@@ -1,55 +1,55 @@
-#ifndef INKSCAPE_LPE_PATHALONGPATH_H\r
-#define INKSCAPE_LPE_PATHALONGPATH_H\r
-\r
-/*\r
- * Inkscape::LPEPathAlongPath\r
- *\r
-* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>\r
- *\r
- * Released under GNU GPL, read the file 'COPYING' for more information\r
- */\r
-\r
-#include "live_effects/effect.h"\r
-#include "live_effects/parameter/path.h"\r
-#include "live_effects/parameter/enum.h"\r
-#include "live_effects/parameter/bool.h"\r
-\r
-namespace Inkscape {\r
-namespace LivePathEffect {\r
-\r
-enum PAPCopyType {\r
-    PAPCT_SINGLE = 0,\r
-    PAPCT_SINGLE_STRETCHED,\r
-    PAPCT_REPEATED,\r
-    PAPCT_REPEATED_STRETCHED,\r
-    PAPCT_END // This must be last\r
-};\r
-\r
-class LPEPathAlongPath : public Effect {\r
-public:\r
-    LPEPathAlongPath(LivePathEffectObject *lpeobject);\r
-    virtual ~LPEPathAlongPath();\r
-\r
-    virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > & pwd2_in);\r
-\r
-    virtual void resetDefaults(SPItem * item);\r
-\r
-private:\r
-    PathParam  bend_path;\r
-    //PathParam  width_path;\r
-    //ScalarParam  width_path_range;\r
-    EnumParam<PAPCopyType> copytype;\r
-    ScalarParam  prop_scale;\r
-    BoolParam scale_y_rel;\r
-    BoolParam    vertical_pattern;\r
-\r
-    void on_pattern_pasted();\r
-\r
-    LPEPathAlongPath(const LPEPathAlongPath&);\r
-    LPEPathAlongPath& operator=(const LPEPathAlongPath&);\r
-};\r
-\r
-}; //namespace LivePathEffect\r
-}; //namespace Inkscape\r
-\r
-#endif\r
+#ifndef INKSCAPE_LPE_PATHALONGPATH_H
+#define INKSCAPE_LPE_PATHALONGPATH_H
+
+/*
+ * Inkscape::LPEPathAlongPath
+ *
+* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "live_effects/effect.h"
+#include "live_effects/parameter/path.h"
+#include "live_effects/parameter/enum.h"
+#include "live_effects/parameter/bool.h"
+
+namespace Inkscape {
+namespace LivePathEffect {
+
+enum PAPCopyType {
+    PAPCT_SINGLE = 0,
+    PAPCT_SINGLE_STRETCHED,
+    PAPCT_REPEATED,
+    PAPCT_REPEATED_STRETCHED,
+    PAPCT_END // This must be last
+};
+
+class LPEPathAlongPath : public Effect {
+public:
+    LPEPathAlongPath(LivePathEffectObject *lpeobject);
+    virtual ~LPEPathAlongPath();
+
+    virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > & pwd2_in);
+
+    virtual void resetDefaults(SPItem * item);
+
+private:
+    PathParam  bend_path;
+    //PathParam  width_path;
+    //ScalarParam  width_path_range;
+    EnumParam<PAPCopyType> copytype;
+    ScalarParam  prop_scale;
+    BoolParam scale_y_rel;
+    BoolParam    vertical_pattern;
+
+    void on_pattern_pasted();
+
+    LPEPathAlongPath(const LPEPathAlongPath&);
+    LPEPathAlongPath& operator=(const LPEPathAlongPath&);
+};
+
+}; //namespace LivePathEffect
+}; //namespace Inkscape
+
+#endif