Code

update to 2geom rev. 1168
authorjohanengelen <johanengelen@users.sourceforge.net>
Mon, 12 Nov 2007 19:47:07 +0000 (19:47 +0000)
committerjohanengelen <johanengelen@users.sourceforge.net>
Mon, 12 Nov 2007 19:47:07 +0000 (19:47 +0000)
19 files changed:
src/2geom/basic-intersection.cpp
src/2geom/bezier.h
src/2geom/concepts.h
src/2geom/coord.h
src/2geom/crossing.cpp
src/2geom/crossing.h
src/2geom/d2.h
src/2geom/geom.cpp
src/2geom/geom.h
src/2geom/matrix.cpp
src/2geom/path-intersection.cpp
src/2geom/path.cpp
src/2geom/point.h
src/2geom/sbasis-to-bezier.cpp
src/2geom/sbasis-to-bezier.h
src/2geom/sbasis.h
src/2geom/shape.cpp
src/2geom/sturm.h
src/2geom/utils.h

index 694760d5abcdc9b000f96c8a1fa4954d7434bc1f..0d84ee7f33ed3ce8a5ca8124bba015b3d5264ba5 100644 (file)
@@ -1,5 +1,7 @@
 #include "basic-intersection.h"
 
+unsigned intersect_steps = 0;
+
 using std::vector;
 namespace Geom {
 
@@ -224,6 +226,7 @@ void recursively_intersect( OldBezier a, double t0, double t1, int deptha,
                           OldBezier b, double u0, double u1, int depthb,
                           std::vector<std::pair<double, double> > &parameters)
 {
+    intersect_steps ++;
     if( deptha > 0 )
     {
         OldBezier A[2];
index e0d274e3bec628698423376cacd055a3c627dcb4..16b4d7446d1b942e1df3e827d9b406d2a580b6a7 100644 (file)
@@ -1,4 +1,4 @@
- /*
+/*
  * bezier.h
  *
  * Copyright 2007  MenTaLguY <mental@rydia.net>
index bd020ab6625d9fab3ae7bcc7fe83cc4a120dc47e..92ec66c7f52d7f16d8de826214edc537cc845dd3 100644 (file)
@@ -104,7 +104,7 @@ struct NearConcept {
     double tol;
     bool res;
     void constraints() {
-        res = near(a, b, tol);
+        res = are_near(a, b, tol);
     }
 };
 
index 34a585bf9fe43ac44a799b59b32ce7c974777c66..e9abfc927d84a8d8c5ab06865b8dec14a96cfd31 100644 (file)
@@ -46,19 +46,8 @@ typedef double Coord;
 
 const Coord EPSILON = 1e-5; //1e-18;
 
-
-#ifdef near
-#define lib2geom_near_save near
-#undef near
-#endif
-
 //IMPL: NearConcept
-inline bool near(Coord a, Coord b, double eps=EPSILON) { return fabs(a-b) <= eps; }
-
-#ifdef lib2geom_near_save
-#define near lib2geom_near_save
-#undef lib2geom_near_save
-#endif
+inline bool are_near(Coord a, Coord b, double eps=EPSILON) { return fabs(a-b) <= eps; }
 
 } /* namespace Geom */
 
index 8f29635e82c5095b3fc4230d596752ed2b357eef..a8add187766247c227b775ee87a98a5c2c33f95c 100644 (file)
@@ -1,7 +1,118 @@
 #include "crossing.h"
+#include "path.h"
 
 namespace Geom {
 
+//bool edge_involved_in(Edge const &e, Crossing const &c) {
+//    if(e.path == c.a) {
+//        if(e.time == c.ta) return true;
+//    } else if(e.path == c.b) {
+//        if(e.time == c.tb) return true;
+//    }
+//    return false;
+//}
+
+double wrap_dist(double from, double to, double size, bool rev) {
+    if(rev) {
+        if(to > from) {
+            return from + (size - to);
+        } else {
+            return from - to;
+        }
+    } else {
+        if(to < from) {
+            return to + (size - from);
+        } else {
+            return to - from;
+        }
+    }
+}
+
+CrossingGraph create_crossing_graph(std::vector<Path> const &p, Crossings const &crs) {
+    std::vector<Point> locs;
+    CrossingGraph ret;
+    for(unsigned i = 0; i < crs.size(); i++) {
+        Point pnt = p[crs[i].a].pointAt(crs[i].ta);
+        unsigned j = 0;
+        for(; j < locs.size(); j++) {
+            if(are_near(pnt, locs[j])) break;
+        }
+        if(j == locs.size()) {
+            ret.push_back(CrossingNode());
+            locs.push_back(pnt);
+        }
+        ret[j].add_edge(Edge(crs[i].a, crs[i].ta, false));
+        ret[j].add_edge(Edge(crs[i].a, crs[i].ta, true));
+        ret[j].add_edge(Edge(crs[i].b, crs[i].tb, false));
+        ret[j].add_edge(Edge(crs[i].b, crs[i].tb, true));
+    }
+    
+    for(unsigned i = 0; i < ret.size(); i++) {
+        for(unsigned j = 0; j < ret[i].edges.size(); j++) {
+            unsigned pth = ret[i].edges[j].path;
+            double t = ret[i].edges[j].time;
+            bool rev = ret[i].edges[j].reverse;
+            double size = p[pth].size()+1;
+            double best = size;
+            unsigned bix = ret.size();
+            for(unsigned k = 0; k < ret.size(); k++) {
+                for(unsigned l = 0; l < ret[k].edges.size(); l++) {
+                   if(ret[i].edges[j].path == ret[k].edges[l].path && (k != i || l != j)) {
+                        double d = wrap_dist(t, ret[i].edges[j].time, size, rev);
+                        if(d < best) {
+                            best = d;
+                            bix = k;
+                        }
+                    }
+                }
+            }
+            if(bix == ret.size()) {
+                std::cout << "couldn't find an adequate next-crossing node";
+                bix = i;
+            }
+            ret[i].edges[j].node = bix;
+        }
+    }
+    
+    return ret;
+ /*  Various incoherent code bits   
+    // list of sets of edges, each set corresponding to those emanating from the path
+    CrossingGraph ret;
+    std::vector<Edge> edges(crs.size());
+    
+    std::vector<std::vector<bool> > used;
+    unsigned i, j;
+    do {
+        first_false(used, i, j);
+        CrossingNode cn;
+        do {
+            unsigned di = i, dj = j;
+            crossing_dual(di, dj);
+            if(!used[di,dj]) {
+                
+            }
+        }
+        
+    } while(!used[i,j])
+    
+    
+    for(unsigned j = 0; j < crs[i].size(); j++) {
+        
+        edges.push_back(Edge(i, crs[i][j].getOtherTime(i), false));
+        edges.push_back(Edge(i, crs[i][j].getOtherTime(i), true));
+    }
+    std::sort(edges.begin(), edges.end(), TimeOrder());
+    for(unsigned j = 0; j < edges.size(); ) {
+        CrossingNode cn;
+        double t = edges[j].time;
+        while(j < edges.size() && are_near(edges[j].time, t)) {
+            cn.edges.push_back(edges[j]);
+        }
+    }
+*/
+}
+
 void merge_crossings(Crossings &a, Crossings &b, unsigned i) {
     Crossings n;
     sort_crossings(b, i);
@@ -67,7 +178,7 @@ void clean(Crossings &cr_a, Crossings &cr_b) {
         const Crossing cur = *i;
         Eraser<Crossings> next(i);
         next++;
-        if(near(cur, *next)) {
+        if(are_near(cur, *next)) {
             cr_b.erase(std::find(cr_b.begin(), cr_b.end(), cur));
             for(i = next; near(*i, cur); i++) {
                 cr_b.erase(std::find(cr_b.begin(), cr_b.end(), *i));
index 79912f024dd558b2b376e6316d7d9ad351abd315..8e3a45142b9b86054c4dd06b6606f5985bf02b47 100644 (file)
@@ -2,11 +2,12 @@
 #define __GEOM_CROSSING_H
 
 #include <vector>
-#include <set>
 #include "rect.h"
 #include "sweep.h"
+
 namespace Geom {
 
+//Crossing between one or two paths
 struct Crossing {
     bool dir; //True: along a, a becomes outside.
     double ta, tb;  //time on a and b of crossing
@@ -16,6 +17,7 @@ struct Crossing {
     Crossing(double t_a, double t_b, unsigned ai, unsigned bi, bool direction) : dir(direction), ta(t_a), tb(t_b), a(ai), b(bi) {}
     bool operator==(const Crossing & other) const { return a == other.a && b == other.b && dir == other.dir && ta == other.ta && tb == other.tb; }
     bool operator!=(const Crossing & other) const { return !(*this == other); }
+
     unsigned getOther(unsigned cur) const { return a == cur ? b : a; }
     double getTime(unsigned cur) const { return a == cur ? ta : tb; }
     double getOtherTime(unsigned cur) const { return a == cur ? tb : ta; }
@@ -23,11 +25,48 @@ struct Crossing {
 };
 
 
-/*inline bool near(Crossing a, Crossing b) {
-    return near(a.ta, b.ta) && near(a.tb, b.tb);
+struct Edge {
+    unsigned node, path;
+    double time;
+    bool reverse;
+    Edge(unsigned p, double t, bool r) : path(p), time(t), reverse(r) {}
+    bool operator==(Edge const &other) const { return other.path == path && other.time == time && other.reverse == reverse; }
+};
+
+struct CrossingNode {
+    std::vector<Edge> edges;
+    CrossingNode() : edges(std::vector<Edge>()) {}
+    explicit CrossingNode(std::vector<Edge> es) : edges(es) {}
+    void add_edge(Edge const &e) {
+       if(std::find(edges.begin(), edges.end(), e) == edges.end())
+           edges.push_back(e);
+    }
+    double time_on(unsigned p) {
+       for(unsigned i = 0; i < edges.size(); i++)
+           if(edges[i].path == p) return edges[i].time;
+       std::cout << "CrossingNode time_on failed\n";
+       return 0;
+    }
+};
+
+typedef std::vector<Crossing> Crossings;
+
+typedef std::vector<CrossingNode> CrossingGraph;
+
+struct TimeOrder {
+    bool operator()(Edge a, Edge b) {
+        return a.time < b.time;
+    }
+};
+
+class Path;
+CrossingGraph create_crossing_graph(std::vector<Path> const &p, Crossings const &crs);
+
+/*inline bool are_near(Crossing a, Crossing b) {
+    return are_near(a.ta, b.ta) && are_near(a.tb, b.tb);
 }
 
-struct NearF { bool operator()(Crossing a, Crossing b) { return near(a, b); } };
+struct NearF { bool operator()(Crossing a, Crossing b) { return are_near(a, b); } };
 */
 
 struct CrossingOrder {
@@ -39,7 +78,7 @@ struct CrossingOrder {
     }
 };
 
-typedef std::vector<Crossing> Crossings;
+
 typedef std::vector<Crossings> CrossingSet;
 
 template<typename C>
index 3a9e14bda8739cd614658123f672051534a6c55a..47355eb6028625904bd181a19df8f0e9bb1f59ba 100644 (file)
@@ -130,9 +130,9 @@ operator!=(D2<T> const &a, D2<T> const &b) {
 //IMPL: NearConcept
 template <typename T>
 inline bool
-near(D2<T> const &a, D2<T> const &b, double tol) {
+are_near(D2<T> const &a, D2<T> const &b, double tol) {
     boost::function_requires<NearConcept<T> >();
-    return near(a[0], b[0]) && near(a[1], b[1]);
+    return are_near(a[0], b[0]) && are_near(a[1], b[1]);
 }
 
 //IMPL: AddableConcept
index e93247899f1b6e3ba071e721b1a60f30b1f1a32b..8845cefa89fe443ae321fe022a7ee4be8c22c574 100644 (file)
@@ -10,6 +10,7 @@
 #include "point.h"
 
 namespace Geom {
+
 /**
  * Finds the intersection of the two (infinite) lines
  * defined by the points p such that dot(n0, p) == d0 and dot(n1, p) == d1.
index c24acea63ccb678464f248248364000e78c1d7fe..f25e43c4922e3cec0aee7b13e846db66ec71066c 100644 (file)
@@ -31,8 +31,8 @@
  * the specific language governing rights and limitations.
  *
  */
-#ifndef SEEN_2Geom_GEOM_H
-#define SEEN_2Geom_GEOM_H
+#ifndef LIB2GEOM_SEEN_GEOM_H
+#define LIB2GEOM_SEEN_GEOM_H
 
 //TODO: move somewhere else
 
index c0e64ad33a0525f31b923faa6ef216f4252b8886..a6e3025d9ce2f0be6219f0da974e259de3c9cef7 100644 (file)
@@ -84,7 +84,7 @@ double Matrix::expansionY() const {
 
 void Matrix::setExpansionX(double val) {
     double exp_x = expansionX();
-    if(!near(exp_x, 0.0)) {  //TODO: best way to deal with it is to skip op?
+    if(!are_near(exp_x, 0.0)) {  //TODO: best way to deal with it is to skip op?
         double coef = val / expansionX();
         for(unsigned i=0;i<2;i++) _c[i] *= coef;
     }
@@ -92,7 +92,7 @@ void Matrix::setExpansionX(double val) {
 
 void Matrix::setExpansionY(double val) {
     double exp_y = expansionY();
-    if(!near(exp_y, 0.0)) {  //TODO: best way to deal with it is to skip op?
+    if(!are_near(exp_y, 0.0)) {  //TODO: best way to deal with it is to skip op?
         double coef = val / expansionY();
         for(unsigned i=2; i<4; i++) _c[i] *= coef;
     }
@@ -108,9 +108,9 @@ void Matrix::setIdentity() {
 //TODO: use eps
 
 bool Matrix::isIdentity(Coord const eps) const {
-    return near(_c[0], 1.0) && near(_c[1], 0.0) &&
-           near(_c[2], 0.0) && near(_c[3], 1.0) &&
-           near(_c[4], 0.0) && near(_c[5], 0.0);
+    return are_near(_c[0], 1.0) && are_near(_c[1], 0.0) &&
+           are_near(_c[2], 0.0) && are_near(_c[3], 1.0) &&
+           are_near(_c[4], 0.0) && are_near(_c[5], 0.0);
 }
 
 /** Answers the question "Does this matrix perform a translation, and \em{only} a translation?"
@@ -118,9 +118,9 @@ bool Matrix::isIdentity(Coord const eps) const {
  \return A bool representing yes/no.
  */
 bool Matrix::isTranslation(Coord const eps) const {
-    return near(_c[0], 1.0) && near(_c[1], 0.0) &&
-           near(_c[2], 0.0) && near(_c[3], 1.0) &&
-           !near(_c[4], 0.0) && !near(_c[5], 0.0);
+    return are_near(_c[0], 1.0) && are_near(_c[1], 0.0) &&
+           are_near(_c[2], 0.0) && are_near(_c[3], 1.0) &&
+           !are_near(_c[4], 0.0) && !are_near(_c[5], 0.0);
 }
 
 /** Answers the question "Does this matrix perform a scale, and \em{only} a Scale?"
@@ -128,9 +128,9 @@ bool Matrix::isTranslation(Coord const eps) const {
  \return A bool representing yes/no.
  */
 bool Matrix::isScale(Coord const eps) const {
-    return !near(_c[0], 1.0) || !near(_c[3], 1.0) &&  //NOTE: these are the diags, and the next line opposite diags
-           near(_c[1], 0.0) && near(_c[2], 0.0) && 
-           near(_c[4], 0.0) && near(_c[5], 0.0);
+    return !are_near(_c[0], 1.0) || !are_near(_c[3], 1.0) &&  //NOTE: these are the diags, and the next line opposite diags
+           are_near(_c[1], 0.0) && are_near(_c[2], 0.0) && 
+           are_near(_c[4], 0.0) && are_near(_c[5], 0.0);
 }
 
 /** Answers the question "Does this matrix perform a uniform scale, and \em{only} a uniform scale?"
@@ -138,9 +138,9 @@ bool Matrix::isScale(Coord const eps) const {
  \return A bool representing yes/no.
  */
 bool Matrix::isUniformScale(Coord const eps) const {
-    return !near(_c[0], 1.0) && near(_c[0], _c[3]) &&
-           near(_c[1], 0.0) && near(_c[2], 0.0) &&  
-           near(_c[4], 0.0) && near(_c[5], 0.0);
+    return !are_near(_c[0], 1.0) && are_near(_c[0], _c[3]) &&
+           are_near(_c[1], 0.0) && are_near(_c[2], 0.0) &&  
+           are_near(_c[4], 0.0) && are_near(_c[5], 0.0);
 }
 
 /** Answers the question "Does this matrix perform a rotation, and \em{only} a rotation?"
@@ -148,13 +148,13 @@ bool Matrix::isUniformScale(Coord const eps) const {
  \return A bool representing yes/no.
  */
 bool Matrix::isRotation(Coord const eps) const {
-    return !near(_c[0], _c[3]) && near(_c[1], -_c[2]) &&
-           near(_c[4], 0.0) && near(_c[5], 0.0) &&
-           near(_c[0]*_c[0] + _c[1]*_c[1], 1.0);
+    return !are_near(_c[0], _c[3]) && are_near(_c[1], -_c[2]) &&
+           are_near(_c[4], 0.0) && are_near(_c[5], 0.0) &&
+           are_near(_c[0]*_c[0] + _c[1]*_c[1], 1.0);
 }
 
 bool Matrix::onlyScaleAndTranslation(Coord const eps) const {
-    return near(_c[0], _c[3]) && near(_c[1], 0) && near(_c[2], 0);
+    return are_near(_c[0], _c[3]) && are_near(_c[1], 0) && are_near(_c[2], 0);
 }
 
 bool Matrix::flips() const {
@@ -175,7 +175,7 @@ Matrix Matrix::inverse() const {
     Matrix d;
 
     Geom::Coord const determ = det();
-    if (!near(determ, 0.0)) {
+    if (!are_near(determ, 0.0)) {
         Geom::Coord const ideterm = 1.0 / determ;
 
         d._c[0] =  _c[3] * ideterm;
index 2ad78e42f87a39465fb4719e27acd517ee725a6e..9a4d65f72ada2b67cb91a107ac806239b6dd5a5f 100644 (file)
@@ -25,7 +25,7 @@ int winding(Path const &path, Point p) {
     if(iter->boundsFast().height()!=0.){ start = iter; break; }
   }
   int wind = 0;
-  int cnt = 0;
+  unsigned cnt = 0;
   bool starting = true;
   for (Path::const_iterator iter = start; iter != start || starting
        ; ++iter, iter = (iter == path.end_closed()) ? path.begin() : iter )
index 79dc0a5f4765faa4d25038ada4f0746b87a94fae..98fec6e24555c3cd9f2fc632c7a9b13984ba7a54 100644 (file)
@@ -144,7 +144,7 @@ void Path::appendPortionTo(Path &ret, double from, double to) const {
 const double eps = .1;
 
 void Path::append(Curve const &curve) {
-  if ( curves_.front() != final_ && !near(curve.initialPoint(), (*final_)[0], eps) ) {
+  if ( curves_.front() != final_ && !are_near(curve.initialPoint(), (*final_)[0], eps) ) {
     throw ContinuityError();
   }
   do_append(curve.duplicate());
@@ -153,7 +153,7 @@ void Path::append(Curve const &curve) {
 void Path::append(D2<SBasis> const &curve) {
   if ( curves_.front() != final_ ) {
     for ( int i = 0 ; i < 2 ; ++i ) {
-      if ( !near(curve[i][0][0], (*final_)[0][i], eps) ) {
+      if ( !are_near(curve[i][0][0], (*final_)[0][i], eps) ) {
         throw ContinuityError();
       }
     }
@@ -205,17 +205,17 @@ void Path::check_continuity(Sequence::iterator first_replaced,
 {
   if ( first != last ) {
     if ( first_replaced != curves_.begin() ) {
-      if ( !near( (*first_replaced)->initialPoint(), (*first)->initialPoint(), eps ) ) {
+      if ( !are_near( (*first_replaced)->initialPoint(), (*first)->initialPoint(), eps ) ) {
         throw ContinuityError();
       }
     }
     if ( last_replaced != (curves_.end()-1) ) {
-      if ( !near( (*(last_replaced-1))->finalPoint(), (*(last-1))->finalPoint(), eps ) ) {
+      if ( !are_near( (*(last_replaced-1))->finalPoint(), (*(last-1))->finalPoint(), eps ) ) {
         throw ContinuityError();
       }
     }
   } else if ( first_replaced != last_replaced && first_replaced != curves_.begin() && last_replaced != curves_.end()-1) {
-    if ( !near((*first_replaced)->initialPoint(), (*(last_replaced-1))->finalPoint(), eps ) ) {
+    if ( !are_near((*first_replaced)->initialPoint(), (*(last_replaced-1))->finalPoint(), eps ) ) {
       throw ContinuityError();
     }
   }
index bf7dc444f3b80355b8b454b2e10cff0d01c9b103..91df159cad90f5364b3cdda88e8cbdaac5c5ee95 100644 (file)
@@ -174,22 +174,11 @@ extern double atan2(Point const p);
 /** compute the angle turning from a to b (signed). */
 extern double angle_between(Point const a, Point const b);
 
-
-#ifdef near
-#define lib2geom_near_save near
-#undef near
-#endif
-
 //IMPL: NearConcept
-inline bool near(Point const &a, Point const &b, double const eps=EPSILON) {
-    return ( near(a[X],b[X],eps) && near(a[Y],b[Y],eps) );
+inline bool are_near(Point const &a, Point const &b, double const eps=EPSILON) {
+    return ( are_near(a[X],b[X],eps) && are_near(a[Y],b[Y],eps) );
 }
 
-#ifdef lib2geom_near_save
-#define near lib2geom_near_save
-#undef lib2geom_near_save
-#endif
-
 /** Returns p * Geom::rotate_degrees(90), but more efficient.
  *
  * Angle direction in Inkscape code: If you use the traditional mathematics convention that y
index 2484af18d94e6026ab42e0b37b9165a0d0934230..7283dd87d3ee02638aad0aba7db46db99fd562e2 100644 (file)
@@ -54,6 +54,28 @@ sbasis_to_bezier(SBasis const &B, unsigned q) {
     return result;
 }
 
+double mopi(int i) {
+    return (i&1)?-1:1;
+}
+
+// this produces a degree k sbasis from a degree 2q bezier
+SBasis
+bezier_to_sbasis(Bezier const &B) {
+    unsigned n = B.size();
+    unsigned q = (n+1)/2;
+    SBasis result;
+    result.resize(q+1);
+    for(unsigned k = 0; k < q; k++) {
+        result[k][0] = result[k][1] = 0;
+        for(unsigned j = 0; j <= n-k; j++) {
+            result[k][0] += mopi(int(j)-int(k))*W(n, j, k)*B[j];
+            result[k][1] += mopi(int(j)-int(k))*W(n, j, k)*B[j];
+            //W(n, n-j, k)*B[k][1]);
+        }
+    }
+    return result;
+}
+
 // this produces a 2q point bezier from a degree q sbasis
 std::vector<Geom::Point>
 sbasis_to_bezier(D2<SBasis> const &B, unsigned qq) {
@@ -188,9 +210,9 @@ path_from_piecewise(Geom::Piecewise<Geom::D2<Geom::SBasis> > const &B, double to
     Geom::Point start = B[0].at0();
     pb.moveTo(start);
     for(unsigned i = 0; ; i++) {
-        if(i+1 == B.size() || !near(B[i+1].at0(), B[i].at1(), tol)) {
+        if(i+1 == B.size() || !are_near(B[i+1].at0(), B[i].at1(), tol)) {
             //start of a new path
-            if(near(start, B[i].at1())) {
+            if(are_near(start, B[i].at1())) {
                 //it's closed
                 pb.closePath();
                 if(sbasis_size(B[i]) <= 1) {
index e566d71561a37b8f5529af98b21c145a2737006b..2c49464f60325b9c342445591c18585bf31ac0cf 100644 (file)
@@ -9,6 +9,10 @@ namespace Geom{
 Bezier
 sbasis_to_bezier(SBasis const &B, unsigned q = 0);
 
+// inverse
+SBasis bezier_to_sbasis(Bezier const &B);
+
+
 std::vector<Geom::Point>
 sbasis_to_bezier(D2<SBasis> const &B, unsigned q = 0);
 
index 118cf2c561731ca3c4f485649c7b916c8256002a..9fc16f1c6caa639da53cebeda6fd750ec245beb9 100644 (file)
@@ -86,6 +86,20 @@ public:
         }
         return (1-t)*p0 + t*p1;
     }
+    double valueAndDerivative(double t, double &der) const {
+        double s = t*(1-t);
+        double p0 = 0, p1 = 0;
+        double sk = 1;
+//TODO: rewrite as horner
+        for(unsigned k = 0; k < size(); k++) {
+            p0 += sk*(*this)[k][0];
+            p1 += sk*(*this)[k][1];
+            sk *= s;
+        }
+        // p0 and p1 at this point form a linear approximation at t
+        der = p1 - p0;
+        return (1-t)*p0 + t*p1;
+    }
     double operator()(double t) const {
         return valueAt(t);
     }
index 54218d4d99171e3ebe704681bb177feeec5e5bba..3cf6d0bc0ddab00c1e03737bcd886b2bbb7d4462 100644 (file)
@@ -296,7 +296,7 @@ unsigned pick_coincident(unsigned ix, unsigned jx, bool &rev, std::vector<Path>
     for(unsigned k = jx; k < crs[ix].size(); k++) {
         unsigned koix = crs[ix][k].getOther(ix);
         if(koix == oix) {
-            if(!near(otime, crs[ix][k].getTime(oix))) break;
+            if(!are_near(otime, crs[ix][k].getTime(oix))) break;
             for(unsigned dir = 0; dir < 2; dir++) {
                 Point val = ps[ix].pointAt(fudgerize(crs[ix][k].getTime(ix), dir)) - cross_point;
                 Cmp to_prev = cmp(cross(val, prev), 0);
@@ -470,7 +470,7 @@ unsigned pick_coincident(unsigned ix, unsigned jx, bool pref, bool &rev, std::ve
     for(unsigned k = jx; k < crs[ix].size(); k++) {
         unsigned koix = crs[ix][k].getOther(ix);
         if(koix == oix) {
-            if(!near(otime, crs[ix][k].getTime(oix))) break;
+            if(!are_near(otime, crs[ix][k].getTime(oix))) break;
             for(unsigned dir = 0; dir < 2; dir++) {
                 Point val = ps[ix].pointAt(crs[ix][k].getTime(ix) + (dir ? -0.01 : 0.01)) - cross_point;
                 Cmp to_prev = cmp(cross(val, prev), 0);
index 4a9fcc6e2d4a292512bf168351fab93d5a616b6c..9937a6f1517ece1bbfead5d1d58037e50327b36b 100644 (file)
@@ -1,6 +1,11 @@
+#ifndef LIB2GEOM_STURM_HEADER
+#define LIB2GEOM_STURM_HEADER
+
 #include "poly.h"
 #include "utils.h"
 
+namespace Geom {
+
 class sturm : public std::vector<Poly>{
 public:
     sturm(Poly const &X) {
@@ -50,6 +55,9 @@ public:
     }
 };
 
+} //namespace Geom
+
+#endif
 /*
   Local Variables:
   mode:c++
index a96a34dff30de2724eaa0d463174662b40fe56fd..50dfa82fe5ac68c0c5a54ca6b16d4eeb24588028 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef UTILS_HEADER
-#define UTILS_HEADER
+#ifndef LIB2GEOM_UTILS_HEADER
+#define LIB2GEOM_UTILS_HEADER
 
 /** Various utility functions.
  *
@@ -40,6 +40,11 @@ public:
   NotImplemented() : std::logic_error("method not implemented") {}
 };
 
+class NotInvertible : public std::range_error {
+ public:
+  NotInvertible() : std::range_error("function does not have a unique inverse") {}
+};
+
 // proper logical xor
 inline bool logical_xor (bool a, bool b) { return (a || b) && !(a && b); }