Code

implemented new classes for horizontal and vertical line segments; path.h has been...
authormcecchetti <mcecchetti@users.sourceforge.net>
Mon, 26 May 2008 22:32:02 +0000 (22:32 +0000)
committermcecchetti <mcecchetti@users.sourceforge.net>
Mon, 26 May 2008 22:32:02 +0000 (22:32 +0000)
13 files changed:
src/2geom/CMakeLists.txt
src/2geom/Makefile_insert
src/2geom/bezier-curve.h [new file with mode: 0644]
src/2geom/curve-helpers.cpp [new file with mode: 0644]
src/2geom/curve.h [new file with mode: 0644]
src/2geom/curves.h [new file with mode: 0644]
src/2geom/elliptical-arc.cpp
src/2geom/elliptical-arc.h [new file with mode: 0644]
src/2geom/forward.h
src/2geom/hvlinesegment.h [new file with mode: 0644]
src/2geom/path.cpp
src/2geom/path.h
src/2geom/sbasis-curve.h [new file with mode: 0644]

index ac019419ddd93c152d4dc6a09ccd64e9fe261677..fc741fb4731398532a7f0f589f05bfefc913b9e2 100644 (file)
@@ -3,6 +3,7 @@ angle.h
 basic-intersection.cpp
 basic-intersection.h
 bezier.h
+bezier-curve.h
 bezier-to-sbasis.h
 bezier-utils.cpp
 bezier-utils.h
@@ -17,14 +18,19 @@ convex-cover.h
 coord.h
 crossing.cpp
 crossing.h
+curve.h
+curves.h
+curve-helpers.cpp
 d2.h
 d2-sbasis.cpp
 d2-sbasis.h
 elliptical-arc.cpp
+elliptical-arc.h
 exception.h
 forward.h
 geom.cpp
 geom.h
+hvlinesegment.h
 interval.h
 isnan.h
 linear.h
@@ -60,6 +66,7 @@ region.h
 sbasis-2d.cpp
 sbasis-2d.h
 sbasis.cpp
+sbasis-curve.h
 sbasis-geometric.cpp
 sbasis-geometric.h
 sbasis.h
index e2c0d6aa37fd4a54bb4d6dbfab40bcb2a4977137..c45dd806d2f003b2057fabd7f12a56a688cef4c4 100644 (file)
@@ -8,6 +8,7 @@
 2geom_lib2geom_a_SOURCES = \\r
        2geom/basic-intersection.cpp    \\r
        2geom/basic-intersection.h      \\r
+       2geom/bezier-curve.h    \\r
        2geom/bezier-to-sbasis.h        \\r
        2geom/bezier-utils.cpp  \\r
        2geom/bezier-utils.h    \\r
        2geom/coord.h   \\r
        2geom/crossing.cpp      \\r
        2geom/crossing.h        \\r
+       2geom/curve.h   \\r
+       2geom/curves.h  \\r
+       2geom/curve-helpers.cpp \\r
        2geom/d2-sbasis.cpp     \\r
        2geom/d2-sbasis.h       \\r
        2geom/d2.h      \\r
        2geom/exception.h       \\r
        2geom/elliptical-arc.cpp   \\r
+       2geom/elliptical-arc.h  \\r
        2geom/forward.h \\r
        2geom/geom.cpp  \\r
        2geom/geom.h    \\r
+       2geom/hvlinesegment.h   \\r
        2geom/interval.h        \\r
        2geom/isnan.h   \\r
        2geom/linear.h  \\r
@@ -67,6 +73,7 @@
        2geom/region.h  \\r
        2geom/sbasis-2d.cpp     \\r
        2geom/sbasis-2d.h       \\r
+       2geom/sbasis-curve.h    \\r
        2geom/sbasis-geometric.cpp      \\r
        2geom/sbasis-geometric.h        \\r
        2geom/sbasis-math.cpp   \\r
diff --git a/src/2geom/bezier-curve.h b/src/2geom/bezier-curve.h
new file mode 100644 (file)
index 0000000..ceab3cc
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Bezier-Curve
+ *
+ * Authors:
+ *             MenTaLguY <mental@rydia.net>
+ *             Marco Cecchetti <mrcekets at gmail.com>
+ * 
+ * Copyright 2007-2008  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.
+ */
+
+
+
+
+#ifndef _2GEOM_BEZIER_CURVE_H_
+#define _2GEOM_BEZIER_CURVE_H_
+
+
+#include "curve.h"
+#include "sbasis-curve.h" // for non-native winding method
+#include "bezier.h"
+
+#include <algorithm>
+
+
+namespace Geom 
+{
+
+
+
+template <unsigned order>
+class BezierCurve : public Curve {
+       
+private:
+  D2<Bezier > inner;
+  
+public:
+  template <unsigned required_degree>
+  static void assert_degree(BezierCurve<required_degree> const *) {}
+
+  BezierCurve() : inner(Bezier::Order(order), Bezier::Order(order)) {
+  }
+
+  explicit BezierCurve(D2<Bezier > const &x) : inner(x) {}
+
+  BezierCurve(Bezier x, Bezier y) : inner(x, y) {}
+
+  // default copy
+  // default assign
+
+  BezierCurve(Point c0, Point c1) {
+    assert_degree<1>(this);
+    for(unsigned d = 0; d < 2; d++)
+        inner[d] = Bezier(c0[d], c1[d]);
+  }
+
+  BezierCurve(Point c0, Point c1, Point c2) {
+    assert_degree<2>(this);
+    for(unsigned d = 0; d < 2; d++)
+        inner[d] = Bezier(c0[d], c1[d], c2[d]);
+  }
+
+  BezierCurve(Point c0, Point c1, Point c2, Point c3) {
+    assert_degree<3>(this);
+    for(unsigned d = 0; d < 2; d++)
+        inner[d] = Bezier(c0[d], c1[d], c2[d], c3[d]);
+  }
+
+  unsigned degree() const { return order; }
+
+  Curve *duplicate() const { return new BezierCurve(*this); }
+
+  Point initialPoint() const { return inner.at0(); }
+  Point finalPoint() const { return inner.at1(); }
+
+  bool isDegenerate() const { return inner.isConstant(); }
+
+  void setInitial(Point v) { setPoint(0, v); }
+  void setFinal(Point v)   { setPoint(order, v); }
+
+  void setPoint(unsigned ix, Point v) { inner[X].setPoint(ix, v[X]); inner[Y].setPoint(ix, v[Y]); }
+  Point const operator[](unsigned ix) const { return Point(inner[X][ix], inner[Y][ix]); }
+
+  Rect boundsFast() const { return bounds_fast(inner); }
+  Rect boundsExact() const { return bounds_exact(inner); }
+  Rect boundsLocal(Interval i, unsigned deg) const {
+      if(i.min() == 0 && i.max() == 1) return boundsFast();
+      if(deg == 0) return bounds_local(inner, i);
+      // TODO: UUUUUUGGGLLY
+      if(deg == 1 && order > 1) return Rect(bounds_local(Geom::derivative(inner[X]), i),
+                                            bounds_local(Geom::derivative(inner[Y]), i));
+      return Rect(Interval(0,0), Interval(0,0));
+  }
+//TODO: local
+
+//TODO: implement next 3 natively
+  int winding(Point p) const {
+    return SBasisCurve(toSBasis()).winding(p);
+  }
+
+  std::vector<double>
+  roots(double v, Dim2 d) const {
+      return (inner[d] - v).roots();
+  }
+  
+  double nearestPoint( Point const& p, double from = 0, double to = 1 ) const
+  {
+         return Curve::nearestPoint(p, from, to);
+  }
+  
+  void setPoints(std::vector<Point> ps) {
+    for(unsigned i = 0; i <= order; i++) {
+      setPoint(i, ps[i]);
+    }
+  }
+  std::vector<Point> points() const { return bezier_points(inner); }
+
+  std::pair<BezierCurve<order>, BezierCurve<order> > subdivide(Coord t) const {
+    std::pair<Bezier, Bezier > sx = inner[X].subdivide(t), sy = inner[Y].subdivide(t);
+    return std::pair<BezierCurve<order>, BezierCurve<order> >(
+               BezierCurve<order>(sx.first, sy.first),
+               BezierCurve<order>(sx.second, sy.second));
+  }
+
+  Curve *portion(double f, double t) const {
+    return new BezierCurve(Geom::portion(inner, f, t));
+  }
+
+  Curve *reverse() const {
+    return new BezierCurve(Geom::reverse(inner));
+  }
+
+  Curve *transformed(Matrix const &m) const {
+    BezierCurve *ret = new BezierCurve();
+    std::vector<Point> ps = points();
+    for(unsigned i = 0;  i <= order; i++) ps[i] = ps[i] * m;
+    ret->setPoints(ps);
+    return ret;
+  }
+
+  Curve *derivative() const {
+     if(order > 1)
+        return new BezierCurve<order-1>(Geom::derivative(inner[X]), Geom::derivative(inner[Y]));
+     else if (order == 1) {
+        double dx = inner[X][1] - inner[X][0], dy = inner[Y][1] - inner[Y][0];
+        return new BezierCurve<1>(Point(dx,dy),Point(dx,dy));
+     }
+  }
+
+  Point pointAt(double t) const { return inner.valueAt(t); }
+  std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const { return inner.valueAndDerivatives(t, n); }
+
+  double valueAt(double t, Dim2 d) const { return inner[d].valueAt(t); }
+
+  D2<SBasis> toSBasis() const {return inner.toSBasis(); }
+
+protected:
+  BezierCurve(Point c[]) {
+    Coord x[order+1], y[order+1];
+    for(unsigned i = 0; i <= order; i++) {
+        x[i] = c[i][X]; y[i] = c[i][Y];
+    }
+    inner = Bezier(x, y);
+  }
+};
+
+// BezierCurve<0> is meaningless; specialize it out
+template<> class BezierCurve<0> : public BezierCurve<1> { public: BezierCurve(); BezierCurve(Bezier x, Bezier y); };
+
+typedef BezierCurve<1> LineSegment;
+typedef BezierCurve<2> QuadraticBezier;
+typedef BezierCurve<3> CubicBezier;
+
+
+template<>
+inline
+double LineSegment::nearestPoint(Point const& p, double from, double to) const
+{
+       if ( from > to ) std::swap(from, to);
+       Point ip = pointAt(from);
+       Point fp = pointAt(to);
+       Point v = fp - ip;
+       double t = dot( p - ip, v ) / L2sq(v);
+       if ( t <= 0 )           return from;
+       else if ( t >= 1 )  return to;
+       else                            return from + t*(to-from);
+}
+
+inline
+Point middle_point(LineSegment const& _segment)
+{
+       return ( _segment.initialPoint() + _segment.finalPoint() ) / 2;
+}
+
+inline
+double length(LineSegment const& _segment)
+{
+       return distance(_segment.initialPoint(), _segment.finalPoint());
+}
+
+} // end namespace Geom
+
+
+#endif // _2GEOM_BEZIER_CURVE_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 :
diff --git a/src/2geom/curve-helpers.cpp b/src/2geom/curve-helpers.cpp
new file mode 100644 (file)
index 0000000..c0e46bc
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 
+ * Authors:
+ *             MenTaLguY <mental@rydia.net>
+ *             Marco Cecchetti <mrcekets at gmail.com>
+ * 
+ * Copyright 2007-2008  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 "curve.h"
+#include "ord.h"
+
+
+namespace Geom 
+{
+
+int CurveHelpers::root_winding(Curve const &c, Point p) {
+    std::vector<double> ts = c.roots(p[Y], Y);
+
+    if(ts.empty()) return 0;
+
+    double const fudge = 0.01; //fudge factor used on first and last
+
+    std::sort(ts.begin(), ts.end());
+
+    // winding determined by crossings at roots
+    int wind=0;
+    // previous time
+    double pt = ts.front() - fudge;
+    for ( std::vector<double>::iterator ti = ts.begin()
+        ; ti != ts.end()
+        ; ++ti )
+    {
+        double t = *ti;
+        if ( t <= 0. || t >= 1. ) continue; //skip endpoint roots 
+        if ( c.valueAt(t, X) > p[X] ) { // root is ray intersection
+            // Get t of next:
+            std::vector<double>::iterator next = ti;
+            next++;
+            double nt;
+            if(next == ts.end()) nt = t + fudge; else nt = *next;
+            
+            // Check before in time and after in time for positions
+            // Currently we're using the average times between next and previous segs
+            Cmp after_to_ray =  cmp(c.valueAt((t + nt) / 2, Y), p[Y]);
+            Cmp before_to_ray = cmp(c.valueAt((t + pt) / 2, Y), p[Y]);
+            // if y is included, these will have opposite values, giving order.
+            Cmp dt = cmp(after_to_ray, before_to_ray);
+            if(dt != EQUAL_TO) //Should always be true, but yah never know..
+                wind += dt;
+            pt = t;
+        }
+    }
+    
+    return wind;
+}
+
+
+}  // end namespace Geom
+
+/*
+  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 :
diff --git a/src/2geom/curve.h b/src/2geom/curve.h
new file mode 100644 (file)
index 0000000..b76c0d3
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Abstract Curve Type
+ *
+ * Authors:
+ *             MenTaLguY <mental@rydia.net>
+ *             Marco Cecchetti <mrcekets at gmail.com>
+ * 
+ * Copyright 2007-2008  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.
+ */
+
+
+
+
+#ifndef _2GEOM_CURVE_H_
+#define _2GEOM_CURVE_H_
+
+
+#include "coord.h"
+#include "point.h"
+#include "interval.h"
+#include "nearest-point.h"
+#include "sbasis.h"
+#include "d2.h"
+#include "matrix.h"
+#include "exception.h"
+
+#include <vector>
+
+
+namespace Geom 
+{
+
+class Curve;
+
+struct CurveHelpers {
+protected:
+  static int root_winding(Curve const &c, Point p);
+};
+
+class Curve : private CurveHelpers {
+public:
+  virtual ~Curve() {}
+
+  virtual Point initialPoint() const = 0;
+  virtual Point finalPoint() const = 0;
+
+  virtual bool isDegenerate() const = 0;
+
+  virtual Curve *duplicate() const = 0;
+
+  virtual Rect boundsFast() const = 0;
+  virtual Rect boundsExact() const = 0;
+  virtual Rect boundsLocal(Interval i, unsigned deg) const = 0;
+  Rect boundsLocal(Interval i) const { return boundsLocal(i, 0); }
+
+  virtual std::vector<double> roots(double v, Dim2 d) const = 0;
+
+  virtual int winding(Point p) const { return root_winding(*this, p); }
+
+  //mental: review these
+  virtual Curve *portion(double f, double t) const = 0;
+  virtual Curve *reverse() const { return portion(1, 0); }
+  virtual Curve *derivative() const = 0;
+
+  virtual void setInitial(Point v) = 0;
+  virtual void setFinal(Point v) = 0;
+  
+  virtual
+  double nearestPoint( Point const& p, double from = 0, double to = 1 ) const
+  {
+         return nearest_point(p, toSBasis(), from, to);
+  }
+  
+  virtual
+  std::vector<double> 
+  allNearestPoints( Point const& p, double from = 0, double to = 1 ) const
+  {
+         return all_nearest_points(p, toSBasis(), from, to);
+  }
+
+  virtual Curve *transformed(Matrix const &m) const = 0;
+
+  virtual Point pointAt(Coord t) const { return pointAndDerivatives(t, 1).front(); }
+  virtual Coord valueAt(Coord t, Dim2 d) const { return pointAt(t)[d]; }
+  virtual std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const = 0;
+  virtual D2<SBasis> toSBasis() const = 0;
+};
+
+
+} // end namespace Geom
+
+
+#endif // _2GEOM_CURVE_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 :
diff --git a/src/2geom/curves.h b/src/2geom/curves.h
new file mode 100644 (file)
index 0000000..a406593
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * this file is only a helper header to include all curve types at once
+ *
+ * Authors:
+ *             MenTaLguY <mental@rydia.net>
+ *             Marco Cecchetti <mrcekets at gmail.com>
+ * 
+ * Copyright 2007-2008  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.
+ */
+
+
+
+
+#ifndef _2GEOM_CURVES_H_
+#define _2GEOM_CURVES_H_
+
+
+#include "curve.h"
+#include "sbasis-curve.h"
+#include "bezier-curve.h"
+#include "hvlinesegment.h"
+#include "elliptical-arc.h"
+
+
+#endif // _2GEOM_CURVES_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 b4a882f093a6eb64ade3da8b838f2ba10370f908..55b23961b269d764ad61f5da493ead7cdcea4e60 100644 (file)
@@ -28,9 +28,8 @@
  */
 
 
-#include "path.h"
-#include "angle.h"
-
+#include "elliptical-arc.h"
+#include "bezier-curve.h"
 #include "poly.h"
 
 #include <cfloat>
diff --git a/src/2geom/elliptical-arc.h b/src/2geom/elliptical-arc.h
new file mode 100644 (file)
index 0000000..f3d4f49
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * Elliptical Arc - implementation of the svg elliptical arc path element
+ *
+ * Authors:
+ *             MenTaLguY <mental@rydia.net>
+ *             Marco Cecchetti <mrcekets at gmail.com>
+ * 
+ * Copyright 2007-2008  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.
+ */
+
+
+
+
+#ifndef _2GEOM_ELLIPTICAL_ARC_H_
+#define _2GEOM_ELLIPTICAL_ARC_H_
+
+
+#include "curve.h"
+#include "angle.h"
+#include "utils.h"
+#include "sbasis-curve.h"  // for non-native methods
+
+#include <algorithm>
+
+
+namespace Geom 
+{
+
+class EllipticalArc : public Curve
+{
+  public:
+       EllipticalArc()
+               : m_initial_point(Point(0,0)), m_final_point(Point(0,0)),
+                 m_rx(0), m_ry(0), m_rot_angle(0),
+                 m_large_arc(true), m_sweep(true)
+       {
+               m_start_angle = m_end_angle = 0;
+               m_center = Point(0,0);
+       }
+       
+    EllipticalArc( Point _initial_point, double _rx, double _ry,
+                   double _rot_angle, bool _large_arc, bool _sweep,
+                   Point _final_point
+                  )
+        : m_initial_point(_initial_point), m_final_point(_final_point),
+          m_rx(_rx), m_ry(_ry), m_rot_angle(_rot_angle),
+          m_large_arc(_large_arc), m_sweep(_sweep)
+    {
+            calculate_center_and_extreme_angles();
+    }
+         
+    void set( Point _initial_point, double _rx, double _ry,
+              double _rot_angle, bool _large_arc, bool _sweep,
+              Point _final_point
+             )
+    {
+       m_initial_point = _initial_point;
+       m_final_point = _final_point;
+       m_rx = _rx;
+       m_ry = _ry;
+       m_rot_angle = _rot_angle;
+       m_large_arc = _large_arc;
+       m_sweep = _sweep;
+       calculate_center_and_extreme_angles();
+    }
+
+       Curve* duplicate() const
+       {
+               return new EllipticalArc(*this);
+       }
+       
+    double center(unsigned int i) const
+    {
+        return m_center[i];
+    }
+
+    Point center() const
+    {
+        return m_center;
+    }
+
+    Point initialPoint() const
+    {
+        return m_initial_point;
+    }
+
+    Point finalPoint() const
+    {
+        return m_final_point;
+    }
+
+    double start_angle() const
+    {
+        return m_start_angle;
+    }
+
+    double end_angle() const
+    {
+        return m_end_angle;
+    }
+
+    double ray(unsigned int i) const
+    {
+        return (i == 0) ? m_rx : m_ry;
+    }
+
+    bool large_arc_flag() const
+    {
+        return m_large_arc;
+    }
+
+    bool sweep_flag() const
+    {
+        return m_sweep;
+    }
+
+    double rotation_angle() const
+    {
+        return m_rot_angle;
+    }
+
+    void setInitial( const Point _point)
+    {
+        m_initial_point = _point;
+        calculate_center_and_extreme_angles();
+    }
+
+    void setFinal( const Point _point)
+    {
+        m_final_point = _point;
+        calculate_center_and_extreme_angles();
+    }
+
+    void setExtremes( const Point& _initial_point, const Point& _final_point )
+    {
+        m_initial_point = _initial_point;
+        m_final_point = _final_point;
+        calculate_center_and_extreme_angles();
+    }
+
+    bool isDegenerate() const
+    {
+        return ( are_near(ray(X), 0) || are_near(ray(Y), 0) );
+    }
+    
+    // TODO: native implementation of the following methods
+    Rect boundsFast() const
+    {
+       return boundsExact();
+    }
+  
+    Rect boundsExact() const;
+    
+    Rect boundsLocal(Interval i, unsigned int deg) const
+    {
+       return SBasisCurve(toSBasis()).boundsLocal(i, deg);
+    }
+    
+    std::vector<double> roots(double v, Dim2 d) const;
+    
+    std::vector<double> 
+    allNearestPoints( Point const& p, double from = 0, double to = 1 ) const;
+    
+    double nearestPoint( Point const& p, double from = 0, double to = 1 ) const
+    {
+       if ( are_near(ray(X), ray(Y)) && are_near(center(), p) )
+       {
+               return from;
+       }
+       return allNearestPoints(p, from, to).front();
+    }
+    
+    int winding(Point p) const
+    {
+       return SBasisCurve(toSBasis()).winding(p);
+    }
+    
+    Curve *derivative() const;
+    
+    Curve *transformed(Matrix const &m) const
+    {
+       return SBasisCurve(toSBasis()).transformed(m);
+    }
+    
+    std::vector<Point> pointAndDerivatives(Coord t, unsigned int n) const;
+    
+    D2<SBasis> toSBasis() const;
+    
+    bool containsAngle(Coord angle) const;
+    
+    double valueAtAngle(Coord t, Dim2 d) const;
+    
+    Point pointAtAngle(Coord t) const
+    {
+        double sin_rot_angle = std::sin(rotation_angle());
+        double cos_rot_angle = std::cos(rotation_angle());
+        Matrix m( ray(X) * cos_rot_angle, ray(X) * sin_rot_angle,
+                 -ray(Y) * sin_rot_angle, ray(Y) * cos_rot_angle,
+                  center(X),              center(Y) );
+        Point p( std::cos(t), std::sin(t) );
+        return p * m;
+    }
+    
+    double valueAt(Coord t, Dim2 d) const
+    {
+       Coord tt = map_to_02PI(t);
+       return valueAtAngle(tt, d);
+    }
+
+    Point pointAt(Coord t) const
+    {
+        Coord tt = map_to_02PI(t);
+        return pointAtAngle(tt);
+    }
+
+    std::pair<EllipticalArc, EllipticalArc>
+    subdivide(Coord t) const
+    {
+        EllipticalArc* arc1 = static_cast<EllipticalArc*>(portion(0, t));
+        EllipticalArc* arc2 = static_cast<EllipticalArc*>(portion(t, 1));
+        assert( arc1 != NULL && arc2 != NULL);
+        std::pair<EllipticalArc, EllipticalArc> arc_pair(*arc1, *arc2);        
+        delete arc1;
+        delete arc2;
+        return arc_pair;
+    }
+
+    Curve* portion(double f, double t) const;
+    
+    // the arc is the same but traversed in the opposite direction
+    Curve* reverse() const
+    {
+        EllipticalArc* rarc = new EllipticalArc( *this );
+        rarc->m_sweep = !m_sweep;
+        rarc->m_initial_point = m_final_point;
+        rarc->m_final_point = m_initial_point;
+        rarc->m_start_angle = m_end_angle;
+        rarc->m_end_angle = m_start_angle;
+        return rarc;
+    }
+
+    double sweep_angle() const
+    {
+        Coord d = end_angle() - start_angle();
+        if ( !sweep_flag() ) d = -d;
+        if ( d < 0 )
+            d += 2*M_PI;
+        return d;
+    }
+    
+  private:
+    Coord map_to_02PI(Coord t) const;
+    Coord map_to_01(Coord angle) const; 
+    void calculate_center_and_extreme_angles();
+  private:
+    Point m_initial_point, m_final_point;
+    double m_rx, m_ry, m_rot_angle;
+    bool m_large_arc, m_sweep;
+    double m_start_angle, m_end_angle;
+    Point m_center;
+    
+}; // end class EllipticalArc
+
+
+} // end namespace Geom
+
+#endif // _2GEOM_ELLIPTICAL_ARC_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 5ed7ee1ffcc9541a37d7d418f5549aeb109cb2d8..52fd3525e324280439ad5589b55b35d38b8cdb7a 100644 (file)
@@ -44,6 +44,9 @@ typedef BezierCurve<1> LineSegment;
 typedef BezierCurve<3> CubicBezier;
 class EllipticalArc;
 
+class HLineSegment;
+class VLineSegment;
+
 typedef double Coord;
 class Point;
 
diff --git a/src/2geom/hvlinesegment.h b/src/2geom/hvlinesegment.h
new file mode 100644 (file)
index 0000000..8c47985
--- /dev/null
@@ -0,0 +1,507 @@
+/*
+ * Horizontal and Vertical Line Segment
+ *
+ * Copyright 2008  Marco Cecchetti <mrcekets at 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, 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.
+ */
+
+
+#ifndef _2GEOM_HVLINESEGMENT_H_
+#define _2GEOM_HVLINESEGMENT_H_
+
+
+#include "bezier-curve.h"
+
+
+namespace Geom
+{
+
+class HLineSegment : public Curve
+{
+  public:
+       HLineSegment()
+       {}
+       
+       HLineSegment(Coord _x0, Coord _x1, Coord _y)
+               : m_line_seg(Point(_x0, _y), Point(_x1, _y))
+       {
+       }
+       
+       HLineSegment(Point const& _p, double _length)
+               : m_line_seg(_p, Point(_p[X] + _length, _p[Y]))
+       {
+       }
+       
+       HLineSegment(Point const& _p0, Point const& _p1)
+               : m_line_seg(_p0, _p1)
+       {
+               if ( _p0[Y] != _p1[Y] )
+               {
+                       THROW_RANGEERROR("HLineSegment::HLineSegment passed points should "
+                                                "have the same Y value");
+               }
+       }
+       
+       Curve* duplicate() const
+       {
+               return new HLineSegment(*this);
+       }
+       
+       bool isDegenerate() const
+       {
+               return m_line_seg.isDegenerate();
+       }
+       
+       Point initialPoint() const
+       {
+               return m_line_seg.initialPoint();
+       }
+       
+       Point finalPoint() const 
+       {
+               return m_line_seg.finalPoint();
+       }
+       
+       Coord getY()
+       {
+               return initialPoint()[Y];
+       }
+       
+       void setInitial(Point _p) 
+       { 
+               m_line_seg.setInitial( Point(_p[X], initialPoint()[Y]) ); 
+       }
+       
+       void setFinal(Point _p) 
+       { 
+               m_line_seg.setFinal( Point(_p[X], finalPoint()[Y]) ); 
+       }
+       
+       void setX0(Coord _x)
+       {
+               m_line_seg.setInitial( Point(_x, initialPoint()[Y]) );
+       }
+       
+       void setX1(Coord _x)
+       {
+               m_line_seg.setFinal( Point(_x, finalPoint()[Y]) );
+       }
+       
+       void setY(Coord _y)
+       {
+               m_line_seg.setInitial( Point(initialPoint()[X], _y) );
+               m_line_seg.setFinal( Point(finalPoint()[X], _y) );
+       }
+
+       Rect boundsFast() const
+       {
+               return boundsExact();
+       }
+       
+       Rect boundsExact() const
+       {
+               return Rect( initialPoint(), finalPoint() );
+       }
+       
+       Rect boundsLocal(Interval i, unsigned deg) const
+       {
+               return m_line_seg.boundsLocal(i, deg);
+       }
+       
+       int winding(Point p) const
+       {
+               return m_line_seg.winding(p);
+       }
+       
+       std::vector<double>
+       roots(double v, Dim2 d) const
+       {
+               if (d < 0 || d > 1)
+               {
+                       THROW_RANGEERROR("dimension argument out of range");
+               }
+               std::vector<double> result;
+               if (d == X)
+               {
+                       if ( v >= initialPoint()[X] && v <= finalPoint()[X] )
+                       {
+                               double t = 0;
+                               if (!isDegenerate())
+                                       t = (v - initialPoint()[X]) / (finalPoint()[X] - initialPoint()[X]);
+                               result.push_back(t);
+                       }
+               }
+               else
+               {
+                       if (v == initialPoint()[Y])
+                       {
+                               if (!isDegenerate())
+                                       THROW_INFINITESOLUTIONS(0);
+                               result.push_back(0);
+                       }
+               }
+               return result;
+       }
+       
+       double nearestPoint( Point const& p, double from = 0, double to = 1 ) const
+       {
+               if ( from > to ) std::swap(from, to);
+               double xfrom = pointAt(from)[X];
+               double xto = pointAt(to)[X];
+               if ( p[X] > xfrom && p[X] < xto )
+               {
+                       return (p[X] - initialPoint()[X]) / (finalPoint()[X] - initialPoint()[X]);
+               }
+               else if ( p[X] <= xfrom )
+                       return from;
+               else
+                       return to;
+       }
+       
+       std::pair<HLineSegment, HLineSegment> subdivide(Coord t) const
+       {
+               std::pair<HLineSegment, HLineSegment> result;
+               Point p = pointAt(t);
+               result.first.setInitial(initialPoint());
+               result.first.setFinal(p);
+               result.second.setInitial(p);
+               result.second.setFinal(finalPoint());
+               return result;
+       }
+       
+       Curve* portion(double f, double t) const
+       {
+               Point ip = pointAt(f);
+               Point ep = pointAt(t);
+               return new HLineSegment(ip[X], ep[X], ip[Y]);
+       }
+       
+       Curve* reverse() const
+       {
+               return 
+               new HLineSegment(finalPoint()[X], initialPoint()[X], initialPoint()[Y]);
+       }
+       
+       Curve* transformed(Matrix const & m) const
+       {
+               Point ip = initialPoint() * m;
+               Point ep = finalPoint() * m;
+               return new LineSegment(ip, ep);
+       }
+       
+       Curve* derivative() const
+       {
+               double x = finalPoint()[X] - initialPoint()[X];
+               return new HLineSegment(x, x, 0);
+       }
+       
+       Point pointAt(double t) const
+       {
+               if ( t < 0 || t > 1 )
+                       THROW_RANGEERROR("domain parameter out of range");
+               double x = initialPoint()[X] + t * (finalPoint()[X] - initialPoint()[X]);
+               return Point(x, initialPoint()[Y]);
+       }
+       
+       double valueAt(double t, Dim2 d) const
+       {
+               if (d < 0 || d > 1)
+               {
+                       THROW_RANGEERROR("dimension argument out of range");
+               }
+               if ( t < 0 || t > 1 )
+                       THROW_RANGEERROR("domain parameter out of range");
+               
+               if (d == Y) return initialPoint()[Y];
+               
+               return initialPoint()[X] + t * (finalPoint()[X] - initialPoint()[X]);
+       }
+       
+       std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const
+       {
+               std::vector<Point> result;
+               if ( n > 0)
+                       result.push_back(pointAt(t));
+               if (n > 1)
+               {
+                       double x = finalPoint()[X] - initialPoint()[X];
+                       result.push_back( Point(x, 0) );
+               }
+               return result;
+       }
+       
+       D2<SBasis> toSBasis() const
+       {
+               return m_line_seg.toSBasis();
+       }
+       
+  private:
+       LineSegment m_line_seg;
+       
+};  // end class HLineSegment
+
+
+class VLineSegment : public Curve
+{
+  public:
+       VLineSegment()
+       {}
+       
+       VLineSegment(Coord _x, Coord _y0, Coord _y1)
+               : m_line_seg(Point(_x, _y0), Point(_x, _y1))
+       {
+       }
+       
+       VLineSegment(Point const& _p, double _length)
+               : m_line_seg(_p, Point(_p[X], _p[Y] + _length))
+       {
+       }
+       
+       VLineSegment(Point const& _p0, Point const& _p1)
+               : m_line_seg(_p0, _p1)
+       {
+               if ( _p0[X] != _p1[X] )
+               {
+                       THROW_RANGEERROR("VLineSegment::VLineSegment passed points should "
+                                                "have the same X value");
+               }
+       }
+       
+       Curve* duplicate() const
+       {
+               return new VLineSegment(*this);
+       }
+       
+       bool isDegenerate() const
+       {
+               return m_line_seg.isDegenerate();
+       }
+       
+       Point initialPoint() const
+       {
+               return m_line_seg.initialPoint();
+       }
+       
+       Point finalPoint() const 
+       {
+               return m_line_seg.finalPoint();
+       }
+       
+       Coord getX()
+       {
+               return initialPoint()[X];
+       }
+       
+       void setInitial(Point _p) 
+       { 
+               m_line_seg.setInitial( Point(initialPoint()[X], _p[Y]) ); 
+       }
+       
+       void setFinal(Point _p) 
+       { 
+               m_line_seg.setFinal( Point(finalPoint()[X], _p[Y]) ); 
+       }
+       
+       void setY0(Coord _y)
+       {
+               m_line_seg.setInitial( Point(initialPoint()[X], _y) );
+       }
+       
+       void setY1(Coord _y)
+       {
+               m_line_seg.setFinal( Point(finalPoint()[Y], _y) );
+       }
+       
+       void setX(Coord _x)
+       {
+               m_line_seg.setInitial( Point(_x, initialPoint()[Y]) );
+               m_line_seg.setFinal( Point(_x, finalPoint()[Y]) );
+       }
+
+       Rect boundsFast() const
+       {
+               return boundsExact();
+       }
+       
+       Rect boundsExact() const
+       {
+               return Rect( initialPoint(), finalPoint() );
+       }
+       
+       Rect boundsLocal(Interval i, unsigned deg) const
+       {
+               return m_line_seg.boundsLocal(i, deg);
+       }
+       
+       int winding(Point p) const
+       {
+               return m_line_seg.winding(p);
+       }
+       
+       std::vector<double>
+       roots(double v, Dim2 d) const
+       {
+               if (d < 0 || d > 1)
+               {
+                       THROW_RANGEERROR("dimension argument out of range");
+               }
+               std::vector<double> result;
+               if (d == Y)
+               {
+                       if ( v >= initialPoint()[Y] && v <= finalPoint()[Y] )
+                       {
+                               double t = 0;
+                               if (!isDegenerate())
+                                       t = (v - initialPoint()[Y]) / (finalPoint()[Y] - initialPoint()[Y]);
+                               result.push_back(t);
+                       }
+               }
+               else
+               {
+                       if (v == initialPoint()[X])
+                       {
+                               if (!isDegenerate())
+                                       THROW_INFINITESOLUTIONS(0);
+                               result.push_back(0);
+                       }
+               }
+               return result;
+       }
+       
+       double nearestPoint( Point const& p, double from = 0, double to = 1 ) const
+       {
+               if ( from > to ) std::swap(from, to);
+               double yfrom = pointAt(from)[Y];
+               double yto = pointAt(to)[Y];
+               if ( p[Y] > yfrom && p[Y] < yto )
+               {
+                       return (p[Y] - initialPoint()[Y]) / (finalPoint()[Y] - initialPoint()[Y]);
+               }
+               else if ( p[Y] <= yfrom )
+                       return from;
+               else
+                       return to;
+       }
+       
+       std::pair<VLineSegment, VLineSegment> subdivide(Coord t) const
+       {
+               std::pair<VLineSegment, VLineSegment> result;
+               Point p = pointAt(t);
+               result.first.setInitial(initialPoint());
+               result.first.setFinal(p);
+               result.second.setInitial(p);
+               result.second.setFinal(finalPoint());
+               return result;
+       }
+       
+       Curve* portion(double f, double t) const
+       {
+               Point ip = pointAt(f);
+               Point ep = pointAt(t);
+               return new VLineSegment(ip[X], ip[Y], ep[Y]);
+       }
+       
+       Curve* reverse() const
+       {
+               return 
+               new VLineSegment(initialPoint()[X], finalPoint()[Y], initialPoint()[Y]);
+       }
+       
+       Curve* transformed(Matrix const & m) const
+       {
+               Point ip = initialPoint() * m;
+               Point ep = finalPoint() * m;
+               return new LineSegment(ip, ep);
+       }
+       
+       Curve* derivative() const
+       {
+               double y = finalPoint()[Y] - initialPoint()[Y];
+               return new VLineSegment(0, y, y);
+       }
+       
+       Point pointAt(double t) const
+       {
+               if ( t < 0 || t > 1 )
+                       THROW_RANGEERROR("domain parameter out of range");
+               double y = initialPoint()[Y] + t * (finalPoint()[Y] - initialPoint()[Y]);
+               return Point(initialPoint()[X], y);
+       }
+       
+       double valueAt(double t, Dim2 d) const
+       {
+               if (d < 0 || d > 1)
+               {
+                       THROW_RANGEERROR("dimension argument out of range");
+               }
+               if ( t < 0 || t > 1 )
+                       THROW_RANGEERROR("domain parameter out of range");
+               
+               if (d == X) return initialPoint()[X];
+               
+               return initialPoint()[Y] + t * (finalPoint()[Y] - initialPoint()[Y]);
+       }
+       
+       std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const
+       {
+               std::vector<Point> result;
+               if ( n > 0)
+                       result.push_back(pointAt(t));
+               if (n > 1)
+               {
+                       double y = finalPoint()[Y] - initialPoint()[Y];
+                       result.push_back( Point(0, y) );
+               }
+               return result;
+       }
+       
+       D2<SBasis> toSBasis() const
+       {
+               return m_line_seg.toSBasis();
+       }
+       
+  private:
+       LineSegment m_line_seg;
+       
+}; // end class VLineSegment
+
+
+
+}  // end namespace Geom
+
+
+#endif // _2GEOM_HVLINESEGMENT_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 3effa93746d833f276a5a0e6e9c109664de9a90a..7176130e9ce2bd0a179f9b2b5a2d2188510a43f3 100644 (file)
@@ -1,95 +1,43 @@
 /*
  * Path - Series of continuous curves
- *   
- * Copyright 2007  MenTaLguY <mental@rydia.net>
- *     
- * This library is free software; you can redistribute it and/or 
+ *
+ * Authors:
+ *             MenTaLguY <mental@rydia.net>
+ *             Marco Cecchetti <mrcekets at gmail.com>
+ * 
+ * Copyright 2007-2008  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 
+ * 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 
+ * 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 
+ * 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 "path.h"
-
-#include "ord.h"
-
-namespace Geom {
-
-
-int CurveHelpers::root_winding(Curve const &c, Point p) {
-    std::vector<double> ts = c.roots(p[Y], Y);
-
-    if(ts.empty()) return 0;
-
-    double const fudge = 0.01; //fudge factor used on first and last
 
-    std::sort(ts.begin(), ts.end());
 
-    // winding determined by crossings at roots
-    int wind=0;
-    // previous time
-    double pt = ts.front() - fudge;
-    for ( std::vector<double>::iterator ti = ts.begin()
-        ; ti != ts.end()
-        ; ++ti )
-    {
-        double t = *ti;
-        if ( t <= 0. || t >= 1. ) continue; //skip endpoint roots 
-        if ( c.valueAt(t, X) > p[X] ) { // root is ray intersection
-            // Get t of next:
-            std::vector<double>::iterator next = ti;
-            next++;
-            double nt;
-            if(next == ts.end()) nt = t + fudge; else nt = *next;
-            
-            // Check before in time and after in time for positions
-            // Currently we're using the average times between next and previous segs
-            Cmp after_to_ray =  cmp(c.valueAt((t + nt) / 2, Y), p[Y]);
-            Cmp before_to_ray = cmp(c.valueAt((t + pt) / 2, Y), p[Y]);
-            // if y is included, these will have opposite values, giving order.
-            Cmp dt = cmp(after_to_ray, before_to_ray);
-            if(dt != EQUAL_TO) //Should always be true, but yah never know..
-                wind += dt;
-            pt = t;
-        }
-    }
-    
-    return wind;
-}
+#include "path.h"
 
 
-template<>
-inline
-double LineSegment::nearestPoint(Point const& p, double from, double to) const
+namespace Geom 
 {
-       if ( from > to ) std::swap(from, to);
-       Point ip = pointAt(from);
-       Point fp = pointAt(to);
-       Point v = fp - ip;
-       double t = dot( p - ip, v ) / L2sq(v);
-       if ( t <= 0 )           return from;
-       else if ( t >= 1 )  return to;
-       else                            return from + t*(to-from);
-}
-
 
 void Path::swap(Path &other) {
   std::swap(curves_, other.curves_);
index abed8604ab963243492b2df0bb3f773a2832ab89..670d4c1251eeb0c23fe97195a49055712290ee60 100644 (file)
  * the specific language governing rights and limitations.
  */
 
-#ifndef SEEN_GEOM_PATH_H
-#define SEEN_GEOM_PATH_H
-
-#include "point.h"
-#include "angle.h"
-#include <iterator>
-#include <algorithm>
-#include "exception.h"
-#include "d2.h"
-#include "matrix.h"
-#include "bezier.h"
-#include "crossing.h"
-#include "utils.h"
-#include "nearest-point.h"
-
-namespace Geom {
-
-class Curve;
-
-struct CurveHelpers {
-protected:
-  static int root_winding(Curve const &c, Point p);
-};
-
-class Curve : private CurveHelpers {
-public:
-  virtual ~Curve() {}
-
-  virtual Point initialPoint() const = 0;
-  virtual Point finalPoint() const = 0;
-
-  virtual bool isDegenerate() const = 0;
-
-  virtual Curve *duplicate() const = 0;
-
-  virtual Rect boundsFast() const = 0;
-  virtual Rect boundsExact() const = 0;
-  virtual Rect boundsLocal(Interval i, unsigned deg) const = 0;
-  Rect boundsLocal(Interval i) const { return boundsLocal(i, 0); }
-
-  virtual std::vector<double> roots(double v, Dim2 d) const = 0;
-
-  virtual int winding(Point p) const { return root_winding(*this, p); }
-
-  //mental: review these
-  virtual Curve *portion(double f, double t) const = 0;
-  virtual Curve *reverse() const { return portion(1, 0); }
-  virtual Curve *derivative() const = 0;
-
-  virtual void setInitial(Point v) = 0;
-  virtual void setFinal(Point v) = 0;
-  
-  virtual
-  double nearestPoint( Point const& p, double from = 0, double to = 1 ) const
-  {
-         return nearest_point(p, toSBasis(), from, to);
-  }
-  
-  virtual
-  std::vector<double> 
-  allNearestPoints( Point const& p, double from = 0, double to = 1 ) const
-  {
-         return all_nearest_points(p, toSBasis(), from, to);
-  }
-
-  virtual Curve *transformed(Matrix const &m) const = 0;
-
-  virtual Point pointAt(Coord t) const { return pointAndDerivatives(t, 1).front(); }
-  virtual Coord valueAt(Coord t, Dim2 d) const { return pointAt(t)[d]; }
-  virtual std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const = 0;
-  virtual D2<SBasis> toSBasis() const = 0;
-};
-
-class SBasisCurve : public Curve {
-       
-private:
-  SBasisCurve();
-  D2<SBasis> inner;
-  
-public:
-  explicit SBasisCurve(D2<SBasis> const &sb) : inner(sb) {}
-  explicit SBasisCurve(Curve const &other) : inner(other.toSBasis()) {}
-  Curve *duplicate() const { return new SBasisCurve(*this); }
-
-  Point initialPoint() const    { return inner.at0(); }
-  Point finalPoint() const      { return inner.at1(); }
-  bool isDegenerate() const     { return inner.isConstant(); }
-  Point pointAt(Coord t) const  { return inner.valueAt(t); }
-  std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const {
-      return inner.valueAndDerivatives(t, n);
-  }
-  double valueAt(Coord t, Dim2 d) const { return inner[d].valueAt(t); }
-
-  void setInitial(Point v) { for(unsigned d = 0; d < 2; d++) { inner[d][0][0] = v[d]; } }
-  void setFinal(Point v)   { for(unsigned d = 0; d < 2; d++) { inner[d][0][1] = v[d]; } }
-
-  Rect boundsFast() const  { return bounds_fast(inner); }
-  Rect boundsExact() const { return bounds_exact(inner); }
-  Rect boundsLocal(Interval i, unsigned deg) const { return bounds_local(inner, i, deg); }
-
-  std::vector<double> roots(double v, Dim2 d) const { return Geom::roots(inner[d] - v); }
-  
-  double nearestPoint( Point const& p, double from = 0, double to = 1 ) const
-  {
-         return nearest_point(p, inner, from, to);
-  }
-  
-  std::vector<double> 
-  allNearestPoints( Point const& p, double from = 0, double to = 1 ) const
-  {
-         return all_nearest_points(p, inner, from, to);
-  }
-
-  Curve *portion(double f, double t) const {
-    return new SBasisCurve(Geom::portion(inner, f, t));
-  }
-
-  Curve *transformed(Matrix const &m) const {
-    return new SBasisCurve(inner * m);
-  }
-
-  Curve *derivative() const {
-    return new SBasisCurve(Geom::derivative(inner));
-  }
-
-  D2<SBasis> toSBasis() const { return inner; }
-
-};
-
-template <unsigned order>
-class BezierCurve : public Curve {
-       
-private:
-  D2<Bezier > inner;
-  
-public:
-  template <unsigned required_degree>
-  static void assert_degree(BezierCurve<required_degree> const *) {}
-
-  BezierCurve() : inner(Bezier::Order(order), Bezier::Order(order)) {
-  }
 
-  explicit BezierCurve(D2<Bezier > const &x) : inner(x) {}
 
-  BezierCurve(Bezier x, Bezier y) : inner(x, y) {}
 
-  // default copy
-  // default assign
-
-  BezierCurve(Point c0, Point c1) {
-    assert_degree<1>(this);
-    for(unsigned d = 0; d < 2; d++)
-        inner[d] = Bezier(c0[d], c1[d]);
-  }
-
-  BezierCurve(Point c0, Point c1, Point c2) {
-    assert_degree<2>(this);
-    for(unsigned d = 0; d < 2; d++)
-        inner[d] = Bezier(c0[d], c1[d], c2[d]);
-  }
-
-  BezierCurve(Point c0, Point c1, Point c2, Point c3) {
-    assert_degree<3>(this);
-    for(unsigned d = 0; d < 2; d++)
-        inner[d] = Bezier(c0[d], c1[d], c2[d], c3[d]);
-  }
-
-  unsigned degree() const { return order; }
-
-  Curve *duplicate() const { return new BezierCurve(*this); }
-
-  Point initialPoint() const { return inner.at0(); }
-  Point finalPoint() const { return inner.at1(); }
-
-  bool isDegenerate() const { return inner.isConstant(); }
-
-  void setInitial(Point v) { setPoint(0, v); }
-  void setFinal(Point v)   { setPoint(order, v); }
-
-  void setPoint(unsigned ix, Point v) { inner[X].setPoint(ix, v[X]); inner[Y].setPoint(ix, v[Y]); }
-  Point const operator[](unsigned ix) const { return Point(inner[X][ix], inner[Y][ix]); }
-
-  Rect boundsFast() const { return bounds_fast(inner); }
-  Rect boundsExact() const { return bounds_exact(inner); }
-  Rect boundsLocal(Interval i, unsigned deg) const {
-      if(i.min() == 0 && i.max() == 1) return boundsFast();
-      if(deg == 0) return bounds_local(inner, i);
-      // TODO: UUUUUUGGGLLY
-      if(deg == 1 && order > 1) return Rect(bounds_local(Geom::derivative(inner[X]), i),
-                                            bounds_local(Geom::derivative(inner[Y]), i));
-      return Rect(Interval(0,0), Interval(0,0));
-  }
-//TODO: local
-
-//TODO: implement next 3 natively
-  int winding(Point p) const {
-    return SBasisCurve(toSBasis()).winding(p);
-  }
-
-  std::vector<double>
-  roots(double v, Dim2 d) const {
-      return (inner[d] - v).roots();
-  }
-  
-  double nearestPoint( Point const& p, double from = 0, double to = 1 ) const
-  {
-         return Curve::nearestPoint(p, from, to);
-  }
-  
-  void setPoints(std::vector<Point> ps) {
-    for(unsigned i = 0; i <= order; i++) {
-      setPoint(i, ps[i]);
-    }
-  }
-  std::vector<Point> points() const { return bezier_points(inner); }
-
-  std::pair<BezierCurve<order>, BezierCurve<order> > subdivide(Coord t) const {
-    std::pair<Bezier, Bezier > sx = inner[X].subdivide(t), sy = inner[Y].subdivide(t);
-    return std::pair<BezierCurve<order>, BezierCurve<order> >(
-               BezierCurve<order>(sx.first, sy.first),
-               BezierCurve<order>(sx.second, sy.second));
-  }
-
-  Curve *portion(double f, double t) const {
-    return new BezierCurve(Geom::portion(inner, f, t));
-  }
-
-  Curve *reverse() const {
-    return new BezierCurve(Geom::reverse(inner));
-  }
-
-  Curve *transformed(Matrix const &m) const {
-    BezierCurve *ret = new BezierCurve();
-    std::vector<Point> ps = points();
-    for(unsigned i = 0;  i <= order; i++) ps[i] = ps[i] * m;
-    ret->setPoints(ps);
-    return ret;
-  }
-
-  Curve *derivative() const {
-     if(order > 1)
-        return new BezierCurve<order-1>(Geom::derivative(inner[X]), Geom::derivative(inner[Y]));
-     else if (order == 1) {
-        double dx = inner[X][1] - inner[X][0], dy = inner[Y][1] - inner[Y][0];
-        return new BezierCurve<1>(Point(dx,dy),Point(dx,dy));
-     }
-  }
-
-  Point pointAt(double t) const { return inner.valueAt(t); }
-  std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const { return inner.valueAndDerivatives(t, n); }
-
-  double valueAt(double t, Dim2 d) const { return inner[d].valueAt(t); }
-
-  D2<SBasis> toSBasis() const {return inner.toSBasis(); }
-
-protected:
-  BezierCurve(Point c[]) {
-    Coord x[order+1], y[order+1];
-    for(unsigned i = 0; i <= order; i++) {
-        x[i] = c[i][X]; y[i] = c[i][Y];
-    }
-    inner = Bezier(x, y);
-  }
-};
-
-// BezierCurve<0> is meaningless; specialize it out
-template<> class BezierCurve<0> : public BezierCurve<1> { public: BezierCurve(); BezierCurve(Bezier x, Bezier y); };
+#ifndef SEEN_GEOM_PATH_H
+#define SEEN_GEOM_PATH_H
 
-typedef BezierCurve<1> LineSegment;
-typedef BezierCurve<2> QuadraticBezier;
-typedef BezierCurve<3> CubicBezier;
 
-template<>
-double LineSegment::nearestPoint(Point const& p, double from, double to) const;
+#include "curves.h"
 
+#include <iterator>
 
 
-class EllipticalArc : public Curve
+namespace Geom
 {
-  public:
-       EllipticalArc()
-               : m_initial_point(Point(0,0)), m_final_point(Point(0,0)),
-                 m_rx(0), m_ry(0), m_rot_angle(0),
-                 m_large_arc(true), m_sweep(true)
-       {
-               m_start_angle = m_end_angle = 0;
-               m_center = Point(0,0);
-       }
-       
-    EllipticalArc( Point _initial_point, double _rx, double _ry,
-                   double _rot_angle, bool _large_arc, bool _sweep,
-                   Point _final_point
-                  )
-        : m_initial_point(_initial_point), m_final_point(_final_point),
-          m_rx(_rx), m_ry(_ry), m_rot_angle(_rot_angle),
-          m_large_arc(_large_arc), m_sweep(_sweep)
-    {
-            calculate_center_and_extreme_angles();
-    }
-         
-    void set( Point _initial_point, double _rx, double _ry,
-              double _rot_angle, bool _large_arc, bool _sweep,
-              Point _final_point
-             )
-    {
-       m_initial_point = _initial_point;
-       m_final_point = _final_point;
-       m_rx = _rx;
-       m_ry = _ry;
-       m_rot_angle = _rot_angle;
-       m_large_arc = _large_arc;
-       m_sweep = _sweep;
-       calculate_center_and_extreme_angles();
-    }
-
-       Curve* duplicate() const
-       {
-               return new EllipticalArc(*this);
-       }
-       
-    double center(unsigned int i) const
-    {
-        return m_center[i];
-    }
-
-    Point center() const
-    {
-        return m_center;
-    }
-
-    Point initialPoint() const
-    {
-        return m_initial_point;
-    }
-
-    Point finalPoint() const
-    {
-        return m_final_point;
-    }
-
-    double start_angle() const
-    {
-        return m_start_angle;
-    }
-
-    double end_angle() const
-    {
-        return m_end_angle;
-    }
-
-    double ray(unsigned int i) const
-    {
-        return (i == 0) ? m_rx : m_ry;
-    }
-
-    bool large_arc_flag() const
-    {
-        return m_large_arc;
-    }
-
-    bool sweep_flag() const
-    {
-        return m_sweep;
-    }
-
-    double rotation_angle() const
-    {
-        return m_rot_angle;
-    }
-
-    void setInitial( const Point _point)
-    {
-        m_initial_point = _point;
-        calculate_center_and_extreme_angles();
-    }
-
-    void setFinal( const Point _point)
-    {
-        m_final_point = _point;
-        calculate_center_and_extreme_angles();
-    }
-
-    void setExtremes( const Point& _initial_point, const Point& _final_point )
-    {
-        m_initial_point = _initial_point;
-        m_final_point = _final_point;
-        calculate_center_and_extreme_angles();
-    }
-
-    bool isDegenerate() const
-    {
-        return ( are_near(ray(X), 0) || are_near(ray(Y), 0) );
-    }
-    
-    // TODO: native implementation of the following methods
-    Rect boundsFast() const
-    {
-       return boundsExact();
-    }
-  
-    Rect boundsExact() const;
-    
-    Rect boundsLocal(Interval i, unsigned int deg) const
-    {
-       return SBasisCurve(toSBasis()).boundsLocal(i, deg);
-    }
-    
-    std::vector<double> roots(double v, Dim2 d) const;
-    
-    std::vector<double> 
-    allNearestPoints( Point const& p, double from = 0, double to = 1 ) const;
-    
-    double nearestPoint( Point const& p, double from = 0, double to = 1 ) const
-    {
-       if ( are_near(ray(X), ray(Y)) && are_near(center(), p) )
-       {
-               return from;
-       }
-       return allNearestPoints(p, from, to).front();
-    }
-    
-    int winding(Point p) const
-    {
-       return SBasisCurve(toSBasis()).winding(p);
-    }
-    
-    Curve *derivative() const;
-    
-    Curve *transformed(Matrix const &m) const
-    {
-       return SBasisCurve(toSBasis()).transformed(m);
-    }
-    
-    std::vector<Point> pointAndDerivatives(Coord t, unsigned int n) const;
-    
-    D2<SBasis> toSBasis() const;
-    
-    bool containsAngle(Coord angle) const;
-    
-    double valueAtAngle(Coord t, Dim2 d) const;
-    
-    Point pointAtAngle(Coord t) const
-    {
-        double sin_rot_angle = std::sin(rotation_angle());
-        double cos_rot_angle = std::cos(rotation_angle());
-        Matrix m( ray(X) * cos_rot_angle, ray(X) * sin_rot_angle,
-                 -ray(Y) * sin_rot_angle, ray(Y) * cos_rot_angle,
-                  center(X),              center(Y) );
-        Point p( std::cos(t), std::sin(t) );
-        return p * m;
-    }
-    
-    double valueAt(Coord t, Dim2 d) const
-    {
-       Coord tt = map_to_02PI(t);
-       return valueAtAngle(tt, d);
-    }
-
-    Point pointAt(Coord t) const
-    {
-        Coord tt = map_to_02PI(t);
-        return pointAtAngle(tt);
-    }
-
-    std::pair<EllipticalArc, EllipticalArc>
-    subdivide(Coord t) const
-    {
-        EllipticalArc* arc1 = static_cast<EllipticalArc*>(portion(0, t));
-        EllipticalArc* arc2 = static_cast<EllipticalArc*>(portion(t, 1));
-        assert( arc1 != NULL && arc2 != NULL);
-        std::pair<EllipticalArc, EllipticalArc> arc_pair(*arc1, *arc2);        
-        delete arc1;
-        delete arc2;
-        return arc_pair;
-    }
-
-    Curve* portion(double f, double t) const;
-    
-    // the arc is the same but traversed in the opposite direction
-    Curve* reverse() const
-    {
-        EllipticalArc* rarc = new EllipticalArc( *this );
-        rarc->m_sweep = !m_sweep;
-        rarc->m_initial_point = m_final_point;
-        rarc->m_final_point = m_initial_point;
-        rarc->m_start_angle = m_end_angle;
-        rarc->m_end_angle = m_start_angle;
-        return rarc;
-    }
-
-    double sweep_angle() const
-    {
-        Coord d = end_angle() - start_angle();
-        if ( !sweep_flag() ) d = -d;
-        if ( d < 0 )
-            d += 2*M_PI;
-        return d;
-    }
-    
-  private:
-    Coord map_to_02PI(Coord t) const;
-    Coord map_to_01(Coord angle) const; 
-    void calculate_center_and_extreme_angles();
-  private:
-    Point m_initial_point, m_final_point;
-    double m_rx, m_ry, m_rot_angle;
-    bool m_large_arc, m_sweep;
-    double m_start_angle, m_end_angle;
-    Point m_center;
-    
-}; // end class EllipticalArc
-
-
-
 
 template <typename IteratorImpl>
 class BaseIterator
@@ -1032,7 +532,8 @@ private:
   Sequence curves_;
   LineSegment *final_;
   bool closed_;
-};
+  
+};  // end class Path
 
 inline static Piecewise<D2<SBasis> > paths_to_pw(std::vector<Path> paths) {
     Piecewise<D2<SBasis> > ret = paths[0].toPwSb();
@@ -1089,7 +590,7 @@ class PathPortion : public Curve {
 };
 */
 
-}
+}  // end namespace Geom
 
 namespace std {
 
@@ -1099,10 +600,14 @@ inline void swap<Geom::Path>(Geom::Path &a, Geom::Path &b)
   a.swap(b);
 }
 
-}
+}  // end namespace std
+
 
 #endif // SEEN_GEOM_PATH_H
 
+
+
+
 /*
   Local Variables:
   mode:c++
diff --git a/src/2geom/sbasis-curve.h b/src/2geom/sbasis-curve.h
new file mode 100644 (file)
index 0000000..1612f46
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Simmetric Power Bais Curve
+ *
+ * Authors:
+ *             MenTaLguY <mental@rydia.net>
+ *             Marco Cecchetti <mrcekets at gmail.com>
+ * 
+ * Copyright 2007-2008  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.
+ */
+
+
+
+
+#ifndef _2GEOM_SBASIS_CURVE_H_
+#define _2GEOM_SBASIS_CURVE_H_
+
+
+#include "curve.h"
+
+
+namespace Geom 
+{
+
+class SBasisCurve : public Curve {
+       
+private:
+  SBasisCurve();
+  D2<SBasis> inner;
+  
+public:
+  explicit SBasisCurve(D2<SBasis> const &sb) : inner(sb) {}
+  explicit SBasisCurve(Curve const &other) : inner(other.toSBasis()) {}
+  Curve *duplicate() const { return new SBasisCurve(*this); }
+
+  Point initialPoint() const    { return inner.at0(); }
+  Point finalPoint() const      { return inner.at1(); }
+  bool isDegenerate() const     { return inner.isConstant(); }
+  Point pointAt(Coord t) const  { return inner.valueAt(t); }
+  std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const {
+      return inner.valueAndDerivatives(t, n);
+  }
+  double valueAt(Coord t, Dim2 d) const { return inner[d].valueAt(t); }
+
+  void setInitial(Point v) { for(unsigned d = 0; d < 2; d++) { inner[d][0][0] = v[d]; } }
+  void setFinal(Point v)   { for(unsigned d = 0; d < 2; d++) { inner[d][0][1] = v[d]; } }
+
+  Rect boundsFast() const  { return bounds_fast(inner); }
+  Rect boundsExact() const { return bounds_exact(inner); }
+  Rect boundsLocal(Interval i, unsigned deg) const { return bounds_local(inner, i, deg); }
+
+  std::vector<double> roots(double v, Dim2 d) const { return Geom::roots(inner[d] - v); }
+  
+  double nearestPoint( Point const& p, double from = 0, double to = 1 ) const
+  {
+         return nearest_point(p, inner, from, to);
+  }
+  
+  std::vector<double> 
+  allNearestPoints( Point const& p, double from = 0, double to = 1 ) const
+  {
+         return all_nearest_points(p, inner, from, to);
+  }
+
+  Curve *portion(double f, double t) const {
+    return new SBasisCurve(Geom::portion(inner, f, t));
+  }
+
+  Curve *transformed(Matrix const &m) const {
+    return new SBasisCurve(inner * m);
+  }
+
+  Curve *derivative() const {
+    return new SBasisCurve(Geom::derivative(inner));
+  }
+
+  D2<SBasis> toSBasis() const { return inner; }
+
+};
+
+
+} // end namespace Geom
+
+
+#endif // _2GEOM_SBASIS_CURVE_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 :