0,0 → 1,97 
SET(2GEOM_VERSION 0.1.0) 

# We need to pass fPIC only to lib2geom on amd64  avoid it elsewhere see: http://www.gentoo.org/proj/en/base/amd64/howtos/index.xml?part=1&chap=3 
IF (ARCH_X86_64 EQUAL 1) 
SET(CMAKE_CXX_FLAGS "$(CMAKE_CXX_FLAGS) fPIC") 
ENDIF (ARCH_X86_64 EQUAL 1) 

OPTION(2GEOM_BUILD_SHARED 
"Build lib2geom and libtoy as shared libraries." 
OFF) 
SET(LIB_TYPE STATIC) 

SET(2GEOM_SRC 
svgpath.h 
svgpath.cpp 
ord.h 
path.cpp 
path.h 
pathintersection.cpp 
pathintersection.h 
svgellipticalarc.h 
shape.cpp 
shape.h 
region.cpp 
region.h 
crossing.h 
crossing.cpp 
sweep.cpp 
sweep.h 
poly.cpp 
poly.h 
polydksolve.cpp 
polydksolve.h 
polylaguerresolve.cpp 
polylaguerresolve.h 
quadtree.cpp 
quadtree.h 
matrix.cpp 
matrix.h 
transforms.cpp 
transforms.h 
point.h 
point.cpp 
pointl.h 
coord.h 
d2.h 
d2sbasis.h 
d2sbasis.cpp 
rect.h 
piecewise.h 
piecewise.cpp 
sbasis.cpp 
sbasis.h 
sbasis2d.h 
sbasis2d.cpp 
sbasisgeometric.cpp 
sbasisgeometric.h 
sbasismath.h 
sbasismath.cpp 
sbasispoly.cpp 
sbasispoly.h 
sbasisroots.cpp 
sbasistobezier.cpp 
sbasistobezier.h 
beziertosbasis.h 
basicintersection.h 
basicintersection.cpp 
geom.cpp 
geom.h 
utils.h 
exception.h 
angle.h 
bezierutils.cpp 
bezierutils.h 
choose.h 
circulator.h 
conjugate_gradient.cpp 
conjugate_gradient.h 
convexcover.cpp 
convexcover.h 
solvebezieroned.cpp 
solvebezierparametric.cpp 
solver.h 
sturm.h 
scribushelper.h 
scribushelper.cpp 
) 

SET(SCRIBUS_2GEOM_LIB "scribus_2geom_lib") 
ADD_LIBRARY(${SCRIBUS_2GEOM_LIB} STATIC ${2GEOM_SRC}) 

# This is a convenience library that for linkage purposes is part of Scribus's 
# main API. 
SET_TARGET_PROPERTIES(${SCRIBUS_2GEOM_LIB} 
PROPERTIES 
COMPILE_FLAGS DCOMPILE_SCRIBUS_MAIN_APP 
) 
Property changes: 
Added: svn:executable 
## 0,0 +1 ## 
+* 
\ No newline at end of property 
Index: Scribus/scribus/third_party/lib2geom/sbasismath.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/sbasismath.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/sbasismath.cpp (revision 14937) 
@@ 0,0 +1,291 @@ 
+/* 
+ * sbasismath.cpp  some std functions to work with (pw)sbasis 
+ * 
+ * Authors: 
+ * JeanFrancois Barraud 
+ * 
+ * Copyright (C) 20062007 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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. 
+ */ 
+ 
+//this a first try to define sqrt, cos, sin, etc... 
+//TODO: define a truncated compose(sb,sb, order) and extend it to pw<sb>. 
+//TODO: in all these functions, compute 'order' according to 'tol'. 
+ 
+#include "sbasismath.h" 
+//#define ZERO 1e3 
+ 
+#include <cstdio> 
+#include <cmath> 
+#include "angle.h" 
+ 
+namespace Geom { 
+ 
+//x 
+Piecewise<SBasis> abs(SBasis const &f){ 
+ return abs(Piecewise<SBasis>(f)); 
+} 
+Piecewise<SBasis> abs(Piecewise<SBasis> const &f){ 
+ Piecewise<SBasis> absf=partition(f,roots(f)); 
+ for (unsigned i=0; i<absf.size(); i++){ 
+ if (absf.segs[i](.5)<0) absf.segs[i]*=1; 
+ } 
+ return absf; 
+} 
+ 
+//max(x,y), min(x,y) 
+Piecewise<SBasis> max( SBasis const &f, SBasis const &g){ 
+ return max(Piecewise<SBasis>(f),Piecewise<SBasis>(g)); 
+} 
+Piecewise<SBasis> max(Piecewise<SBasis> const &f, SBasis const &g){ 
+ return max(f,Piecewise<SBasis>(g)); 
+} 
+Piecewise<SBasis> max( SBasis const &f, Piecewise<SBasis> const &g){ 
+ return max(Piecewise<SBasis>(f),g); 
+} 
+Piecewise<SBasis> max(Piecewise<SBasis> const &f, Piecewise<SBasis> const &g){ 
+ Piecewise<SBasis> max=partition(f,roots(fg)); 
+ Piecewise<SBasis> gg =partition(g,max.cuts); 
+ max = partition(max,gg.cuts); 
+ for (unsigned i=0; i<max.size(); i++){ 
+ if (max.segs[i](.5)<gg.segs[i](.5)) max.segs[i]=gg.segs[i]; 
+ } 
+ return max; 
+} 
+ 
+Piecewise<SBasis> 
+min( SBasis const &f, SBasis const &g){ return max(f,g); } 
+Piecewise<SBasis> 
+min(Piecewise<SBasis> const &f, SBasis const &g){ return max(f,g); } 
+Piecewise<SBasis> 
+min( SBasis const &f, Piecewise<SBasis> const &g){ return max(f,g); } 
+Piecewise<SBasis> 
+min(Piecewise<SBasis> const &f, Piecewise<SBasis> const &g){ return max(f,g); } 
+ 
+ 
+//sign(x) 
+Piecewise<SBasis> signSb(SBasis const &f){ 
+ return signSb(Piecewise<SBasis>(f)); 
+} 
+Piecewise<SBasis> signSb(Piecewise<SBasis> const &f){ 
+ Piecewise<SBasis> sign=partition(f,roots(f)); 
+ for (unsigned i=0; i<sign.size(); i++){ 
+ sign.segs[i] = (sign.segs[i](.5)<0)? Linear(1.):Linear(1.); 
+ } 
+ return sign; 
+} 
+ 
+//Sqrt 
+static Piecewise<SBasis> sqrt_internal(SBasis const &f, 
+ double tol, 
+ int order){ 
+ SBasis sqrtf; 
+ if(f.isZero()  order == 0){ 
+ return Piecewise<SBasis>(sqrtf); 
+ } 
+ if (f.at0()<tol*tol && f.at1()<tol*tol){ 
+ return sqrt_internal(f,tol,order); 
+ }else if (f.at0()>tol*tol && f.at1()>tol*tol){ 
+ sqrtf.resize(order+1, Linear(0,0)); 
+ sqrtf[0] = Linear(std::sqrt(f[0][0]), std::sqrt(f[0][1])); 
+ SBasis r = f  multiply(sqrtf, sqrtf); // remainder 
+ for(unsigned i = 1; int(i) <= order && i<r.size(); ++i) { 
+ Linear ci(r[i][0]/(2*sqrtf[0][0]), r[i][1]/(2*sqrtf[0][1])); 
+ SBasis cisi = shift(ci, i); 
+ r = multiply(shift((sqrtf*2 + cisi), i), SBasis(ci)); 
+ r.truncate(order+1); 
+ sqrtf[i] = ci; 
+ if(r.tailError(i) == 0) // if exact 
+ break; 
+ } 
+ }else{ 
+ sqrtf = Linear(std::sqrt(fabs(f.at0())), std::sqrt(fabs(f.at1()))); 
+ } 
+ 
+ double err = (f  multiply(sqrtf, sqrtf)).tailError(0); 
+ if (err<tol){ 
+ return Piecewise<SBasis>(sqrtf); 
+ } 
+ 
+ Piecewise<SBasis> sqrtf0,sqrtf1; 
+ sqrtf0 = sqrt_internal(compose(f,Linear(0.,.5)),tol,order); 
+ sqrtf1 = sqrt_internal(compose(f,Linear(.5,1.)),tol,order); 
+ sqrtf0.setDomain(Interval(0.,.5)); 
+ sqrtf1.setDomain(Interval(.5,1.)); 
+ sqrtf0.concat(sqrtf1); 
+ return sqrtf0; 
+} 
+ 
+Piecewise<SBasis> sqrt(SBasis const &f, double tol, int order){ 
+ return sqrt(max(f,Linear(tol*tol)),tol,order); 
+} 
+ 
+Piecewise<SBasis> sqrt(Piecewise<SBasis> const &f, double tol, int order){ 
+ Piecewise<SBasis> result; 
+ Piecewise<SBasis> zero = Piecewise<SBasis>(Linear(tol*tol)); 
+ zero.setDomain(f.domain()); 
+ Piecewise<SBasis> ff=max(f,zero); 
+ 
+ for (unsigned i=0; i<ff.size(); i++){ 
+ Piecewise<SBasis> sqrtfi = sqrt_internal(ff.segs[i],tol,order); 
+ sqrtfi.setDomain(Interval(ff.cuts[i],ff.cuts[i+1])); 
+ result.concat(sqrtfi); 
+ } 
+ return result; 
+} 
+ 
+//Yet another sin/cos 
+ 
+Piecewise<SBasis> sin( SBasis const &f, double tol, int order){return cos(f+M_PI_2,tol,order);} 
+Piecewise<SBasis> sin(Piecewise<SBasis> const &f, double tol, int order){return cos(f+M_PI_2,tol,order);} 
+ 
+Piecewise<SBasis> cos(Piecewise<SBasis> const &f, double tol, int order){ 
+ Piecewise<SBasis> result; 
+ for (unsigned i=0; i<f.size(); i++){ 
+ Piecewise<SBasis> cosfi = cos(f.segs[i],tol,order); 
+ cosfi.setDomain(Interval(f.cuts[i],f.cuts[i+1])); 
+ result.concat(cosfi); 
+ } 
+ return result; 
+} 
+ 
+Piecewise<SBasis> cos( SBasis const &f, double tol, int order){ 
+ double alpha = (f.at0()+f.at1())/2.; 
+ SBasis x = falpha; 
+ double d = x.tailError(0),err=1; 
+ //estimate cos(x)sum_0^order (1)^k x^2k/2k! by the first neglicted term 
+ for (int i=1; i<=2*order; i++) err*=d/i; 
+ 
+ if (err<tol){ 
+ SBasis xk=Linear(1), c=Linear(1), s=Linear(0); 
+ for (int k=1; k<=2*order; k+=2){ 
+ xk*=x/k; 
+ //take also truncature errors into account... 
+ err+=xk.tailError(order); 
+ xk.truncate(order); 
+ s+=xk; 
+ xk*=x/(k+1); 
+ //take also truncature errors into account... 
+ err+=xk.tailError(order); 
+ xk.truncate(order); 
+ c+=xk; 
+ } 
+ if (err<tol){ 
+ return Piecewise<SBasis>(std::cos(alpha)*cstd::sin(alpha)*s); 
+ } 
+ } 
+ Piecewise<SBasis> c0,c1; 
+ c0 = cos(compose(f,Linear(0.,.5)),tol,order); 
+ c1 = cos(compose(f,Linear(.5,1.)),tol,order); 
+ c0.setDomain(Interval(0.,.5)); 
+ c1.setDomain(Interval(.5,1.)); 
+ c0.concat(c1); 
+ return c0; 
+} 
+ 
+ 
+//1/x 
+//TODO: this implementation is just wrong. Remove or redo! 
+ 
+void truncateResult(Piecewise<SBasis> &f, int order){ 
+ if (order>=0){ 
+ for (unsigned k=0; k<f.segs.size(); k++){ 
+ f.segs[k].truncate(order); 
+ } 
+ } 
+} 
+ 
+Piecewise<SBasis> reciprocalOnDomain(Interval range, double tol){ 
+ Piecewise<SBasis> reciprocal_fn; 
+ //TODO: deduce R from tol... 
+ double R=2.; 
+ SBasis reciprocal1_R=reciprocal(Linear(1,R),3); 
+ double a=range.min(), b=range.max(); 
+ if (a*b<0){ 
+ b=std::max(fabs(a),fabs(b)); 
+ a=0; 
+ }else if (b<0){ 
+ a=range.max(); 
+ b=range.min(); 
+ } 
+ 
+ if (a<=tol){ 
+ reciprocal_fn.push_cut(0); 
+ int i0=(int) floor(std::log(tol)/std::log(R)); 
+ a=pow(R,i0); 
+ reciprocal_fn.push(Linear(1/a),a); 
+ }else{ 
+ int i0=(int) floor(std::log(a)/std::log(R)); 
+ a=pow(R,i0); 
+ reciprocal_fn.cuts.push_back(a); 
+ } 
+ 
+ while (a<b){ 
+ reciprocal_fn.push(reciprocal1_R/a,R*a); 
+ a*=R; 
+ } 
+ if (range.min()<0  range.max()<0){ 
+ Piecewise<SBasis>reciprocal_fn_neg; 
+ //TODO: define reverse(pw<sb>); 
+ reciprocal_fn_neg.cuts.push_back(reciprocal_fn.cuts.back()); 
+ for (unsigned i=0; i<reciprocal_fn.size(); i++){ 
+ int idx=reciprocal_fn.segs.size()1i; 
+ reciprocal_fn_neg.push_seg(reverse(reciprocal_fn.segs.at(idx))); 
+ reciprocal_fn_neg.push_cut(reciprocal_fn.cuts.at(idx)); 
+ } 
+ if (range.max()>0){ 
+ reciprocal_fn_neg.concat(reciprocal_fn); 
+ } 
+ reciprocal_fn=reciprocal_fn_neg; 
+ } 
+ 
+ return(reciprocal_fn); 
+} 
+ 
+Piecewise<SBasis> reciprocal(SBasis const &f, double tol, int order){ 
+ Piecewise<SBasis> reciprocal_fn=reciprocalOnDomain(bounds_fast(f), tol); 
+ Piecewise<SBasis> result=compose(reciprocal_fn,f); 
+ truncateResult(result,order); 
+ return(result); 
+} 
+Piecewise<SBasis> reciprocal(Piecewise<SBasis> const &f, double tol, int order){ 
+ Piecewise<SBasis> reciprocal_fn=reciprocalOnDomain(bounds_fast(f), tol); 
+ Piecewise<SBasis> result=compose(reciprocal_fn,f); 
+ truncateResult(result,order); 
+ return(result); 
+} 
+ 
+} 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype = cpp:expandtab:shiftwidth = 4:tabstop = 8:softtabstop = 4:encoding = utf8:textwidth = 99 : 
Index: Scribus/scribus/third_party/lib2geom/scribushelper.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/scribushelper.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/scribushelper.h (revision 14937) 
@@ 0,0 +1,40 @@ 
+/* 
+For general Scribus (>=1.3.2) copyright and licensing information please refer 
+to the COPYING file provided with the program. Following this notice may exist 
+a copyright and/or license notice that predates the release of Scribus 1.3.2 
+for which a new license (GPL+exception) is in place. 
+*/ 
+#ifndef SCRIBUSHELPER_H 
+#define SCRIBUSHELPER_H 
+ 
+#include "fpointarray.h" 
+#include <vector> 
+#include "sbasis.h" 
+#include "sbasisgeometric.h" 
+#include "beziertosbasis.h" 
+#include "sbasistobezier.h" 
+#include "d2.h" 
+#include "piecewise.h" 
+#include "utils.h" 
+#include "path.h" 
+#include "sbasis2d.h" 
+#include <QPainterPath> 
+ 
+static FPoint currentPoint; 
+// Functions to convert from lib2geom to FPointArray and vice versa 
+void scribus_curve(FPointArray *cr, Geom::Curve const& c); 
+void geomPath2FPointArray(FPointArray *p, Geom::Path &pp); 
+void Piecewise2FPointArray(FPointArray *p, Geom::Piecewise<Geom::D2<Geom::SBasis> > &pp); 
+void D2sb2d2FPointArray(FPointArray* cr, Geom::D2<Geom::SBasis2d> const &sb2, int num, double width); 
+std::vector<Geom::Path> FPointArray2geomPath(FPointArray &p, bool closed); 
+Geom::Piecewise<Geom::D2<Geom::SBasis> > FPointArray2Piecewise(FPointArray &p, bool closed); 
+ 
+// Functions to convert from lib2geom to QPainterPath and vice versa 
+void arthur_curve(QPainterPath *cr, Geom::Curve const& c); 
+void geomPath2QPainterPath(QPainterPath *p, Geom::Path &pp); 
+void Piecewise2QPainterPath(QPainterPath *p, Geom::Piecewise<Geom::D2<Geom::SBasis> > &pp); 
+void D2sb2d2QPainterPath(QPainterPath* cr, Geom::D2<Geom::SBasis2d> const &sb2, int num, double width); 
+std::vector<Geom::Path> QPainterPath2geomPath(QPainterPath &p, bool closed); 
+Geom::Piecewise<Geom::D2<Geom::SBasis> > QPainterPath2Piecewise(QPainterPath &p, bool closed); 
+ 
+#endif 
Index: Scribus/scribus/third_party/lib2geom/scribushelper.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/scribushelper.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/scribushelper.cpp (revision 14937) 
@@ 0,0 +1,311 @@ 
+/* 
+For general Scribus (>=1.3.2) copyright and licensing information please refer 
+to the COPYING file provided with the program. Following this notice may exist 
+a copyright and/or license notice that predates the release of Scribus 1.3.2 
+for which a new license (GPL+exception) is in place. 
+*/ 
+ 
+#include "scribushelper.h" 
+ 
+// Functions to convert from lib2geom to FPointArray and vice versa 
+void scribus_curve(FPointArray *cr, Geom::Curve const& c) 
+{ 
+ if(Geom::LineSegment const* line_segment = dynamic_cast<Geom::LineSegment const*>(&c)) 
+ { 
+ cr>addPoint(currentPoint); 
+ cr>addPoint(currentPoint); 
+ cr>addPoint((*line_segment)[1][0], (*line_segment)[1][1]); 
+ cr>addPoint((*line_segment)[1][0], (*line_segment)[1][1]); 
+ currentPoint = FPoint((*line_segment)[1][0], (*line_segment)[1][1]); 
+ } 
+ else if(Geom::QuadraticBezier const *quadratic_bezier = dynamic_cast<Geom::QuadraticBezier const*>(&c)) 
+ { 
+ std::vector<Geom::Point> points = quadratic_bezier>points(); 
+ Geom::Point b1 = points[0] + (2./3) * (points[1]  points[0]); 
+ Geom::Point b2 = b1 + (1./3) * (points[2]  points[0]); 
+ cr>addPoint(currentPoint); 
+ cr>addPoint(b1[0], b1[1]); 
+ cr>addPoint(points[2][0], points[2][1]); 
+ cr>addPoint(b2[0], b2[1]); 
+ currentPoint = FPoint(points[2][0], points[2][1]); 
+ } 
+ else if(Geom::CubicBezier const *cubic_bezier = dynamic_cast<Geom::CubicBezier const*>(&c)) 
+ { 
+ std::vector<Geom::Point> points = cubic_bezier>points(); 
+ cr>addPoint(currentPoint); 
+ cr>addPoint(points[1][0], points[1][1]); 
+ cr>addPoint(points[3][0], points[3][1]); 
+ cr>addPoint(points[2][0], points[2][1]); 
+ currentPoint = FPoint(points[3][0], points[3][1]); 
+ } 
+ else 
+ { 
+ //this case handles sbasis as well as all other curve types 
+ Geom::Path sbasis_path = Geom::path_from_sbasis(c.toSBasis(), 0.1); 
+ currentPoint = FPoint(sbasis_path.initialPoint()[0], sbasis_path.initialPoint()[1]); 
+ //recurse to convert the new path resulting from the sbasis to svgd 
+ for(Geom::Path::iterator iter = sbasis_path.begin(); iter != sbasis_path.end(); ++iter) 
+ { 
+ scribus_curve(cr, *iter); 
+ } 
+ } 
+} 
+ 
+void geomPath2FPointArray(FPointArray *p, Geom::Path &pp) 
+{ 
+ currentPoint = FPoint(pp.initialPoint()[0], pp.initialPoint()[1]); 
+ for(Geom::Path::iterator iter(pp.begin()), end(pp.end()); iter != end; ++iter) 
+ { 
+ scribus_curve(p, *iter); 
+ } 
+ if (pp.closed()) 
+ p>setMarker(); 
+} 
+ 
+void Piecewise2FPointArray(FPointArray *p, Geom::Piecewise<Geom::D2<Geom::SBasis> > &pp) 
+{ 
+ std::vector<Geom::Path> pa = path_from_piecewise( pp, 0.1); 
+ std::vector<Geom::Path>::iterator it(pa.begin()); 
+ for(; it != pa.end(); it++) 
+ { 
+ geomPath2FPointArray(p, *it); 
+ } 
+} 
+ 
+void D2sb2d2FPointArray(FPointArray* cr, Geom::D2<Geom::SBasis2d> const &sb2, int num, double width) 
+{ 
+ Geom::D2<Geom::SBasis> B; 
+ for(int ui = 0; ui <= num; ui++) 
+ { 
+ double u = ui / static_cast<double>(num); 
+ B[0] = extract_u(sb2[0], u);// + Linear(u); 
+ B[1] = extract_u(sb2[1], u); 
+ for(unsigned i = 0; i < 2; i ++) 
+ { 
+ B[i] = B[i]*(width/2) + Geom::Linear(width/4); 
+ } 
+ Geom::Path pp = path_from_sbasis(B, 0.1); 
+ geomPath2FPointArray(cr, pp); 
+ cr>setMarker(); 
+ } 
+ for(int vi = 0; vi <= num; vi++) 
+ { 
+ double v = vi / static_cast<double>(num); 
+ B[1] = extract_v(sb2[1], v);// + Linear(v); 
+ B[0] = extract_v(sb2[0], v); 
+ for(unsigned i = 0; i < 2; i ++) 
+ { 
+ B[i] = B[i]*(width/2) + Geom::Linear(width/4); 
+ } 
+ Geom::Path pp = path_from_sbasis(B, 0.1); 
+ geomPath2FPointArray(cr, pp); 
+ cr>setMarker(); 
+ } 
+} 
+ 
+std::vector<Geom::Path> FPointArray2geomPath(FPointArray &p, bool closed) 
+{ 
+ std::vector<Geom::Path> pa; 
+ Geom::Path ret = Geom::Path(); 
+ Geom::Point cur; 
+ FPoint np, np1, np2, np3; 
+ bool nPath = true; 
+ if (p.size() > 3) 
+ { 
+ for (uint poi=0; poi < p.size()3; poi += 4) 
+ { 
+ if (p.point(poi).x() > 900000) 
+ { 
+ if (closed) 
+ ret.close(); 
+ pa.push_back(ret); 
+ ret.clear(); 
+ nPath = true; 
+ continue; 
+ } 
+ if (nPath) 
+ { 
+ np = p.point(poi); 
+ cur = Geom::Point(np.x(), np.y()); 
+ nPath = false; 
+ } 
+ np = p.point(poi); 
+ np1 = p.point(poi+1); 
+ np2 = p.point(poi+3); 
+ np3 = p.point(poi+2); 
+ if ((np == np1) && (np2 == np3)) 
+ { 
+ // Geom::Point pe = Geom::Point(np3.x(), np3.y()); 
+ // ret.append(Geom::LineSegment(cur, pe)); 
+ Geom::Point pc1 = Geom::Point(np1.x()+0.001, np1.y()+0.001); 
+ Geom::Point pc2 = Geom::Point(np2.x()+0.001, np2.y()+0.001); 
+ Geom::Point pe = Geom::Point(np3.x(), np3.y()); 
+ ret.append(Geom::CubicBezier(cur, pc1, pc2, pe)); 
+ cur = pe; 
+ } 
+ else 
+ { 
+ Geom::Point pc1 = Geom::Point(np1.x(), np1.y()); 
+ Geom::Point pc2 = Geom::Point(np2.x(), np2.y()); 
+ Geom::Point pe = Geom::Point(np3.x(), np3.y()); 
+ ret.append(Geom::CubicBezier(cur, pc1, pc2, pe)); 
+ cur = pe; 
+ } 
+ } 
+ } 
+ if (closed) 
+ ret.close(); 
+ pa.push_back(ret); 
+ return pa; 
+} 
+ 
+Geom::Piecewise<Geom::D2<Geom::SBasis> > FPointArray2Piecewise(FPointArray &p, bool closed) 
+{ 
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > patternpwd2; 
+ std::vector<Geom::Path> originald = FPointArray2geomPath(p, closed); 
+ for (unsigned int i=0; i < originald.size(); i++) 
+ { 
+ patternpwd2.concat( originald[i].toPwSb() ); 
+ } 
+ return patternpwd2; 
+} 
+ 
+// Functions to convert from lib2geom to QPainterPath and vice versa 
+void arthur_curve(QPainterPath *cr, Geom::Curve const& c) 
+{ 
+ if(Geom::LineSegment const* line_segment = dynamic_cast<Geom::LineSegment const*>(&c)) 
+ { 
+ cr>lineTo(QPointF((*line_segment)[1][0], (*line_segment)[1][1])); 
+ } 
+ else if(Geom::QuadraticBezier const *quadratic_bezier = dynamic_cast<Geom::QuadraticBezier const*>(&c)) 
+ { 
+ std::vector<Geom::Point> points = quadratic_bezier>points(); 
+ Geom::Point b1 = points[0] + (2./3) * (points[1]  points[0]); 
+ Geom::Point b2 = b1 + (1./3) * (points[2]  points[0]); 
+ cr>cubicTo(b1[0], b1[1], b2[0], b2[1], points[2][0], points[2][1]); 
+ } 
+ else if(Geom::CubicBezier const *cubic_bezier = dynamic_cast<Geom::CubicBezier const*>(&c)) 
+ { 
+ std::vector<Geom::Point> points = cubic_bezier>points(); 
+ cr>cubicTo(points[1][0], points[1][1], points[2][0], points[2][1], points[3][0], points[3][1]); 
+ } 
+ else 
+ { 
+ //this case handles sbasis as well as all other curve types 
+ Geom::Path sbasis_path = Geom::path_from_sbasis(c.toSBasis(), 0.1); 
+ cr>moveTo(sbasis_path.initialPoint()[0], sbasis_path.initialPoint()[1]); 
+ //recurse to convert the new path resulting from the sbasis to svgd 
+ for(Geom::Path::iterator iter = sbasis_path.begin(); iter != sbasis_path.end(); ++iter) 
+ { 
+ arthur_curve(cr, *iter); 
+ } 
+ } 
+} 
+ 
+void geomPath2QPainterPath(QPainterPath *p, Geom::Path &pp) 
+{ 
+ p>moveTo(pp.initialPoint()[0], pp.initialPoint()[1]); 
+ for(Geom::Path::iterator iter(pp.begin()), end(pp.end()); iter != end; ++iter) 
+ { 
+ arthur_curve(p, *iter); 
+ } 
+ if (pp.closed()) 
+ p>closeSubpath(); 
+} 
+ 
+void Piecewise2QPainterPath(QPainterPath *p, Geom::Piecewise<Geom::D2<Geom::SBasis> > &pp) 
+{ 
+ std::vector<Geom::Path> pa = path_from_piecewise( pp, 0.1); 
+ std::vector<Geom::Path>::iterator it(pa.begin()); 
+ for(; it != pa.end(); it++) 
+ { 
+ geomPath2QPainterPath(p, *it); 
+ } 
+} 
+ 
+void D2sb2d2QPainterPath(QPainterPath* cr, Geom::D2<Geom::SBasis2d> const &sb2, int num, double width) 
+{ 
+ Geom::D2<Geom::SBasis> B; 
+ for(int ui = 0; ui <= num; ui++) 
+ { 
+ double u = ui / static_cast<double>(num); 
+ B[0] = extract_u(sb2[0], u);// + Linear(u); 
+ B[1] = extract_u(sb2[1], u); 
+ for(unsigned i = 0; i < 2; i ++) 
+ { 
+ B[i] = B[i]*(width/2) + Geom::Linear(width/4); 
+ } 
+ Geom::Path pp = path_from_sbasis(B, 0.1); 
+ geomPath2QPainterPath(cr, pp); 
+// cr>setMarker(); 
+ } 
+ for(int vi = 0; vi <= num; vi++) 
+ { 
+ double v = vi / static_cast<double>(num); 
+ B[1] = extract_v(sb2[1], v);// + Linear(v); 
+ B[0] = extract_v(sb2[0], v); 
+ for(unsigned i = 0; i < 2; i ++) 
+ { 
+ B[i] = B[i]*(width/2) + Geom::Linear(width/4); 
+ } 
+ Geom::Path pp = path_from_sbasis(B, 0.1); 
+ geomPath2QPainterPath(cr, pp); 
+// cr>setMarker(); 
+ } 
+} 
+ 
+std::vector<Geom::Path> QPainterPath2geomPath(QPainterPath &p, bool closed) 
+{ 
+ std::vector<Geom::Path> pa; 
+ Geom::Path ret = Geom::Path(); 
+ Geom::Point cur; 
+ bool WasM = false; 
+ for (int i = 0; i < p.elementCount(); ++i) 
+ { 
+ const QPainterPath::Element &elm = p.elementAt(i); 
+ switch (elm.type) 
+ { 
+ case QPainterPath::MoveToElement: 
+ if (WasM) 
+ { 
+ if (closed) 
+ ret.close(); 
+ pa.push_back(ret); 
+ ret.clear(); 
+ } 
+ WasM = true; 
+ cur = Geom::Point(elm.x, elm.y); 
+ break; 
+ case QPainterPath::LineToElement: 
+ ret.append(Geom::LineSegment(cur, Geom::Point(elm.x, elm.y))); 
+ cur = Geom::Point(elm.x, elm.y); 
+ break; 
+ case QPainterPath::CurveToElement: 
+ { 
+ Geom::Point pc1 = Geom::Point(elm.x, elm.y); 
+ Geom::Point pc2 = Geom::Point(p.elementAt(i+1).x, p.elementAt(i+1).y); 
+ Geom::Point pe = Geom::Point(p.elementAt(i+2).x, p.elementAt(i+2).y); 
+ ret.append(Geom::CubicBezier(cur, pc1, pc2, pe)); 
+ cur = pe; 
+ } 
+ break; 
+ default: 
+ break; 
+ } 
+ } 
+ if (closed) 
+ ret.close(); 
+ pa.push_back(ret); 
+ return pa; 
+} 
+ 
+Geom::Piecewise<Geom::D2<Geom::SBasis> > QPainterPath2Piecewise(QPainterPath &p, bool closed) 
+{ 
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > patternpwd2; 
+ std::vector<Geom::Path> originald = QPainterPath2geomPath(p, closed); 
+ for (unsigned int i=0; i < originald.size(); i++) 
+ { 
+ patternpwd2.concat( originald[i].toPwSb() ); 
+ } 
+ return patternpwd2; 
+} 
Index: Scribus/scribus/third_party/lib2geom/path.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/path.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/path.h (revision 14937) 
@@ 0,0 +1,821 @@ 
+/* 
+ * Path  Series of continuous curves 
+ * 
+ * Copyright 2007 MenTaLguY <mental@rydia.net> 
+ * 
+ * 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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_PATH_H 
+#define SEEN_GEOM_PATH_H 
+ 
+#include "point.h" 
+#include <iterator> 
+#include <algorithm> 
+#include "exception.h" 
+#include "d2.h" 
+#include "matrix.h" 
+#include "bezier.h" 
+#include "crossing.h" 
+#include "utils.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 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); } 
+ 
+ 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(1, 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(); 
+ } 
+ 
+ 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<order1>(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]; 
+ if(dx == 0) return new BezierCurve<1>(Point(0,0), Point(0,0)); 
+ double slope = dy / dx; 
+ Geom::Point pnt; 
+ if(slope == 0) pnt = Geom::Point(0, 0); else pnt = Geom::Point(slope, 1./slope); 
+ return new BezierCurve<1>(pnt, pnt); 
+ } 
+ } 
+ 
+ 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; 
+ 
+class SVGEllipticalArc : public Curve { 
+public: 
+ SVGEllipticalArc() {} 
+ 
+ SVGEllipticalArc(Point initial, double rx, double ry, 
+ double x_axis_rotation, bool large_arc, 
+ bool sweep, Point final) 
+ : initial_(initial), rx_(rx), ry_(ry), x_axis_rotation_(x_axis_rotation), 
+ large_arc_(large_arc), sweep_(sweep), final_(final) 
+ {} 
+ 
+ Curve *duplicate() const { return new SVGEllipticalArc(*this); } 
+ 
+ Point initialPoint() const { return initial_; } 
+ Point finalPoint() const { return final_; } 
+ 
+ void setInitial(Point v) { initial_ = v; } 
+ void setFinal(Point v) { final_ = v; } 
+ 
+ //TODO: implement funcs 
+ 
+ bool isDegenerate() const { return toSBasis().isConstant(); } 
+ Rect boundsFast() const; 
+ Rect boundsExact() const; 
+ Rect boundsLocal(Interval i, unsigned deg) const; 
+ 
+ int winding(Point p) const { 
+ return SBasisCurve(toSBasis()).winding(p); 
+ } 
+ 
+ std::vector<double> roots(double v, Dim2 d) const; 
+ 
+ inline std::pair<SVGEllipticalArc, SVGEllipticalArc> 
+ subdivide(Coord t) { 
+ SVGEllipticalArc a(*this), b(*this); 
+ a.final_ = b.initial_ = pointAt(t); 
+ return std::pair<SVGEllipticalArc, SVGEllipticalArc>(a, b); 
+ } 
+ 
+// TODO: how are the flags affected by reducing an arc from more than 180deg to less than 180deg? 
+ Curve *portion(double f, double t) const { 
+ SVGEllipticalArc *ret = new SVGEllipticalArc (*this); 
+ ret>initial_ = pointAt(f); 
+ ret>final_ = pointAt(t); 
+ return ret; 
+ } 
+ 
+// TODO: incomplete/buggy 
+ Curve *reverse(double /*f*/, double /*t*/) const { 
+ SVGEllipticalArc *ret = new SVGEllipticalArc (*this); 
+ ret>initial_ = final_; 
+ ret>final_ = initial_; 
+ return ret; 
+ } 
+ 
+ //TODO: this next def isn't right 
+ Curve *transformed(Matrix const & m) const { 
+ SVGEllipticalArc *ret = new SVGEllipticalArc (*this); 
+ ret>initial_ = initial_ * m; 
+ ret>final_ = final_ * m; 
+ return ret; 
+ } 
+ 
+ Curve *derivative() const { throwNotImplemented(0); } 
+ 
+ std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const; 
+ 
+ D2<SBasis> toSBasis() const; 
+ 
+private: 
+ Point initial_; 
+ double rx_; 
+ double ry_; 
+ double x_axis_rotation_; 
+ bool large_arc_; 
+ bool sweep_; 
+ Point final_; 
+}; 
+ 
+template <typename IteratorImpl> 
+class BaseIterator 
+: public std::iterator<std::forward_iterator_tag, Curve const> 
+{ 
+public: 
+ BaseIterator() {} 
+ 
+ // default construct 
+ // default copy 
+ 
+ bool operator==(BaseIterator const &other) { 
+ return other.impl_ == impl_; 
+ } 
+ bool operator!=(BaseIterator const &other) { 
+ return other.impl_ != impl_; 
+ } 
+ 
+ Curve const &operator*() const { return **impl_; } 
+ Curve const *operator>() const { return *impl_; } 
+ 
+ BaseIterator &operator++() { 
+ ++impl_; 
+ return *this; 
+ } 
+ 
+ BaseIterator operator++(int) { 
+ BaseIterator old=*this; 
+ ++(*this); 
+ return old; 
+ } 
+ 
+private: 
+ BaseIterator(IteratorImpl const &pos) : impl_(pos) {} 
+ 
+ IteratorImpl impl_; 
+ friend class Path; 
+}; 
+ 
+template <typename Iterator> 
+class DuplicatingIterator 
+: public std::iterator<std::input_iterator_tag, Curve *> 
+{ 
+public: 
+ DuplicatingIterator() {} 
+ DuplicatingIterator(Iterator const &iter) : impl_(iter) {} 
+ 
+ bool operator==(DuplicatingIterator const &other) { 
+ return other.impl_ == impl_; 
+ } 
+ bool operator!=(DuplicatingIterator const &other) { 
+ return other.impl_ != impl_; 
+ } 
+ 
+ Curve *operator*() const { return (*impl_)>duplicate(); } 
+ 
+ DuplicatingIterator &operator++() { 
+ ++impl_; 
+ return *this; 
+ } 
+ DuplicatingIterator operator++(int) { 
+ DuplicatingIterator old=*this; 
+ ++(*this); 
+ return old; 
+ } 
+ 
+private: 
+ Iterator impl_; 
+}; 
+ 
+class Path { 
+private: 
+ typedef std::vector<Curve *> Sequence; 
+ 
+public: 
+ typedef BaseIterator<Sequence::iterator> iterator; 
+ typedef BaseIterator<Sequence::const_iterator> const_iterator; 
+ typedef Sequence::size_type size_type; 
+ typedef Sequence::difference_type difference_type; 
+ 
+ Path() 
+ : final_(new LineSegment()), closed_(false) 
+ { 
+ curves_.push_back(final_); 
+ } 
+ 
+ Path(Path const &other) 
+ : final_(new LineSegment()), closed_(other.closed_) 
+ { 
+ curves_.push_back(final_); 
+ insert(begin(), other.begin(), other.end()); 
+ } 
+ 
+ explicit Path(Point p) 
+ : final_(new LineSegment(p, p)), closed_(false) 
+ { 
+ curves_.push_back(final_); 
+ } 
+ 
+ template <typename Impl> 
+ Path(BaseIterator<Impl> first, BaseIterator<Impl> last, bool closed=false) 
+ : closed_(closed), final_(new LineSegment()) 
+ { 
+ curves_.push_back(final_); 
+ insert(begin(), first, last); 
+ } 
+ 
+ virtual ~Path() { 
+ delete_range(curves_.begin(), curves_.end()1); 
+ delete final_; 
+ } 
+ 
+ Path &operator=(Path const &other) { 
+ clear(); 
+ insert(begin(), other.begin(), other.end()); 
+ close(other.closed_); 
+ return *this; 
+ } 
+ 
+ void swap(Path &other); 
+ 
+ Curve const &operator[](unsigned i) const { return *curves_[i]; } 
+ 
+ iterator begin() { return curves_.begin(); } 
+ iterator end() { return curves_.end()1; } 
+ 
+ Curve const &front() const { return *curves_[0]; } 
+ Curve const &back() const { return *curves_[curves_.size()2]; } 
+ 
+ const_iterator begin() const { return curves_.begin(); } 
+ const_iterator end() const { return curves_.end()1; } 
+ 
+ const_iterator end_open() const { return curves_.end()1; } 
+ const_iterator end_closed() const { return curves_.end(); } 
+ const_iterator end_default() const { 
+ return ( closed_ ? end_closed() : end_open() ); 
+ } 
+ 
+ size_type size() const { return curves_.size()1; } 
+ size_type max_size() const { return curves_.max_size()1; } 
+ 
+ bool empty() const { return curves_.size() == 1; } 
+ bool closed() const { return closed_; } 
+ void close(bool closed=true) { closed_ = closed; } 
+ 
+ Rect boundsFast() const; 
+ Rect boundsExact() const; 
+ 
+ Piecewise<D2<SBasis> > toPwSb() const { 
+ Piecewise<D2<SBasis> > ret; 
+ ret.push_cut(0); 
+ unsigned i = 1; 
+ // ignore that path is closed or open. pw<d2<>> is always open. 
+ for(const_iterator it = begin(); it != end(); ++it) { 
+ if (!it>isDegenerate()) { 
+ ret.push(it>toSBasis(), i++); 
+ } 
+ } 
+ return ret; 
+ } 
+ 
+ Path operator*(Matrix const &m) const { 
+ Path ret; 
+ for(const_iterator it = begin(); it != end(); ++it) { 
+ Curve *temp = it>transformed(m); 
+ //Possible point of discontinuity? 
+ ret.append(*temp); 
+ delete temp; 
+ } 
+ return ret; 
+ } 
+ 
+ Point pointAt(double t) const { 
+ if(empty()) return Point(0,0); 
+ double i, f = modf(t, &i); 
+ if(i == size() && f == 0) { i; } 
+ assert(i >= 0 && i <= size()); 
+ return (*this)[unsigned(i)].pointAt(f); 
+ } 
+ 
+ double valueAt(double t, Dim2 d) const { 
+ if(empty()) return 0; 
+ double i, f = modf(t, &i); 
+ if(i == size() && f == 0) { i; } 
+ assert(i >= 0 && i <= size()); 
+ return (*this)[unsigned(i)].valueAt(f, d); 
+ } 
+ 
+ std::vector<double> roots(double v, Dim2 d) const { 
+ std::vector<double> res; 
+ for(unsigned i = 0; i <= size(); i++) { 
+ std::vector<double> temp = (*this)[i].roots(v, d); 
+ for(unsigned j = 0; j < temp.size(); j++) 
+ res.push_back(temp[j] + i); 
+ } 
+ return res; 
+ } 
+ 
+ void appendPortionTo(Path &p, double f, double t) const; 
+ 
+ Path portion(double f, double t) const { 
+ Path ret; 
+ ret.close(false); 
+ appendPortionTo(ret, f, t); 
+ return ret; 
+ } 
+ Path portion(Interval i) const { return portion(i.min(), i.max()); } 
+ 
+ Path reverse() const { 
+ Path ret; 
+ ret.close(closed_); 
+ for(int i = size()  (closed_ ? 0 : 1); i >= 0; i) { 
+ //TODO: do we really delete? 
+ Curve *temp = (*this)[i].reverse(); 
+ ret.append(*temp); 
+ delete temp; 
+ } 
+ return ret; 
+ } 
+ 
+ void insert(iterator pos, Curve const &curve) { 
+ Sequence source(1, curve.duplicate()); 
+ try { 
+ do_update(pos.impl_, pos.impl_, source.begin(), source.end()); 
+ } catch (...) { 
+ delete_range(source.begin(), source.end()); 
+ throw; 
+ } 
+ } 
+ 
+ template <typename Impl> 
+ void insert(iterator pos, BaseIterator<Impl> first, BaseIterator<Impl> last) 
+ { 
+ Sequence source(DuplicatingIterator<Impl>(first.impl_), 
+ DuplicatingIterator<Impl>(last.impl_)); 
+ try { 
+ do_update(pos.impl_, pos.impl_, source.begin(), source.end()); 
+ } catch (...) { 
+ delete_range(source.begin(), source.end()); 
+ throw; 
+ } 
+ } 
+ 
+ void clear() { 
+ do_update(curves_.begin(), curves_.end()1, 
+ curves_.begin(), curves_.begin()); 
+ } 
+ 
+ void erase(iterator pos) { 
+ do_update(pos.impl_, pos.impl_+1, curves_.begin(), curves_.begin()); 
+ } 
+ 
+ void erase(iterator first, iterator last) { 
+ do_update(first.impl_, last.impl_, curves_.begin(), curves_.begin()); 
+ } 
+ 
+ void replace(iterator replaced, Curve const &curve) { 
+ Sequence source(1, curve.duplicate()); 
+ try { 
+ do_update(replaced.impl_, replaced.impl_+1, source.begin(), source.end()); 
+ } catch (...) { 
+ delete_range(source.begin(), source.end()); 
+ throw; 
+ } 
+ } 
+ 
+ void replace(iterator first_replaced, iterator last_replaced, 
+ Curve const &curve) 
+ { 
+ Sequence source(1, curve.duplicate()); 
+ try { 
+ do_update(first_replaced.impl_, last_replaced.impl_, 
+ source.begin(), source.end()); 
+ } catch (...) { 
+ delete_range(source.begin(), source.end()); 
+ throw; 
+ } 
+ } 
+ 
+ template <typename Impl> 
+ void replace(iterator replaced, 
+ BaseIterator<Impl> first, BaseIterator<Impl> last) 
+ { 
+ Sequence source(DuplicatingIterator<Impl>(first.impl_), 
+ DuplicatingIterator<Impl>(last.impl_)); 
+ try { 
+ do_update(replaced.impl_, replaced.impl_+1, source.begin(), source.end()); 
+ } catch (...) { 
+ delete_range(source.begin(), source.end()); 
+ throw; 
+ } 
+ } 
+ 
+ template <typename Impl> 
+ void replace(iterator first_replaced, iterator last_replaced, 
+ BaseIterator<Impl> first, BaseIterator<Impl> last) 
+ { 
+ Sequence source(first.impl_, last.impl_); 
+ try { 
+ do_update(first_replaced.impl_, last_replaced.impl_, 
+ source.begin(), source.end()); 
+ } catch (...) { 
+ delete_range(source.begin(), source.end()); 
+ throw; 
+ } 
+ } 
+ 
+ void start(Point p) { 
+ clear(); 
+ final_>setPoint(0, p); 
+ final_>setPoint(1, p); 
+ } 
+ 
+ Point initialPoint() const { return (*final_)[1]; } 
+ Point finalPoint() const { return (*final_)[0]; } 
+ 
+ void append(Curve const &curve); 
+ void append(D2<SBasis> const &curve); 
+ 
+ template <typename CurveType, typename A> 
+ void appendNew(A a) { 
+ do_append(new CurveType((*final_)[0], a)); 
+ } 
+ 
+ template <typename CurveType, typename A, typename B> 
+ void appendNew(A a, B b) { 
+ do_append(new CurveType((*final_)[0], a, b)); 
+ } 
+ 
+ template <typename CurveType, typename A, typename B, typename C> 
+ void appendNew(A a, B b, C c) { 
+ do_append(new CurveType((*final_)[0], a, b, c)); 
+ } 
+ 
+ template <typename CurveType, typename A, typename B, typename C, 
+ typename D> 
+ void appendNew(A a, B b, C c, D d) { 
+ do_append(new CurveType((*final_)[0], a, b, c, d)); 
+ } 
+ 
+ template <typename CurveType, typename A, typename B, typename C, 
+ typename D, typename E> 
+ void appendNew(A a, B b, C c, D d, E e) { 
+ do_append(new CurveType((*final_)[0], a, b, c, d, e)); 
+ } 
+ 
+ template <typename CurveType, typename A, typename B, typename C, 
+ typename D, typename E, typename F> 
+ void appendNew(A a, B b, C c, D d, E e, F f) { 
+ do_append(new CurveType((*final_)[0], a, b, c, d, e, f)); 
+ } 
+ 
+ template <typename CurveType, typename A, typename B, typename C, 
+ typename D, typename E, typename F, 
+ typename G> 
+ void appendNew(A a, B b, C c, D d, E e, F f, G g) { 
+ do_append(new CurveType((*final_)[0], a, b, c, d, e, f, g)); 
+ } 
+ 
+ template <typename CurveType, typename A, typename B, typename C, 
+ typename D, typename E, typename F, 
+ typename G, typename H> 
+ void appendNew(A a, B b, C c, D d, E e, F f, G g, H h) { 
+ do_append(new CurveType((*final_)[0], a, b, c, d, e, f, g, h)); 
+ } 
+ 
+ template <typename CurveType, typename A, typename B, typename C, 
+ typename D, typename E, typename F, 
+ typename G, typename H, typename I> 
+ void appendNew(A a, B b, C c, D d, E e, F f, G g, H h, I i) { 
+ do_append(new CurveType((*final_)[0], a, b, c, d, e, f, g, h, i)); 
+ } 
+ 
+private: 
+ void do_update(Sequence::iterator first_replaced, 
+ Sequence::iterator last_replaced, 
+ Sequence::iterator first, 
+ Sequence::iterator last); 
+ 
+ void do_append(Curve *curve); 
+ 
+ void delete_range(Sequence::iterator first, Sequence::iterator last); 
+ 
+ void check_continuity(Sequence::iterator first_replaced, 
+ Sequence::iterator last_replaced, 
+ Sequence::iterator first, 
+ Sequence::iterator last); 
+ 
+ Sequence curves_; 
+ LineSegment *final_; 
+ bool closed_; 
+}; 
+ 
+inline static Piecewise<D2<SBasis> > paths_to_pw(std::vector<Path> paths) { 
+ Piecewise<D2<SBasis> > ret = paths[0].toPwSb(); 
+ for(unsigned i = 1; i < paths.size(); i++) { 
+ ret.concat(paths[i].toPwSb()); 
+ } 
+ return ret; 
+} 
+ 
+/* 
+class PathPortion : public Curve { 
+ Path *source; 
+ double f, t; 
+ boost::optional<Path> result; 
+ 
+ public: 
+ double from() const { return f; } 
+ double to() const { return t; } 
+ 
+ explicit PathPortion(Path *s, double fp, double tp) : source(s), f(fp), t(tp) {} 
+ Curve *duplicate() const { return new PathPortion(*this); } 
+ 
+ Point initialPoint() const { return source>pointAt(f); } 
+ Point finalPoint() const { return source>pointAt(t); } 
+ 
+ Path actualPath() { 
+ if(!result) *result = source>portion(f, t); 
+ return *result; 
+ } 
+ 
+ Rect boundsFast() const { return actualPath().boundsFast; } 
+ Rect boundsExact() const { return actualPath().boundsFast; } 
+ Rect boundsLocal(Interval i) const { throwNotImplemented(); } 
+ 
+ std::vector<double> roots(double v, Dim2 d) const = 0; 
+ 
+ virtual int winding(Point p) const { return root_winding(*this, p); } 
+ 
+ virtual Curve *portion(double f, double t) const = 0; 
+ virtual Curve *reverse() const { return portion(1, 0); } 
+ 
+ virtual Crossings crossingsWith(Curve const & other) const; 
+ 
+ virtual void setInitial(Point v) = 0; 
+ virtual void setFinal(Point v) = 0; 
+ 
+ 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; 
+ 
+}; 
+*/ 
+ 
+} 
+ 
+namespace std { 
+ 
+template <> 
+inline void swap<Geom::Path>(Geom::Path &a, Geom::Path &b) 
+{ 
+ a.swap(b); 
+} 
+ 
+} 
+ 
+#endif // SEEN_GEOM_PATH_H 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(substatementopen . 0)) 
+ indenttabsmode:nil 
+ cbraceoffset:0 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=2:tabstop=8:softtabstop=2 : 
Index: Scribus/scribus/third_party/lib2geom/polylaguerresolve.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/polylaguerresolve.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/polylaguerresolve.cpp (revision 14937) 
@@ 0,0 +1,151 @@ 
+#include "polylaguerresolve.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 *= 1e7; // 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*HG*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*HG*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) { 
+ std::vector<double > solutions; 
+ return solutions; 
+} 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/sweep.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/sweep.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/sweep.cpp (revision 14937) 
@@ 0,0 +1,105 @@ 
+#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(); 
+ unsigned i[2] = {0}; 
+ while( 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: Scribus/scribus/third_party/lib2geom/sbasis.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/sbasis.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/sbasis.cpp (revision 14937) 
@@ 0,0 +1,492 @@ 
+/* 
+ * sbasis.cpp  Spower basis function class + supporting classes 
+ * 
+ * Authors: 
+ * Nathan Hurst <njh@mail.csse.monash.edu.au> 
+ * Michael Sloan <mgsloan@gmail.com> 
+ * 
+ * Copyright (C) 20062007 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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" 
+#include "angle.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; 
+} 
+*/ 
+ 
+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[ij]); 
+ 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[ij][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[k1])/(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 && 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 = (1u)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 = (1u)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], 1a[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./(1a[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 << "1a=" << 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*q01p01*q10; 
+ 
+ //TODO: handle det~0!! 
+ if (fabs(det)<zero){ 
+ det = zero; 
+ a=b=0; 
+ }else{ 
+ a=( q01*r10q10*r01)/det; 
+ b=(p01*r10+p10*r01)/det; 
+ } 
+ result.push_back(Linear(a,b)); 
+ r=rPk*aQk*b; 
+ 
+ Pk=Pk*sg; 
+ Qk=Qk*sg; 
+ Pk.truncate(order); 
+ Qk.truncate(order); 
+ r.truncate(order); 
+ } 
+ result.normalize(); 
+ return result; 
+} 
+ 
+} 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/angle.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/angle.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/angle.h (revision 14937) 
@@ 0,0 +1,53 @@ 
+/** 
+ * \file angle.h 
+ * \brief Various trigoniometric helper functions 
+ * 
+ * Authors: 
+ * Johan Engelen <goejendaagh@zonnet.nl> 
+ * 
+ * Copyright (C) 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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 LIB2GEOM_SEEN_ANGLE_H 
+#define LIB2GEOM_SEEN_ANGLE_H 
+ 
+namespace Geom { 
+ 
+#ifndef M_PI 
+# define M_PI 3.14159265358979323846 
+#endif 
+#ifndef M_PI_2 
+# define M_PI_2 ( M_PI / 2) 
+#endif 
+ 
+inline double deg_to_rad(double deg) { return deg*M_PI/180.0;} 
+ 
+inline double rad_to_deg(double rad) { return rad*180.0/M_PI;} 
+ 
+} 
+ 
+#endif 
Index: Scribus/scribus/third_party/lib2geom/solvebezierparametric.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/solvebezierparametric.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/solvebezierparametric.cpp (revision 14937) 
@@ 0,0 +1,232 @@ 
+#include "solver.h" 
+#include "point.h" 
+#include <algorithm> 
+ 
+namespace Geom{ 
+ 
+/*** Find the zeros of the parametric function in 2d defined by two beziers X(t), Y(t). The code subdivides until it happy with the linearity of the bezier. This requires an n^2 subdivision for each step, even when there is only one solution. 
+ * 
+ * Perhaps it would be better to subdivide particularly around nodes with changing sign, rather than simply cutting in half. 
+ */ 
+ 
+#define SGN(a) (((a)<0) ? 1 : 1) 
+ 
+/* 
+ * Forward declarations 
+ */ 
+static Geom::Point 
+Bezier(Geom::Point const *V, 
+ unsigned degree, 
+ double t, 
+ Geom::Point *Left, 
+ Geom::Point *Right); 
+ 
+unsigned 
+crossing_count(Geom::Point const *V, unsigned degree); 
+static unsigned 
+control_poly_flat_enough(Geom::Point const *V, unsigned degree); 
+static double 
+compute_x_intercept(Geom::Point const *V, unsigned degree); 
+ 
+const unsigned MAXDEPTH = 64; /* Maximum depth for recursion */ 
+ 
+const double BEPSILON = ldexp(1.0,((signed)1)MAXDEPTH); /*Flatness control value */ 
+ 
+unsigned total_steps, total_subs; 
+ 
+/* 
+ * find_bezier_roots : Given an equation in BernsteinBezier form, find all 
+ * of the roots in the interval [0, 1]. Return the number of roots found. 
+ */ 
+void 
+find_parametric_bezier_roots(Geom::Point const *w, /* The control points */ 
+ unsigned degree, /* The degree of the polynomial */ 
+ std::vector<double> &solutions, /* RETURN candidate tvalues */ 
+ unsigned depth) /* The depth of the recursion */ 
+{ 
+ total_steps++; 
+ const unsigned max_crossings = crossing_count(w, degree); 
+ switch (max_crossings) { 
+ case 0: /* No solutions here */ 
+ return; 
+ 
+ case 1: 
+ /* Unique solution */ 
+ /* Stop recursion when the tree is deep enough */ 
+ /* if deep enough, return 1 solution at midpoint */ 
+ if (depth >= MAXDEPTH) { 
+ solutions.push_back((w[0][Geom::X] + w[degree][Geom::X]) / 2.0); 
+ return; 
+ } 
+ 
+ // I thought secant method would be faster here, but it'aint.  njh 
+ 
+ if (control_poly_flat_enough(w, degree)) { 
+ solutions.push_back(compute_x_intercept(w, degree)); 
+ return; 
+ } 
+ break; 
+ } 
+ 
+ /* Otherwise, solve recursively after subdividing control polygon */ 
+ std::vector<Geom::Point>Left(degree+1); /* New left and right */ 
+ std::vector<Geom::Point>Right(degree+1); /* control polygons */ 
+ Bezier(w, degree, 0.5, &Left[0], &Right[0]); 
+ total_subs ++; 
+ find_parametric_bezier_roots(&Left[0], degree, solutions, depth+1); 
+ find_parametric_bezier_roots(&Right[0], degree, solutions, depth+1); 
+} 
+ 
+ 
+/* 
+ * crossing_count: 
+ * Count the number of times a Bezier control polygon 
+ * crosses the 0axis. This number is >= the number of roots. 
+ * 
+ */ 
+unsigned 
+crossing_count(Geom::Point const *V, /* Control pts of Bezier curve */ 
+ unsigned degree) /* Degree of Bezier curve */ 
+{ 
+ unsigned n_crossings = 0; /* Number of zerocrossings */ 
+ 
+ int old_sign = SGN(V[0][Geom::Y]); 
+ for (unsigned i = 1; i <= degree; i++) { 
+ int sign = SGN(V[i][Geom::Y]); 
+ if (sign != old_sign) 
+ n_crossings++; 
+ old_sign = sign; 
+ } 
+ return n_crossings; 
+} 
+ 
+ 
+ 
+/* 
+ * control_poly_flat_enough : 
+ * Check if the control polygon of a Bezier curve is flat enough 
+ * for recursive subdivision to bottom out. 
+ * 
+ */ 
+static unsigned 
+control_poly_flat_enough(Geom::Point const *V, /* Control points */ 
+ unsigned degree) /* Degree of polynomial */ 
+{ 
+ /* Find the perpendicular distance from each interior control point to line connecting V[0] and 
+ * V[degree] */ 
+ 
+ /* Derive the implicit equation for line connecting first */ 
+ /* and last control points */ 
+ const double a = V[0][Geom::Y]  V[degree][Geom::Y]; 
+ const double b = V[degree][Geom::X]  V[0][Geom::X]; 
+ const double c = V[0][Geom::X] * V[degree][Geom::Y]  V[degree][Geom::X] * V[0][Geom::Y]; 
+ 
+ const double abSquared = (a * a) + (b * b); 
+ 
+ std::vector<double> distance(degree); /* Distances from pts to line */ 
+ for (unsigned i = 1; i < degree; i++) { 
+ /* Compute distance from each of the points to that line */ 
+ double & dist(distance[i1]); 
+ const double d = a * V[i][Geom::X] + b * V[i][Geom::Y] + c; 
+ dist = d*d / abSquared; 
+ if (d < 0.0) 
+ dist = dist; 
+ } 
+ 
+ 
+ // Find the largest distance 
+ double max_distance_above = 0.0; 
+ double max_distance_below = 0.0; 
+ for (unsigned i = 0; i < degree1; i++) { 
+ const double d = distance[i]; 
+ if (d < 0.0) 
+ max_distance_below = std::min(max_distance_below, d); 
+ if (d > 0.0) 
+ max_distance_above = std::max(max_distance_above, d); 
+ } 
+ 
+ const double intercept_1 = (c + max_distance_above) / a; 
+ const double intercept_2 = (c + max_distance_below) / a; 
+ 
+ /* Compute bounding interval*/ 
+ const double left_intercept = std::min(intercept_1, intercept_2); 
+ const double right_intercept = std::max(intercept_1, intercept_2); 
+ 
+ const double error = 0.5 * (right_intercept  left_intercept); 
+ 
+ if (error < BEPSILON) 
+ return 1; 
+ 
+ return 0; 
+} 
+ 
+ 
+ 
+/* 
+ * compute_x_intercept : 
+ * Compute intersection of chord from first control point to last 
+ * with 0axis. 
+ * 
+ */ 
+static double 
+compute_x_intercept(Geom::Point const *V, /* Control points */ 
+ unsigned degree) /* Degree of curve */ 
+{ 
+ const Geom::Point A = V[degree]  V[0]; 
+ 
+ return (A[Geom::X]*V[0][Geom::Y]  A[Geom::Y]*V[0][Geom::X]) / A[Geom::Y]; 
+} 
+ 
+ 
+/* 
+ * Bezier : 
+ * Evaluate a Bezier curve at a particular parameter value 
+ * Fill in control points for resulting subcurves. 
+ * 
+ */ 
+static Geom::Point 
+Bezier(Geom::Point const *V, /* Control pts */ 
+ unsigned degree, /* Degree of bezier curve */ 
+ double t, /* Parameter value */ 
+ Geom::Point *Left, /* RETURN left half ctl pts */ 
+ Geom::Point *Right) /* RETURN right half ctl pts */ 
+{ 
+const unsigned size=degree+1; 
+ std::vector<Geom::Point> vtemp(V,V+size); 
+ 
+ //storing left/right coordinates 
+ std::vector<Geom::Point> nodata(size); 
+ if(Left == NULL)Left=&nodata[0]; 
+ if(Right == NULL)Right=&nodata[0]; 
+ 
+ /* Copy control points */ 
+ Left[0] = vtemp[0]; 
+ Right[degree]= vtemp[degree]; 
+ 
+ /* Triangle computation */ 
+ for (unsigned i = 1; i < size; ++i) { 
+ for (unsigned j = 0; j < size  i; ++j) { 
+ vtemp[j] = lerp(t, vtemp[j], vtemp[j+1]); 
+ } 
+ Left[i] =vtemp[0]; 
+ Right[degreei]=vtemp[degreei]; 
+ } 
+ 
+ return (vtemp[0]); 
+} 
+ 
+}; 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(substatementopen . 0)) 
+ indenttabsmode:nil 
+ cbraceoffset:0 
+ fillcolumn:99 
+ End: 
+ vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : 
+*/ 
+ 
+ 
Index: Scribus/scribus/third_party/lib2geom/solvebezieroned.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/solvebezieroned.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/solvebezieroned.cpp (revision 14937) 
@@ 0,0 +1,198 @@ 
+#include "solver.h" 
+#include "point.h" 
+#include <algorithm> 
+ 
+/*** Find the zeros of the bernstein function. The code subdivides until it is happy with the 
+ * linearity of the function. This requires an O(degree^2) subdivision for each step, even when 
+ * there is only one solution. 
+ */ 
+ 
+namespace Geom{ 
+ 
+template<class t> 
+static int SGN(t x) { return (x > 0 ? 1 : (x < 0 ? 1 : 0)); } 
+ 
+/* 
+ * Forward declarations 
+ */ 
+static void 
+Bernstein(double const *V, 
+ unsigned degree, 
+ double t, 
+ double *Left, 
+ double *Right); 
+ 
+static unsigned 
+control_poly_flat_enough(double const *V, unsigned degree, 
+ double left_t, double right_t); 
+ 
+const unsigned MAXDEPTH = 64; /* Maximum depth for recursion */ 
+ 
+const double BEPSILON = ldexp(1.0,((signed)1)MAXDEPTH); /*Flatness control value */ 
+ 
+/* 
+ * find_bernstein_roots : Given an equation in BernsteinBernstein form, find all 
+ * of the roots in the open interval (0, 1). Return the number of roots found. 
+ */ 
+void 
+find_bernstein_roots(double const *w, /* The control points */ 
+ unsigned degree, /* The degree of the polynomial */ 
+ std::vector<double> &solutions, /* RETURN candidate tvalues */ 
+ unsigned depth, /* The depth of the recursion */ 
+ double left_t, double right_t) 
+{ 
+ unsigned n_crossings = 0; /* Number of zerocrossings */ 
+ 
+ int old_sign = SGN(w[0]); 
+ for (unsigned i = 1; i <= degree; i++) { 
+ int sign = SGN(w[i]); 
+ if (sign) { 
+ if (sign != old_sign && old_sign) { 
+ n_crossings++; 
+ } 
+ old_sign = sign; 
+ } 
+ } 
+ 
+ switch (n_crossings) { 
+ case 0: /* No solutions here */ 
+ return; 
+ 
+ case 1: 
+ /* Unique solution */ 
+ /* Stop recursion when the tree is deep enough */ 
+ /* if deep enough, return 1 solution at midpoint */ 
+ if (depth >= MAXDEPTH) { 
+ solutions.push_back((left_t + right_t) / 2.0); 
+ return; 
+ } 
+ 
+ // I thought secant method would be faster here, but it'aint.  njh 
+ 
+ if (control_poly_flat_enough(w, degree, left_t, right_t)) { 
+ const double Ax = right_t  left_t; 
+ const double Ay = w[degree]  w[0]; 
+ 
+ solutions.push_back(left_t  Ax*w[0] / Ay); 
+ return; 
+ } 
+ break; 
+ } 
+ 
+ /* Otherwise, solve recursively after subdividing control polygon */ 
+ std::vector<double> Left(degree+1); /* New left and right */ 
+ std::vector<double> Right(degree+1);/* control polygons */ 
+ const double split = 0.5; 
+ Bernstein(w, degree, split, &Left[0], &Right[0]); 
+ 
+ double mid_t = left_t*(1split) + right_t*split; 
+ 
+ find_bernstein_roots(&Left[0], degree, solutions, depth+1, left_t, mid_t); 
+ 
+ /* Solution is exactly on the subdivision point. */ 
+ if (Right[0] == 0) 
+ solutions.push_back(mid_t); 
+ 
+ find_bernstein_roots(&Right[0], degree, solutions, depth+1, mid_t, right_t); 
+} 
+ 
+/* 
+ * control_poly_flat_enough : 
+ * Check if the control polygon of a Bernstein curve is flat enough 
+ * for recursive subdivision to bottom out. 
+ * 
+ */ 
+static unsigned 
+control_poly_flat_enough(double const *V, /* Control points */ 
+ unsigned degree, 
+ double left_t, double right_t) /* Degree of polynomial */ 
+{ 
+ /* Find the perpendicular distance from each interior control point to line connecting V[0] and 
+ * V[degree] */ 
+ 
+ /* Derive the implicit equation for line connecting first */ 
+ /* and last control points */ 
+ const double a = V[0]  V[degree]; 
+ const double b = right_t  left_t; 
+ const double c = left_t * V[degree]  right_t * V[0] + a * left_t; 
+ 
+ double max_distance_above = 0.0; 
+ double max_distance_below = 0.0; 
+ double ii = 0, dii = 1./degree; 
+ for (unsigned i = 1; i < degree; i++) { 
+ ii += dii; 
+ /* Compute distance from each of the points to that line */ 
+ const double d = (a + V[i]) * ii*b + c; 
+ double dist = d*d; 
+ // Find the largest distance 
+ if (d < 0.0) 
+ max_distance_below = std::min(max_distance_below, dist); 
+ else 
+ max_distance_above = std::max(max_distance_above, dist); 
+ } 
+ 
+ const double abSquared = (a * a) + (b * b); 
+ 
+ const double intercept_1 = (c + max_distance_above / abSquared); 
+ const double intercept_2 = (c + max_distance_below / abSquared); 
+ 
+ /* Compute bounding interval*/ 
+ const double left_intercept = std::min(intercept_1, intercept_2); 
+ const double right_intercept = std::max(intercept_1, intercept_2); 
+ 
+ const double error = 0.5 * (right_intercept  left_intercept); 
+ 
+ if (error < BEPSILON * a) 
+ return 1; 
+ 
+ return 0; 
+} 
+ 
+ 
+ 
+/* 
+ * Bernstein : 
+ * Evaluate a Bernstein function at a particular parameter value 
+ * Fill in control points for resulting subcurves. 
+ * 
+ */ 
+static void 
+Bernstein(double const *V, /* Control pts */ 
+ unsigned degree, /* Degree of bernstein curve */ 
+ double t, /* Parameter value */ 
+ double *Left, /* RETURN left half ctl pts */ 
+ double *Right) /* RETURN right half ctl pts */ 
+{ 
+ const unsigned size=degree+1; 
+ std::vector<double> vtemp(V,V+size); 
+ 
+ /* Copy control points */ 
+ Left[0] = vtemp[0]; 
+ Right[degree]= vtemp[degree]; 
+ 
+ /* Triangle computation */ 
+ const double omt = (1t); 
+ for (unsigned i = 1; i < size; ++i) { 
+ for (unsigned j = 0; j < size  i; ++j) { 
+ vtemp[j] = omt*vtemp[j]+t*vtemp[j+1]; 
+ } 
+ Left[i] =vtemp[0]; 
+ Right[degreei]=vtemp[degreei]; 
+ } 
+} 
+ 
+}; 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(substatementopen . 0)) 
+ indenttabsmode:nil 
+ cbraceoffset:0 
+ fillcolumn:99 
+ End: 
+ vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : 
+*/ 
+ 
+ 
Index: Scribus/scribus/third_party/lib2geom/point.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/point.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/point.cpp (revision 14937) 
@@ 0,0 +1,166 @@ 
+#include "point.h" 
+#include <assert.h> 
+#include "coord.h" 
+#include "isnan.h" //temporary fix for isnan() 
+#include "matrix.h" 
+#include <limits> 
+ 
+ 
+namespace Geom { 
+ 
+/** Scales this vector to make it a unit vector (within rounding error). 
+ * 
+ * The current version tries to handle infinite coordinates gracefully, 
+ * but it's not clear that any callers need that. 
+ * 
+ * \pre \f$this \neq (0, 0)\f$ 
+ * \pre Neither component is NaN. 
+ * \post \f$\epsilon<\leftthis\right1<\epsilon\f$ 
+ */ 
+void Point::normalize() { 
+ double len = hypot(_pt[0], _pt[1]); 
+ if(len == 0) return; 
+ if(is_nan(len)) return; 
+ static double const inf = std::numeric_limits<double>::infinity(); 
+ if(len != inf) { 
+ *this /= len; 
+ } else { 
+ unsigned n_inf_coords = 0; 
+ /* Delay updating pt in case neither coord is infinite. */ 
+ Point tmp; 
+ for ( unsigned i = 0 ; i < 2 ; ++i ) { 
+ if ( _pt[i] == inf ) { 
+ ++n_inf_coords; 
+ tmp[i] = 1.0; 
+ } else if ( _pt[i] == inf ) { 
+ ++n_inf_coords; 
+ tmp[i] = 1.0; 
+ } else { 
+ tmp[i] = 0.0; 
+ } 
+ } 
+ switch (n_inf_coords) { 
+ case 0: { 
+ /* Can happen if both coords are near +/DBL_MAX. */ 
+ *this /= 4.0; 
+ len = hypot(_pt[0], _pt[1]); 
+ assert(len != inf); 
+ *this /= len; 
+ break; 
+ } 
+ case 1: { 
+ *this = tmp; 
+ break; 
+ } 
+ case 2: { 
+ *this = tmp * sqrt(0.5); 
+ break; 
+ } 
+ } 
+ } 
+} 
+ 
+/** Compute the L1 norm, or manhattan distance, of \a p. */ 
+Coord L1(Point const &p) { 
+ Coord d = 0; 
+ for ( int i = 0 ; i < 2 ; i++ ) { 
+ d += fabs(p[i]); 
+ } 
+ return d; 
+} 
+ 
+/** Compute the L infinity, or maximum, norm of \a p. */ 
+Coord LInfty(Point const &p) { 
+ Coord const a(fabs(p[0])); 
+ Coord const b(fabs(p[1])); 
+ return ( a < b  is_nan(b) 
+ ? b 
+ : a ); 
+} 
+ 
+/** Returns true iff p is a zero vector, i.e.\ Point(0, 0). 
+ * 
+ * (NaN is considered nonzero.) 
+ */ 
+bool 
+is_zero(Point const &p) 
+{ 
+ return ( p[0] == 0 && 
+ p[1] == 0 ); 
+} 
+ 
+bool 
+is_unit_vector(Point const &p) 
+{ 
+ return fabs(1.0  L2(p)) <= 1e4; 
+ /* The tolerance of 1e4 is somewhat arbitrary. Point::normalize is believed to return 
+ points well within this tolerance. I'm not aware of any callers that want a small 
+ tolerance; most callers would be ok with a tolerance of 0.25. */ 
+} 
+ 
+Coord atan2(Point const p) { 
+ return std::atan2(p[Y], p[X]); 
+} 
+ 
+/** compute the angle turning from a to b. This should give \f$\pi/2\f$ for angle_between(a, rot90(a)); 
+ * This works by projecting b onto the basis defined by a, rot90(a) 
+ */ 
+Coord angle_between(Point const a, Point const b) { 
+ return std::atan2(cross(b,a), dot(b,a)); 
+} 
+ 
+ 
+ 
+/** Returns a version of \a a scaled to be a unit vector (within rounding error). 
+ * 
+ * The current version tries to handle infinite coordinates gracefully, 
+ * but it's not clear that any callers need that. 
+ * 
+ * \pre a != Point(0, 0). 
+ * \pre Neither coordinate is NaN. 
+ * \post L2(ret) very near 1.0. 
+ */ 
+Point unit_vector(Point const &a) 
+{ 
+ Point ret(a); 
+ ret.normalize(); 
+ return ret; 
+} 
+ 
+Point abs(Point const &b) 
+{ 
+ Point ret; 
+ for ( int i = 0 ; i < 2 ; i++ ) { 
+ ret[i] = fabs(b[i]); 
+ } 
+ return ret; 
+} 
+ 
+Point operator*(Point const &v, Matrix const &m) { 
+ Point ret; 
+ for(int i = 0; i < 2; i++) { 
+ ret[i] = v[X] * m[i] + v[Y] * m[i + 2] + m[i + 4]; 
+ } 
+ return ret; 
+} 
+ 
+Point operator/(Point const &p, Matrix const &m) { return p * m.inverse(); } 
+ 
+Point &Point::operator*=(Matrix const &m) 
+{ 
+ *this = *this * m; 
+ return *this; 
+} 
+ 
+} //Namespace Geom 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/interval.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/interval.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/interval.h (revision 14937) 
@@ 0,0 +1,228 @@ 
+/* 
+ * interval.h  Simple closed interval class 
+ * 
+ * Copyright 2007 Michael Sloan <mgsloan@gmail.com> 
+ * 
+ * Original Rect/Range code by: 
+ * Lauris Kaplinski <lauris@kaplinski.com> 
+ * Nathan Hurst <njh@mail.csse.monash.edu.au> 
+ * bulia byak <buliabyak@users.sf.net> 
+ * MenTaLguY <mental@rydia.net> 
+ * 
+ * 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 COPYINGLGPL2.1; if not, output to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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_INTERVAL_H 
+#define SEEN_INTERVAL_H 
+ 
+#include <assert.h> 
+#include "coord.h" 
+ 
+#include <boost/optional/optional.hpp> 
+ 
+//error in miesh_distortion 
+#ifdef min 
+# undef min 
+#endif 
+ 
+#ifdef max 
+# undef max 
+#endif 
+ 
+namespace Geom { 
+ 
+// 
+class Interval { 
+private: 
+ Coord _b[2]; 
+ 
+public: 
+ //TODO: I just know this'll pop up somewhere, starting off someone's interval at 0... I can't see how to avoid this. 
+ explicit Interval() { _b[0] = _b[1] = 0; } 
+ explicit Interval(Coord u) { _b[0] = _b[1] = u; } 
+ Interval(Coord u, Coord v) { 
+ if(u < v) { 
+ _b[0] = u; _b[1] = v; 
+ } else { 
+ _b[0] = v; _b[1] = u; 
+ } 
+ } 
+ 
+ double operator[](unsigned i) const { 
+ assert(i < 2); 
+ return _b[i]; 
+ } 
+ inline double& operator[](unsigned i) { return _b[i]; } //Trust the user... 
+ 
+ inline Coord min() const { return _b[0]; } 
+ inline Coord max() const { return _b[1]; } 
+ inline Coord extent() const { return _b[1]  _b[0]; } 
+ inline Coord middle() const { return (_b[1] + _b[0]) * 0.5; } 
+ 
+ inline bool isEmpty() const { return _b[0] == _b[1]; } 
+ inline bool contains(Coord val) const { return _b[0] <= val && val <= _b[1]; } 
+ bool contains(const Interval & val) const { return _b[0] <= val._b[0] && val._b[1] <= _b[1]; } 
+ bool intersects(const Interval & val) const { 
+ return contains(val._b[0])  contains(val._b[1])  val.contains(*this); 
+ } 
+ 
+ inline bool operator==(Interval other) { return _b[0] == other._b[0] && _b[1] == other._b[1]; } 
+ inline bool operator!=(Interval other) { return _b[0] != other._b[0]  _b[1] != other._b[1]; } 
+ 
+ //IMPL: OffsetableConcept 
+ //TODO: rename output_type to something else in the concept 
+ typedef Coord output_type; 
+ inline Interval operator+(Coord amnt) { 
+ return Interval(_b[0] + amnt, _b[1] + amnt); 
+ } 
+ inline Interval operator(Coord amnt) { 
+ return Interval(_b[0]  amnt, _b[1]  amnt); 
+ } 
+ inline Interval operator+=(Coord amnt) { 
+ _b[0] += amnt; _b[1] += amnt; 
+ return *this; 
+ } 
+ inline Interval operator=(Coord amnt) { 
+ _b[0] = amnt; _b[1] = amnt; 
+ return *this; 
+ } 
+ 
+ //IMPL: ScalableConcept 
+ inline Interval operator() const { return Interval(*this); } 
+ inline Interval operator*(Coord s) const { return Interval(_b[0]*s, _b[1]*s); } 
+ inline Interval operator/(Coord s) const { return Interval(_b[0]/s, _b[1]/s); } 
+ Interval operator*=(Coord s) { 
+ if(s < 0) { 
+ Coord temp = _b[0]; 
+ _b[0] = _b[1]*s; 
+ _b[1] = temp*s; 
+ } else { 
+ _b[0] *= s; 
+ _b[1] *= s; 
+ } 
+ return *this; 
+ } 
+ Interval operator/=(Coord s) { 
+ //TODO: what about s=0? 
+ if(s < 0) { 
+ Coord temp = _b[0]; 
+ _b[0] = _b[1]/s; 
+ _b[1] = temp/s; 
+ } else { 
+ _b[0] /= s; 
+ _b[1] /= s; 
+ } 
+ return *this; 
+ } 
+ 
+ //TODO: NaN handleage for the next two? 
+ //TODO: Evaluate if wrap behaviour is proper. 
+ //If val > max, then rather than becoming a min==max range, it 'wraps' over 
+ void setMin(Coord val) { 
+ if(val > _b[1]) { 
+ _b[0] = _b[1]; 
+ _b[1] = val; 
+ } else { 
+ _b[0] = val; 
+ } 
+ } 
+ //If val < min, then rather than becoming a min==max range, it 'wraps' over 
+ void setMax(Coord val) { 
+ if(val < _b[0]) { 
+ _b[1] = _b[0]; 
+ _b[0] = val; 
+ } else { 
+ _b[1] = val; 
+ } 
+ } 
+ 
+ inline void extendTo(Coord val) { 
+ if(val < _b[0]) _b[0] = val; 
+ if(val > _b[1]) _b[1] = val; //no else, as we want to handle NaN 
+ } 
+ 
+ static Interval fromArray(const Coord* c, int n) { 
+ assert(n > 0); 
+ Interval result(c[0]); 
+ for(int i = 1; i < n; i++) result.extendTo(c[i]); 
+ return result; 
+ } 
+ 
+ inline void expandBy(double amnt) { 
+ _b[0] = amnt; 
+ _b[1] += amnt; 
+ } 
+ 
+ inline void unionWith(const Interval & a) { 
+ if(a._b[0] < _b[0]) _b[0] = a._b[0]; 
+ if(a._b[1] > _b[1]) _b[1] = a._b[1]; 
+ } 
+}; 
+ 
+//IMPL: AddableConcept 
+inline Interval operator+(const Interval & a, const Interval & b) { 
+ return Interval(a.min() + b.min(), a.max() + b.max()); 
+} 
+inline Interval operator(const Interval & a, const Interval & b) { 
+ return Interval(a.min()  b.max(), a.max()  b.min()); 
+} 
+inline Interval operator+=(Interval & a, const Interval & b) { a = a + b; return a; } 
+inline Interval operator=(Interval & a, const Interval & b) { a = a  b; return a; } 
+ 
+//There might be impls of this based off sign checks 
+inline Interval operator*(const Interval & a, const Interval & b) { 
+ Interval res(a.min() * b.min()); 
+ res.extendTo(a.min() * b.max()); 
+ res.extendTo(a.max() * b.min()); 
+ res.extendTo(a.max() * b.max()); 
+ return res; 
+} 
+inline Interval operator*=(Interval & a, const Interval & b) { a = a * b; return a; } 
+ 
+/* reinstate if useful (doesn't do the proper thing for 0 inclusion) 
+inline Interval operator/(const Interval & a, const Interval & b) { 
+ Interval res(a.min() / b.min()); 
+ res.extendTo(a.min() / b.max()); 
+ res.extendTo(a.max() / b.min()); 
+ res.extendTo(a.max() / b.max()); 
+ return res; 
+} 
+inline Interval operator/=(Interval & a, const Interval & b) { a = a / b; return a; } 
+*/ 
+ 
+// 'union' conflicts with C keyword 
+inline Interval unify(const Interval & a, const Interval & b) { 
+ return Interval(std::min(a.min(), b.min()), 
+ std::max(a.max(), b.max())); 
+} 
+inline boost::optional<Interval> intersect(const Interval & a, const Interval & b) { 
+ Coord u = std::max(a.min(), b.min()), 
+ v = std::min(a.max(), b.max()); 
+ //technically >= might be incorrect, but singulars suck 
+ return u >= v ? boost::optional<Interval>() 
+ : boost::optional<Interval>(Interval(u, v)); 
+} 
+ 
+} 
+#endif //SEEN_INTERVAL_H 
Index: Scribus/scribus/third_party/lib2geom/sbasis.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/sbasis.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/sbasis.h (revision 14937) 
@@ 0,0 +1,331 @@ 
+/* 
+ * sbasis.h  Spower basis function class 
+ * 
+ * Authors: 
+ * Nathan Hurst <njh@mail.csse.monash.edu.au> 
+ * Michael Sloan <mgsloan@gmail.com> 
+ * 
+ * Copyright (C) 20062007 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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_SBASIS_H 
+#define SEEN_SBASIS_H 
+#include <vector> 
+#include <cassert> 
+#include <iostream> 
+ 
+#include "linear.h" 
+#include "interval.h" 
+#include "utils.h" 
+#include "exception.h" 
+ 
+namespace Geom { 
+ 
+/*** An empty SBasis is identically 0. */ 
+class SBasis : public std::vector<Linear>{ 
+public: 
+ SBasis() {} 
+ explicit SBasis(double a) { 
+ push_back(Linear(a,a)); 
+ } 
+ SBasis(SBasis const & a) : 
+ std::vector<Linear>(a) 
+ {} 
+ SBasis(Linear const & bo) { 
+ push_back(bo); 
+ } 
+ 
+ //IMPL: FragmentConcept 
+ typedef double output_type; 
+ inline bool isZero() const { 
+ if(empty()) return true; 
+ for(unsigned i = 0; i < size(); i++) { 
+ if(!(*this)[i].isZero()) return false; 
+ } 
+ return true; 
+ } 
+ inline bool isConstant() const { 
+ if (empty()) return true; 
+ for (unsigned i = 0; i < size(); i++) { 
+ if(!(*this)[i].isConstant()) return false; 
+ } 
+ return true; 
+ } 
+ 
+ bool isFinite() const; 
+ inline double at0() const { 
+ if(empty()) return 0; else return (*this)[0][0]; 
+ } 
+ inline double at1() const{ 
+ if(empty()) return 0; else return (*this)[0][1]; 
+ } 
+ 
+ double valueAt(double t) const { 
+ double s = t*(1t); 
+ 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; 
+ } 
+ return (1t)*p0 + t*p1; 
+ } 
+ double valueAndDerivative(double t, double &der) const { 
+ double s = t*(1t); 
+ 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 (1t)*p0 + t*p1; 
+ } 
+ double operator()(double t) const { 
+ return valueAt(t); 
+ } 
+ 
+ std::vector<double> valueAndDerivatives(double /*t*/, unsigned /*n*/) const { 
+ //TODO 
+ throwNotImplemented(0); 
+ } 
+ 
+ SBasis toSBasis() const { return SBasis(*this); } 
+ 
+ double tailError(unsigned tail) const; 
+ 
+// compute f(g) 
+ SBasis operator()(SBasis const & g) const; 
+ 
+ Linear operator[](unsigned i) const { 
+ assert(i < size()); 
+ return std::vector<Linear>::operator[](i); 
+ } 
+ 
+//MUTATOR PRISON 
+ Linear& operator[](unsigned i) { return this>at(i); } 
+ 
+ //remove extra zeros 
+ void normalize() { 
+ while(!empty() && 0 == back()[0] && 0 == back()[1]) 
+ pop_back(); 
+ } 
+ void truncate(unsigned k) { if(k < size()) resize(k); } 
+}; 
+ 
+//TODO: figure out how to stick this in linear, while not adding an sbasis dep 
+inline SBasis Linear::toSBasis() const { return SBasis(*this); } 
+ 
+//implemented in sbasisroots.cpp 
+Interval bounds_exact(SBasis const &a); 
+Interval bounds_fast(SBasis const &a, int order = 0); 
+Interval bounds_local(SBasis const &a, const Interval &t, int order = 0); 
+ 
+inline SBasis reverse(SBasis const &a) { 
+ SBasis result; 
+ result.reserve(a.size()); 
+ for(unsigned k = 0; k < a.size(); k++) 
+ result.push_back(reverse(a[k])); 
+ return result; 
+} 
+ 
+//IMPL: ScalableConcept 
+inline SBasis operator(const SBasis& p) { 
+ if(p.isZero()) return SBasis(); 
+ SBasis result; 
+ result.reserve(p.size()); 
+ 
+ for(unsigned i = 0; i < p.size(); i++) { 
+ result.push_back(p[i]); 
+ } 
+ return result; 
+} 
+SBasis operator*(SBasis const &a, double k); 
+inline SBasis operator*(double k, SBasis const &a) { return a*k; } 
+inline SBasis operator/(SBasis const &a, double k) { return a*(1./k); } 
+SBasis& operator*=(SBasis& a, double b); 
+inline SBasis& operator/=(SBasis& a, double b) { return (a*=(1./b)); } 
+ 
+//IMPL: AddableConcept 
+SBasis operator+(const SBasis& a, const SBasis& b); 
+SBasis operator(const SBasis& a, const SBasis& b); 
+SBasis& operator+=(SBasis& a, const SBasis& b); 
+SBasis& operator=(SBasis& a, const SBasis& b); 
+ 
+//TODO: remove? 
+inline SBasis operator+(const SBasis & a, Linear const & b) { 
+ if(b.isZero()) return a; 
+ if(a.isZero()) return b; 
+ SBasis result(a); 
+ result[0] += b; 
+ return result; 
+} 
+inline SBasis operator(const SBasis & a, Linear const & b) { 
+ if(b.isZero()) return a; 
+ SBasis result(a); 
+ result[0] = b; 
+ return result; 
+} 
+inline SBasis& operator+=(SBasis& a, const Linear& b) { 
+ if(a.isZero()) 
+ a.push_back(b); 
+ else 
+ a[0] += b; 
+ return a; 
+} 
+inline SBasis& operator=(SBasis& a, const Linear& b) { 
+ if(a.isZero()) 
+ a.push_back(b); 
+ else 
+ a[0] = b; 
+ return a; 
+} 
+ 
+//IMPL: OffsetableConcept 
+inline SBasis operator+(const SBasis & a, double b) { 
+ if(a.isZero()) return Linear(b, b); 
+ SBasis result(a); 
+ result[0] += b; 
+ return result; 
+} 
+inline SBasis operator(const SBasis & a, double b) { 
+ if(a.isZero()) return Linear(b, b); 
+ SBasis result(a); 
+ result[0] = b; 
+ return result; 
+} 
+inline SBasis& operator+=(SBasis& a, double b) { 
+ if(a.isZero()) 
+ a.push_back(Linear(b,b)); 
+ else 
+ a[0] += b; 
+ return a; 
+} 
+inline SBasis& operator=(SBasis& a, double b) { 
+ if(a.isZero()) 
+ a.push_back(Linear(b,b)); 
+ else 
+ a[0] = b; 
+ return a; 
+} 
+ 
+SBasis shift(SBasis const &a, int sh); 
+SBasis shift(Linear const &a, int sh); 
+ 
+inline SBasis truncate(SBasis const &a, unsigned terms) { 
+ SBasis c; 
+ c.insert(c.begin(), a.begin(), a.begin() + std::min(terms, (unsigned)a.size())); 
+ return c; 
+} 
+ 
+SBasis multiply(SBasis const &a, SBasis const &b); 
+ 
+SBasis integral(SBasis const &c); 
+SBasis derivative(SBasis const &a); 
+ 
+SBasis sqrt(SBasis const &a, int k); 
+ 
+// return a kth order approx to 1/a) 
+SBasis reciprocal(Linear const &a, int k); 
+SBasis divide(SBasis const &a, SBasis const &b, int k); 
+ 
+inline SBasis operator*(SBasis const & a, SBasis const & b) { 
+ return multiply(a, b); 
+} 
+ 
+inline SBasis& operator*=(SBasis& a, SBasis const & b) { 
+ a = multiply(a, b); 
+ return a; 
+} 
+ 
+//valuation: degree of the first non zero coefficient. 
+inline unsigned 
+valuation(SBasis const &a, double tol=0){ 
+ unsigned val=0; 
+ while( val<a.size() && 
+ fabs(a[val][0])<tol && 
+ fabs(a[val][1])<tol ) 
+ val++; 
+ return val; 
+} 
+ 
+// a(b(t)) 
+SBasis compose(SBasis const &a, SBasis const &b); 
+SBasis compose(SBasis const &a, SBasis const &b, unsigned k); 
+SBasis inverse(SBasis a, int k); 
+//compose_inverse(f,g)=compose(f,inverse(g)), but is numerically more stable in some good cases... 
+//TODO: requires g(0)=0 & g(1)=1 atm. generalization should be obvious. 
+SBasis compose_inverse(SBasis const &f, SBasis const &g, unsigned order=2, double tol=1e3); 
+ 
+inline SBasis portion(const SBasis &t, double from, double to) { return compose(t, Linear(from, to)); } 
+ 
+// compute f(g) 
+inline SBasis 
+SBasis::operator()(SBasis const & g) const { 
+ return compose(*this, g); 
+} 
+ 
+inline std::ostream &operator<< (std::ostream &out_file, const Linear &bo) { 
+ out_file << "{" << bo[0] << ", " << bo[1] << "}"; 
+ return out_file; 
+} 
+ 
+inline std::ostream &operator<< (std::ostream &out_file, const SBasis & p) { 
+ for(unsigned i = 0; i < p.size(); i++) { 
+ out_file << p[i] << "s^" << i << " + "; 
+ } 
+ return out_file; 
+} 
+ 
+SBasis sin(Linear bo, int k); 
+SBasis cos(Linear bo, int k); 
+ 
+std::vector<double> roots(SBasis const & s); 
+std::vector<std::vector<double> > multi_roots(SBasis const &f, 
+ std::vector<double> const &levels, 
+ double htol=1e7, 
+ double vtol=1e7, 
+ double a=0, 
+ double b=1); 
+ 
+} 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
+#endif 
Index: Scribus/scribus/third_party/lib2geom/conjugate_gradient.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/conjugate_gradient.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/conjugate_gradient.cpp (revision 14937) 
@@ 0,0 +1,133 @@ 
+/* 
+ * conjugate_gradient.cpp 
+ * 
+ * Copyright 2006 Nathan Hurst <njh@mail.csse.monash.edu.au> 
+ * 
+ * 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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 <math.h> 
+#include <stdlib.h> 
+#include <valarray> 
+#include <cassert> 
+#include "conjugate_gradient.h" 
+ 
+/* lifted wholely from wikipedia. */ 
+ 
+using std::valarray; 
+ 
+static void 
+matrix_times_vector(valarray<double> const &matrix, /* m * n */ 
+ valarray<double> const &vec, /* n */ 
+ valarray<double> &result) /* m */ 
+{ 
+ unsigned n = vec.size(); 
+ unsigned m = result.size(); 
+ assert(m*n == matrix.size()); 
+ for (unsigned i = 0; i < m; i++) { 
+ double res = 0; 
+ for (unsigned j = 0; j < n; j++) 
+ res += matrix[i*m+j] * vec[j]; 
+ result[i] = res; 
+ } 
+} 
+/* 
+static double Linfty(valarray<double> const &vec) { 
+ return std::max(vec.max(), vec.min()); 
+} 
+*/ 
+double 
+inner(valarray<double> const &x, 
+ valarray<double> const &y) { 
+ double total = 0; 
+ for(unsigned i = 0; i < x.size(); i++) 
+ total += x[i]*y[i]; 
+ return total;// (x*y).sum(); < this is more concise, but ineff 
+} 
+ 
+void 
+conjugate_gradient(double **A, 
+ double *x, 
+ double *b, 
+ unsigned n, 
+ double tol, 
+ int max_iterations, 
+ bool ortho1) { 
+ valarray<double> vA(n*n); 
+ valarray<double> vx(n); 
+ valarray<double> vb(n); 
+ for(unsigned i=0;i<n;i++) { 
+ vx[i]=x[i]; 
+ vb[i]=b[i]; 
+ for(unsigned j=0;j<n;j++) { 
+ vA[i*n+j]=A[i][j]; 
+ } 
+ } 
+ conjugate_gradient(vA,vx,vb,n,tol,max_iterations,ortho1); 
+ for(unsigned i=0;i<n;i++) { 
+ x[i]=vx[i]; 
+ } 
+} 
+void 
+conjugate_gradient(valarray<double> const &A, 
+ valarray<double> &x, 
+ valarray<double> const &b, 
+ unsigned n, double tol, 
+ unsigned max_iterations, bool ortho1) { 
+ valarray<double> Ap(n), p(n), r(n); 
+ matrix_times_vector(A,x,Ap); 
+ r=bAp; 
+ double r_r = inner(r,r); 
+ unsigned k = 0; 
+ tol *= tol; 
+ while(k < max_iterations && r_r > tol) { 
+ k++; 
+ double r_r_new = r_r; 
+ if(k == 1) 
+ p = r; 
+ else { 
+ r_r_new = inner(r,r); 
+ p = r + (r_r_new/r_r)*p; 
+ } 
+ matrix_times_vector(A, p, Ap); 
+ double alpha_k = r_r_new / inner(p, Ap); 
+ x += alpha_k*p; 
+ r = alpha_k*Ap; 
+ r_r = r_r_new; 
+ } 
+ //printf("njh: %d iters, Linfty = %g L2 = %g\n", k, 
+ //std::max(r.min(), r.max()), sqrt(r_r)); 
+ // x is solution 
+} 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4 
Index: Scribus/scribus/third_party/lib2geom/shape.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/shape.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/shape.cpp (revision 14937) 
@@ 0,0 +1,632 @@ 
+#include "shape.h" 
+#include "utils.h" 
+#include "sweep.h" 
+#include "ord.h" 
+ 
+#include <iostream> 
+#include <algorithm> 
+#include <cstdlib> 
+ 
+namespace Geom { 
+ 
+// A little sugar for appending a list to another 
+template<typename T> 
+void append(T &a, T const &b) { 
+ a.insert(a.end(), b.begin(), b.end()); 
+} 
+ 
+//Orders a list of indices according to their containment within eachother. 
+struct ContainmentOrder { 
+ std::vector<Region> const *rs; 
+ explicit ContainmentOrder(std::vector<Region> const *r) : rs(r) {} 
+ bool operator()(unsigned a, unsigned b) const { return (*rs)[b].contains((*rs)[a]); } 
+}; 
+ 
+//Returns the list of regions containing a particular point. Useful in tandem with ContainmentOrder 
+std::vector<unsigned> Shape::containment_list(Point p) const { 
+ std::vector<Rect> pnt; 
+ pnt.push_back(Rect(p, p)); 
+ std::vector<std::vector<unsigned> > cull = sweep_bounds(pnt, bounds(*this)); 
+ std::vector<unsigned> containers; 
+ if(cull[0].size() == 0) return containers; 
+ for(unsigned i = 0; i < cull[0].size(); i++) 
+ if(content[cull[0][i]].contains(p)) containers.push_back(cull[0][i]); 
+ return containers; 
+} 
+ 
+/* Used within shape_boolean and related functions, as the name describes, finds the 
+ * first false within the list of lists of booleans. 
+ */ 
+void first_false(std::vector<std::vector<bool> > visited, unsigned &i, unsigned &j) { 
+ for(i = 0, j = 0; i < visited.size(); i++) { 
+ std::vector<bool>::iterator unvisited = std::find(visited[i].begin(), visited[i].end(), false); 
+ if(unvisited != visited[i].end()) { 
+ j = unvisited  visited[i].begin(); 
+ break; 
+ } 
+ } 
+} 
+ 
+// Finds a crossing in a list of them, given the sorting index. 
+unsigned find_crossing(Crossings const &cr, Crossing x, unsigned i) { 
+ return std::lower_bound(cr.begin(), cr.end(), x, CrossingOrder(i))  cr.begin(); 
+} 
+ 
+/* This function handles boolean ops on shapes. The first parameter is a bool 
+ * which determines its behavior in each combination of cases. For proper 
+ * fill information and noncrossing behavior, the fill data of the regions 
+ * must be correct. The boolean parameter determines whether the operation 
+ * is a union or a subtraction. Reversed paths represent inverse regions, 
+ * where everything is included in the fill except for the insides. 
+ * 
+ * Here is a chart of the behavior under various circumstances: 
+ * 
+ * rev = false (union) 
+ * A 
+ * F H 
+ * F A+B > F AB > H 
+ *B 
+ * H BA > H AxB > H 
+ * 
+ * rev = true (intersect) 
+ * A 
+ * F H 
+ * F AxB > F BA > F 
+ *B 
+ * H AB > F A+B > H 
+ * 
+ * F/H = Fill outer / Hole outer 
+ * A/B specify operands 
+ * + = union,  = subtraction, x = intersection 
+ * > read as "produces" 
+ * 
+ * This is the main function of boolops, yet its operation isn't very complicated. 
+ * It traverses the crossings, and uses the crossing direction to decide whether 
+ * the next segment should be taken from A or from B. The second half of the 
+ * function deals with figuring out what to do with bits that have no intersection. 
+ */ 
+Shape shape_boolean(bool rev, Shape const & a, Shape const & b, CrossingSet const & crs) { 
+ const Regions ac = a.content, bc = b.content; 
+ 
+ //Keep track of which crossings we've hit. 
+ std::vector<std::vector<bool> > visited; 
+ for(unsigned i = 0; i < crs.size(); i++) 
+ visited.push_back(std::vector<bool>(crs[i].size(), false)); 
+ 
+ //Traverse the crossings, creating chunks 
+ Regions chunks; 
+ while(true) { 
+ unsigned i, j; 
+ first_false(visited, i, j); 
+ if(i == visited.size()) break; 
+ 
+ Path res; 
+ do { 
+ Crossing cur = crs[i][j]; 
+ visited[i][j] = true; 
+ 
+ //get indices of the dual: 
+ unsigned io = cur.getOther(i), jo = find_crossing(crs[io], cur, io); 
+ if(jo < visited[io].size()) visited[io][jo] = true; 
+ 
+ //main driving logic 
+ if(logical_xor(cur.dir, rev)) { 
+ if(i >= ac.size()) { i = io; j = jo; } 
+ j++; 
+ if(j >= crs[i].size()) j = 0; 
+ Crossing next = crs[i][j]; 
+ ac[next.a].boundary.appendPortionTo(res, cur.ta, next.ta); 
+ } else { 
+ if(i < ac.size()) { i = io; j = jo; } 
+ j++; 
+ if(j >= crs[i].size()) j = 0; 
+ Crossing next = crs[i][j]; 
+ bc[next.b  ac.size()].boundary.appendPortionTo(res, cur.tb, next.tb); 
+ } 
+ } while (!visited[i][j]); 
+ if(res.size() > 0) chunks.push_back(Region(res)); 
+ } 
+ 
+ //If true, then we are on the 'subtraction diagonal' 
+ bool const on_sub = logical_xor(a.fill, b.fill); 
+ //If true, outer paths are filled 
+ bool const res_fill = rev ? (on_sub  (a.fill && b.fill)) : (a.fill && b.fill); 
+ 
+ //Handle unintersecting portions 
+ for(unsigned i = 0; i < crs.size(); i++) { 
+ if(crs[i].size() == 0) { 
+ bool env; 
+ bool on_a = i < ac.size(); 
+ Region const & r(on_a ? ac[i] : bc[i  ac.size()]); 
+ Shape const & other(on_a ? b : a); 
+ 
+ std::vector<unsigned> containers = other.containment_list(r.boundary.initialPoint()); 
+ if(containers.empty()) { 
+ //not included in any container, the environment fill is the opposite of the outer fill 
+ env = !res_fill; 
+ if(on_sub && logical_xor(other.fill, res_fill)) env = !env; //If on the subtractor, invert the environment fill 
+ } else { 
+ //environment fill is the same as the innermost container 
+ std::vector<unsigned>::iterator cit = std::min_element(containers.begin(), containers.end(), ContainmentOrder(&other.content)); 
+ env = other[*cit].isFill(); 
+ } 
+ if(!logical_xor(rev, env)) chunks.push_back(r); //When unioning, environment must be hole for inclusion, when intersecting, it must be filled 
+ } 
+ } 
+ 
+ return Shape(chunks, res_fill); 
+} 
+ 
+// Just a convenience wrapper for shape_boolean, which handles the crossings 
+Shape shape_boolean(bool rev, Shape const & a, Shape const & b) { 
+ CrossingSet crs = crossings_between(a, b); 
+ 
+ return shape_boolean(rev, a, b, crs); 
+} 
+ 
+ 
+// Some utility functions for boolop: 
+ 
+std::vector<double> region_sizes(Shape const &a) { 
+ std::vector<double> ret; 
+ for(unsigned i = 0; i < a.size(); i++) { 
+ ret.push_back(double(a[i].size())); 
+ } 
+ return ret; 
+} 
+ 
+Shape shape_boolean_ra(bool rev, Shape const &a, Shape const &b, CrossingSet const &crs) { 
+ return shape_boolean(rev, a.inverse(), b, reverse_ta(crs, a.size(), region_sizes(a))); 
+} 
+ 
+Shape shape_boolean_rb(bool rev, Shape const &a, Shape const &b, CrossingSet const &crs) { 
+ return shape_boolean(rev, a, b.inverse(), reverse_tb(crs, a.size(), region_sizes(b))); 
+} 
+ 
+/* This is a function based on shape_boolean which allows boolean operations 
+ * to be specified as a logic table. This logic table is 4 bitflags, which 
+ * correspond to the elements of the 'truth table' for a particular operation. 
+ * These flags are defined with the enums starting with BOOLOP_ . 
+ * 
+ * NOTE: currently doesn't work, as the CrossingSet reversal functions crash 
+ */ 
+Shape boolop(Shape const &a, Shape const &b, unsigned flags, CrossingSet const &crs) { 
+ throwNotImplemented(0); 
+ flags &= 15; 
+ if(flags <= BOOLOP_UNION) { 
+ switch(flags) { 
+ case BOOLOP_INTERSECT: return shape_boolean(true, a, b, crs); 
+ case BOOLOP_SUBTRACT_A_B: return shape_boolean_rb(true, a, b, crs); 
+ case BOOLOP_IDENTITY_A: return a; 
+ case BOOLOP_SUBTRACT_B_A: return shape_boolean_ra(true, a, b, crs); 
+ case BOOLOP_IDENTITY_B: return b; 
+ case BOOLOP_EXCLUSION: { 
+ Shape res = shape_boolean_rb(true, a, b, crs); 
+ append(res.content, shape_boolean_ra(true, a, b, crs).content); 
+ return res; 
+ } 
+ case BOOLOP_UNION: return shape_boolean(false, a, b); 
+ } 
+ } else { 
+ flags = ~flags & 15; 
+ switch(flags  BOOLOP_NEITHER) { 
+ case BOOLOP_SUBTRACT_A_B: return shape_boolean_ra(false, a, b, crs); 
+ case BOOLOP_SUBTRACT_B_A: return shape_boolean_rb(false, a, b, crs); 
+ case BOOLOP_EXCLUSION: { 
+ Shape res = shape_boolean_ra(false, a, b, CrossingSet(crs)); 
+ append(res.content, shape_boolean_rb(false, a, b, CrossingSet(crs)).content); 
+ return res; 
+ } 
+ } 
+ return boolop(a, b, flags, crs).inverse(); 
+ } 
+ return Shape(); 
+} 
+ 
+/* This version of the boolop function doesn't require a set of crossings, as 
+ * it computes them for you. This is more efficient in some cases, as the 
+ * shape can be inverted before finding crossings. In the special case of 
+ * exclusion it uses the other version of boolop. 
+ */ 
+Shape boolop(Shape const &a, Shape const &b, unsigned flags) { 
+ flags &= 15; 
+ if(flags <= BOOLOP_UNION) { 
+ switch(flags) { 
+ case BOOLOP_INTERSECT: return shape_boolean(true, a, b); 
+ case BOOLOP_SUBTRACT_A_B: return shape_boolean(true, a, b.inverse()); 
+ case BOOLOP_IDENTITY_A: return a; 
+ case BOOLOP_SUBTRACT_B_A: return shape_boolean(true, b, a.inverse()); 
+ case BOOLOP_IDENTITY_B: return b; 
+ case BOOLOP_EXCLUSION: { 
+ Shape res = shape_boolean(true, a, b.inverse()); 
+ append(res.content, shape_boolean(true, b, a.inverse()).content); 
+ return res; 
+ } //return boolop(a, b, flags, crossings_between(a, b)); 
+ case BOOLOP_UNION: return shape_boolean(false, a, b); 
+ } 
+ } else { 
+ flags = ~flags & 15; 
+ switch(flags) { 
+ case BOOLOP_SUBTRACT_A_B: return shape_boolean(false, b, a.inverse()); 
+ case BOOLOP_SUBTRACT_B_A: return shape_boolean(false, a, b.inverse()); 
+ case BOOLOP_EXCLUSION: { 
+ Shape res = shape_boolean(false, a, b.inverse()); 
+ append(res.content, shape_boolean(false, b, a.inverse()).content); 
+ return res; 
+ } //return boolop(a, b, flags, crossings_between(a, b)); 
+ } 
+ return boolop(a, b, flags).inverse(); 
+ } 
+ return Shape(); 
+} 
+ 
+int paths_winding(std::vector<Path> const &ps, Point p) { 
+ int ret = 0; 
+ for(unsigned i = 0; i < ps.size(); i++) 
+ ret += winding(ps[i], p); 
+ return ret; 
+} 
+ 
+void add_to_shape(Shape &s, Path const &p, bool fill) { 
+ if(fill) 
+ s.content.push_back(Region(p).asFill()); 
+ else 
+ s.content.push_back(Region(p).asHole()); 
+} 
+ 
+int inner_winding(Path const & p, std::vector<Path> const &ps) { 
+ Point pnt = p.initialPoint(); 
+ return paths_winding(ps, pnt)  winding(p, pnt) + 1; 
+} 
+ 
+double fudgerize(double d, bool rev) { 
+ double ret = rev ? d  0.01 : d + 0.01; 
+ if(ret < 0) ret = 0; 
+ return ret; 
+} 
+ 
+unsigned pick_coincident(unsigned ix, unsigned jx, bool &rev, std::vector<Path> const &ps, CrossingSet const &crs) { 
+ unsigned ex_jx = jx; 
+ unsigned oix = crs[ix][jx].getOther(ix); 
+ double otime = crs[ix][jx].getTime(oix); 
+ Point cross_point = ps[oix].pointAt(otime), 
+ along = ps[oix].pointAt(fudgerize(otime, rev))  cross_point, 
+ prev = along; 
+ bool ex_dir = rev; 
+ for(unsigned k = jx; k < crs[ix].size(); k++) { 
+ unsigned koix = crs[ix][k].getOther(ix); 
+ if(koix == oix) { 
+ 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); 
+ Cmp from_along = cmp(cross(along, val), 0); 
+ Cmp c = cmp(from_along, to_prev); 
+ if(c == EQUAL_TO && from_along == LESS_THAN) { 
+ ex_jx = k; 
+ prev = val; 
+ ex_dir = dir; 
+ } 
+ } 
+ } 
+ } 
+ rev = ex_dir; 
+ return ex_jx; 
+} 
+ 
+unsigned crossing_along(double t, unsigned ix, unsigned jx, bool dir, Crossings const & crs) { 
+ Crossing cur = Crossing(t, t, ix, ix, false); 
+ if(jx < crs.size()) { 
+ double ct = crs[jx].getTime(ix); 
+ if(t == ct) { 
+ cur = crs[jx]; 
+ if(cur.a == cur.b) { 
+ if(jx+1 <= crs.size() && crs[jx+1].getOther(ix) == ix) return jx+1; 
+ if(jx > 0 && crs[jx1].getOther(ix) == ix) return jx1; 
+ } 
+ } 
+ } 
+ if(!dir) { 
+ jx = std::upper_bound(crs.begin(), crs.end(), cur, CrossingOrder(ix))  crs.begin(); 
+ } else { 
+ jx = std::lower_bound(crs.begin(), crs.end(), cur, CrossingOrder(ix))  crs.begin(); 
+ if(jx == 0) jx = crs.size()  1; else jx; 
+ jx = std::lower_bound(crs.begin(), crs.end(), crs[jx], CrossingOrder(ix))  crs.begin(); 
+ } 
+ if(jx >= crs.size()) jx = 0; 
+ return jx; 
+} 
+ 
+void crossing_dual(unsigned &i, unsigned &j, CrossingSet const & crs) { 
+ Crossing cur = crs[i][j]; 
+ i = cur.getOther(i); 
+// std::cout << i << "\n"; 
+ if(crs[i].empty()) 
+ j = 0; 
+ else 
+ j = std::lower_bound(crs[i].begin(), crs[i].end(), cur, CrossingOrder(i))  crs[i].begin(); 
+} 
+ 
+//locate a crossing on the outside, by casting a ray through the middle of the bbox 
+void outer_crossing(unsigned &ix, unsigned &jx, bool & dir, std::vector<Path> const & ps, CrossingSet const & crs) { 
+ Rect bounds = ps[ix].boundsFast(); 
+ double ry = bounds[Y].middle(); 
+ double max_val = bounds.left(), max_t = 0; 
+ ix = ps.size(); 
+ for(unsigned i = 0; i < ps.size(); i++) { 
+ if(!crs[i].empty()) { 
+ std::vector<double> rts = ps[i].roots(ry, Y); 
+ for(unsigned j = 0; j < rts.size(); j++) { 
+ double val = ps[i].valueAt(rts[j], X); 
+ if(val > max_val) { 
+ ix = i; 
+ max_val = val; 
+ max_t = rts[j]; 
+ } 
+ } 
+ } 
+ } 
+ if(ix != ps.size()) { 
+ dir = ps[ix].valueAt(max_t + 0.01, Y) > 
+ ps[ix].valueAt(max_t  0.01, Y); 
+ jx = crossing_along(max_t, ix, jx, dir, crs[ix]); 
+ } 
+} 
+ 
+std::vector<Path> inner_sanitize(std::vector<Path> const & ps) { 
+ CrossingSet crs(crossings_among(ps)); 
+ 
+ Regions chunks; 
+ 
+ std::vector<bool> used_path(ps.size(), false); 
+ std::vector<std::vector<bool> > visited; 
+ for(unsigned i = 0; i < crs.size(); i++) 
+ visited.push_back(std::vector<bool>(crs[i].size(), false)); 
+ 
+ std::vector<Path> result_paths; 
+ 
+ while(true) { 
+ unsigned ix = 0, jx = 0; 
+ bool dir = false; 
+ 
+ //find an outer crossing by trying various paths and checking if the crossings are used 
+ for(; ix < crs.size(); ix++) { 
+ //TODO: optimize so it doesn't unecessarily check stuff 
+ bool cont = true; 
+ for(unsigned j = 0; j < crs[ix].size(); j++) { 
+ if(!visited[ix][j]) { cont = false; break; } 
+ } 
+ if(cont) continue; 
+ unsigned rix = ix, rjx = jx; 
+ outer_crossing(rix, rjx, dir, ps, crs); 
+ if(rix >= crs.size()  visited[rix][rjx]) continue; 
+ ix = rix; jx = rjx; 
+ break; 
+ } 
+ if(ix == crs.size()) break; 
+ crossing_dual(ix, jx, crs); 
+ 
+ dir = !dir; 
+ 
+ Path res; 
+ do { 
+ visited[ix][jx] = true; 
+ //unsigned nix = ix, njx = jx; 
+ //crossing_dual(nix, njx, crs); 
+ //visited[nix][njx] = true; 
+ unsigned fix = ix, fjx = jx; 
+ 
+ bool new_dir = dir; 
+ 
+ jx = crossing_along(crs[ix][jx].getTime(ix), ix, jx, dir, crs[ix]); 
+ if(crs[ix][jx].a != crs[ix][jx].b) crossing_dual(ix, jx, crs); else new_dir = !new_dir; 
+ jx = pick_coincident(ix, jx, new_dir, ps, crs); 
+ 
+ //unsigned nix = ix, njx = jx; 
+ //crossing_dual(nix, njx, crs); 
+ 
+ Crossing from = crs[fix][fjx], 
+ to = crs[ix][jx]; 
+ if(dir) { 
+ // backwards 
+// std::cout << "r" << ix << "[" << from.getTime(ix) << ", " << to.getTime(ix) << "]\n"; 
+ Path p = ps[ix].portion(from.getTime(ix), to.getTime(ix)).reverse(); 
+ for(unsigned i = 0; i < p.size(); i++) 
+ res.append(p[i]); 
+ } else { 
+ // forwards 
+// std::cout << "f" << ix << "[" << from.getTime(ix) << ", " << to.getTime(ix) << "]\n"; 
+ ps[ix].appendPortionTo(res, from.getTime(ix), to.getTime(ix)); 
+ } 
+ dir = new_dir; 
+ } while(!visited[ix][jx]); 
+// std::cout << "added " << res.size() << "\n"; 
+ result_paths.push_back(res); 
+ } 
+ for(unsigned i = 0; i < crs.size(); i++) { 
+ if(crs[i].empty() && !used_path[i]) 
+ result_paths.push_back(ps[i]); 
+ } 
+ return result_paths; 
+} 
+ 
+Shape sanitize(std::vector<Path> const & ps) { 
+ std::vector<Path> res; 
+ for(unsigned i = 0; i < ps.size(); i++) { 
+ append(res, inner_sanitize(std::vector<Path>(1, ps[i]))); 
+ } 
+ return stopgap_cleaner(res); 
+} 
+ 
+/* WIP sanitizer: 
+unsigned pick_coincident(unsigned ix, unsigned jx, bool pref, bool &rev, std::vector<Path> const &ps, CrossingSet const &crs) { 
+ unsigned ex_jx = jx; 
+ unsigned oix = crs[ix][jx].getOther(ix); 
+ double otime = crs[ix][jx].getTime(oix); 
+ Point cross_point = ps[oix].pointAt(otime), 
+ along = ps[oix].pointAt(otime + (rev ? 0.01 : 0.01))  cross_point, 
+ prev = along; 
+ bool ex_dir = rev; 
+ for(unsigned k = jx; k < crs[ix].size(); k++) { 
+ unsigned koix = crs[ix][k].getOther(ix); 
+ if(koix == oix) { 
+ 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); 
+ Cmp from_along = cmp(cross(along, val), 0); 
+ Cmp c = cmp(from_along, to_prev); 
+ if(c == EQUAL_TO && (from_along == LESS_THAN) == pref) { 
+ ex_jx = k; 
+ prev = val; 
+ ex_dir = dir; 
+ } 
+ } 
+ } 
+ } 
+ rev = ex_dir; 
+ return ex_jx; 
+} 
+ 
+unsigned corner_index(unsigned &i) { 
+ div_t div_res = div(i, 4); 
+ i = div_res.quot; 
+ return div_res.rem; 
+} 
+ 
+bool corner_direction(unsigned ix, unsigned jc, unsigned corner, CrossingSet const &crs) { 
+ if(crs[ix][jc].a == ix) return corner > 1; else return corner %2 == 1; 
+} 
+ 
+Shape sanitize(std::vector<Path> const & ps) { 
+ CrossingSet crs = crossings_among(ps); 
+ 
+ //Keep track of which CORNERS we've hit. 
+ // FF FR RF RR, first is A dir, second B dir 
+ std::vector<std::vector<bool> > visited; 
+ for(unsigned i = 0; i < crs.size(); i++) 
+ visited.push_back(std::vector<bool>(crs[i].size()*4, false)); 
+ 
+ Regions chunks; 
+ while(true) { 
+ unsigned i, j; 
+ first_false(visited, i, j); 
+ unsigned corner = corner_index(j); 
+ 
+ if(i == visited.size()) break; 
+ 
+ bool dir = corner_direction(i, j, corner, crs); 
+ 
+ //Figure out whether we hug the path cw or ccw, based on the orientation of the initial corner: 
+ unsigned oix = crs[i][j].getOther(i); 
+ double otime = crs[i][j].getTime(oix); 
+ bool odir = (oix == crs[i][j].a) ? corner > 1 : corner % 2 == 1; 
+ Point cross_point = ps[oix].pointAt(otime), 
+ along = ps[oix].pointAt(otime + (odir ? 0.01 : 0.01))  cross_point, 
+ val = ps[i].pointAt(crs[i][j].getTime(i) + (dir ? 0.01 : 0.01))  cross_point; 
+ 
+ Cmp from_along = cmp(cross(along, val), 0); 
+ bool cw = from_along == LESS_THAN; 
+ std::cout << "cw = " << cw << "\n"; 
+ Path res; 
+ do { 
+ Crossing cur = crs[i][j]; 
+ visited[i][j*4+corner] = true; 
+ 
+ unsigned fix = i, fjx = j; 
+ crossing_dual(i, j, crs); 
+ visited[i][j*4+corner] = true; 
+ i = fix; j = fjx; 
+ 
+ j = crossing_along(crs[i][j].getTime(i), i, j, dir, crs[i]); 
+ 
+ crossing_dual(i, j, crs); 
+ 
+ bool new_dir = dir; 
+ pick_coincident(i, j, cw, new_dir, ps, crs); 
+ 
+ Crossing from = crs[fix][fjx], 
+ to = crs[i][j]; 
+ if(dir) { 
+ // backwards 
+ std::cout << "r" << i << "[" << to.getTime(i) << ", " << from.getTime(i) << "]\n"; 
+ Path p = ps[i].portion(to.getTime(i) + 0.001, from.getTime(i)).reverse(); 
+ for(unsigned k = 0; k < p.size(); k++) 
+ res.append(p[k]); 
+ } else { 
+ // forwards 
+ std::cout << "f" << i << "[" << from.getTime(i) << ", " << to.getTime(i) << "]\n"; 
+ ps[i].appendPortionTo(res, from.getTime(i) + 0.001, to.getTime(i)); 
+ } 
+ if(i == to.a) 
+ corner = (new_dir ? 2 : 0) + (dir ? 1 : 0); 
+ else 
+ corner = (new_dir ? 1 : 0) + (dir ? 2 : 0); 
+ dir = new_dir; 
+ } while(!visited[i][j*4+corner]); 
+ chunks.push_back(Region(res)); 
+// if(use) { 
+// chunks.push_back(Region(res, true)); 
+// } 
+ } 
+ return Shape(chunks); 
+// return ret; 
+} */ 
+ 
+/* This transforms a shape by a matrix. In the case that the matrix flips 
+ * the shape, it reverses the paths in order to preserve the fill. 
+ */ 
+Shape Shape::operator*(Matrix const &m) const { 
+ Shape ret; 
+ for(unsigned i = 0; i < size(); i++) 
+ ret.content.push_back(content[i] * m); 
+ ret.fill = fill; 
+ return ret; 
+} 
+ 
+// Inverse is a boolean not, and simply reverses all the paths & fill flags 
+Shape Shape::inverse() const { 
+ Shape ret; 
+ for(unsigned i = 0; i < size(); i++) 
+ ret.content.push_back(content[i].inverse()); 
+ ret.fill = !fill; 
+ return ret; 
+} 
+ 
+bool Shape::contains(Point const &p) const { 
+ std::vector<unsigned> containers = containment_list(p); 
+ if(containers.empty()) return !isFill(); 
+ unsigned ix = *min_element(containers.begin(), containers.end(), ContainmentOrder(&content)); 
+ return content[ix].isFill(); 
+} 
+ 
+Shape stopgap_cleaner(std::vector<Path> const &ps) { 
+ if(ps.empty()) return Shape(false); 
+ Shape ret; 
+ for(unsigned i = 0; i < ps.size(); i++) 
+ add_to_shape(ret, ps[i], inner_winding(ps[i], ps) % 2 != 0); 
+ return ret; 
+} 
+ 
+bool Shape::inside_invariants() const { //semislow & easy to violate 
+ for(unsigned i = 0; i < size(); i++) 
+ if( logical_xor(content[i].isFill(), contains(content[i].boundary.initialPoint())) ) return false; 
+ return true; 
+} 
+bool Shape::region_invariants() const { //semislow 
+ for(unsigned i = 0; i < size(); i++) 
+ if(!content[i].invariants()) return false; 
+ return true; 
+} 
+bool Shape::cross_invariants() const { //slow 
+ CrossingSet crs; // = crossings_among(paths_from_regions(content)); 
+ for(unsigned i = 0; i < crs.size(); i++) 
+ if(!crs[i].empty()) return false; 
+ return true; 
+} 
+ 
+bool Shape::invariants() const { 
+ return inside_invariants() && region_invariants() && cross_invariants(); 
+} 
+ 
+} 
Index: Scribus/scribus/third_party/lib2geom/basicintersection.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/basicintersection.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/basicintersection.cpp (revision 14937) 
@@ 0,0 +1,365 @@ 
+#include "basicintersection.h" 
+#include "exception.h" 
+#include "angle.h" 
+ 
+#ifndef M_SQRT2 
+#define M_SQRT2 1.41421356237309504880 
+#endif 
+ 
+ 
+unsigned intersect_steps = 0; 
+ 
+using std::vector; 
+namespace Geom { 
+ 
+class OldBezier { 
+public: 
+ std::vector<Geom::Point> p; 
+ OldBezier() { 
+ } 
+ void split(double t, OldBezier &a, OldBezier &b) const; 
+ 
+ ~OldBezier() {} 
+ 
+ void bounds(double &minax, double &maxax, 
+ double &minay, double &maxay) { 
+ // Compute bounding box for a 
+ minax = p[0][X]; // These are the most likely to be extremal 
+ maxax = p.back()[X]; 
+ if( minax > maxax ) 
+ std::swap(minax, maxax); 
+ for(unsigned i = 1; i < p.size()1; i++) { 
+ if( p[i][X] < minax ) 
+ minax = p[i][X]; 
+ else if( p[i][X] > maxax ) 
+ maxax = p[i][X]; 
+ } 
+ 
+ minay = p[0][Y]; // These are the most likely to be extremal 
+ maxay = p.back()[Y]; 
+ if( minay > maxay ) 
+ std::swap(minay, maxay); 
+ for(unsigned i = 1; i < p.size()1; i++) { 
+ if( p[i][Y] < minay ) 
+ minay = p[i][Y]; 
+ else if( p[i][Y] > maxay ) 
+ maxay = p[i][Y]; 
+ } 
+ 
+ } 
+ 
+}; 
+ 
+static std::vector<std::pair<double, double> > 
+find_intersections( OldBezier a, OldBezier b); 
+ 
+static std::vector<std::pair<double, double> > 
+find_self_intersections(OldBezier const &Sb, D2<SBasis> const & A); 
+ 
+std::vector<std::pair<double, double> > 
+find_intersections( vector<Geom::Point> const & A, 
+ vector<Geom::Point> const & B) { 
+ OldBezier a, b; 
+ a.p = A; 
+ b.p = B; 
+ return find_intersections(a,b); 
+} 
+ 
+std::vector<std::pair<double, double> > 
+find_self_intersections(OldBezier const &Sb) { 
+ throwNotImplemented(0); 
+} 
+ 
+std::vector<std::pair<double, double> > 
+find_self_intersections(D2<SBasis> const & A) { 
+ OldBezier Sb; 
+ Sb.p = sbasis_to_bezier(A); 
+ return find_self_intersections(Sb, A); 
+} 
+ 
+ 
+static std::vector<std::pair<double, double> > 
+find_self_intersections(OldBezier const &Sb, D2<SBasis> const & A) { 
+ 
+ 
+ vector<double> dr = roots(derivative(A[X])); 
+ { 
+ vector<double> dyr = roots(derivative(A[Y])); 
+ dr.insert(dr.begin(), dyr.begin(), dyr.end()); 
+ } 
+ dr.push_back(0); 
+ dr.push_back(1); 
+ // We want to be sure that we have no empty segments 
+ sort(dr.begin(), dr.end()); 
+ unique(dr.begin(), dr.end()); 
+ 
+ std::vector<std::pair<double, double> > all_si; 
+ 
+ vector<OldBezier> pieces; 
+ { 
+ OldBezier in = Sb, l, r; 
+ for(unsigned i = 0; i < dr.size()1; i++) { 
+ in.split((dr[i+1]dr[i]) / (1  dr[i]), l, r); 
+ pieces.push_back(l); 
+ in = r; 
+ } 
+ } 
+ for(unsigned i = 0; i < dr.size()1; i++) { 
+ for(unsigned j = i+1; j < dr.size()1; j++) { 
+ std::vector<std::pair<double, double> > section = 
+ find_intersections( pieces[i], pieces[j]); 
+ for(unsigned k = 0; k < section.size(); k++) { 
+ double l = section[k].first; 
+ double r = section[k].second; 
+// XXX: This condition will prune out false positives, but it might create some false negatives. Todo: Confirm it is correct. 
+ if(j == i+1) 
+ if((l == 1) && (r == 0)) 
+ continue; 
+ all_si.push_back(std::make_pair((1l)*dr[i] + l*dr[i+1], 
+ (1r)*dr[j] + r*dr[j+1])); 
+ } 
+ } 
+ } 
+ 
+ // Because i is in order, all_si should be roughly already in order? 
+ //sort(all_si.begin(), all_si.end()); 
+ //unique(all_si.begin(), all_si.end()); 
+ 
+ return all_si; 
+} 
+ 
+/* The value of 1.0 / (1L<<14) is enough for most applications */ 
+const double INV_EPS = (1L<<14); 
+ 
+/* 
+ * split the curve at the midpoint, returning an array with the two parts 
+ * Temporary storage is minimized by using part of the storage for the result 
+ * to hold an intermediate value until it is no longer needed. 
+ */ 
+void OldBezier::split(double t, OldBezier &left, OldBezier &right) const { 
+ const unsigned sz = p.size(); 
+ std::vector<Geom::Point> Vtemp(p); 
+ 
+ left.p.resize(sz); 
+ right.p.resize(sz); 
+ left.p[0] = Vtemp[0]; 
+ right.p[sz1] = Vtemp[sz1]; 
+ /* Triangle computation */ 
+ for (unsigned i = 1; i < sz; i++) { 
+ for (unsigned j = 0; j < sz  i; j++) { 
+ Vtemp[j] = lerp(t, Vtemp[j], Vtemp[j+1]); 
+ } 
+ left.p[i] = Vtemp[0]; 
+ right.p[sz1i] = Vtemp[sz1i]; 
+ } 
+} 
+ 
+ 
+/* 
+ * Test the bounding boxes of two OldBezier curves for interference. 
+ * Several observations: 
+ * First, it is cheaper to compute the bounding box of the second curve 
+ * and test its bounding box for interference than to use a more direct 
+ * approach of comparing all control points of the second curve with 
+ * the various edges of the bounding box of the first curve to test 
+ * for interference. 
+ * Second, after a few subdivisions it is highly probable that two corners 
+ * of the bounding box of a given Bezier curve are the first and last 
+ * control point. Once this happens once, it happens for all subsequent 
+ * subcurves. It might be worth putting in a test and then shortcircuit 
+ * code for further subdivision levels. 
+ * Third, in the final comparison (the interference test) the comparisons 
+ * should both permit equality. We want to find intersections even if they 
+ * occur at the ends of segments. 
+ * Finally, there are tighter bounding boxes that can be derived. It isn't 
+ * clear whether the higher probability of rejection (and hence fewer 
+ * subdivisions and tests) is worth the extra work. 
+ */ 
+ 
+bool intersect_BB( OldBezier a, OldBezier b ) { 
+ double minax, maxax, minay, maxay; 
+ a.bounds(minax, maxax, minay, maxay); 
+ double minbx, maxbx, minby, maxby; 
+ b.bounds(minbx, maxbx, minby, maxby); 
+ // Test bounding box of b against bounding box of a 
+ // Not >= : need boundary case 
+ return !( ( minax > maxbx )  ( minay > maxby )  
+ ( minbx > maxax )  ( minby > maxay ) ); 
+} 
+ 
+/* 
+ * Recursively intersect two curves keeping track of their real parameters 
+ * and depths of intersection. 
+ * The results are returned in a 2D array of doubles indicating the parameters 
+ * for which intersections are found. The parameters are in the order the 
+ * intersections were found, which is probably not in sorted order. 
+ * When an intersection is found, the parameter value for each of the two 
+ * is stored in the index elements array, and the index is incremented. 
+ * 
+ * If either of the curves has subdivisions left before it is straight 
+ * (depth > 0) 
+ * that curve (possibly both) is (are) subdivided at its (their) midpoint(s). 
+ * the depth(s) is (are) decremented, and the parameter value(s) corresponding 
+ * to the midpoints(s) is (are) computed. 
+ * Then each of the subcurves of one curve is intersected with each of the 
+ * subcurves of the other curve, first by testing the bounding boxes for 
+ * interference. If there is any bounding box interference, the corresponding 
+ * subcurves are recursively intersected. 
+ * 
+ * If neither curve has subdivisions left, the line segments from the first 
+ * to last control point of each segment are intersected. (Actually the 
+ * only the parameter value corresponding to the intersection point is found). 
+ * 
+ * The apriori flatness test is probably more efficient than testing at each 
+ * level of recursion, although a test after three or four levels would 
+ * probably be worthwhile, since many curves become flat faster than their 
+ * asymptotic rate for the first few levels of recursion. 
+ * 
+ * The bounding box test fails much more frequently than it succeeds, providing 
+ * substantial pruning of the search space. 
+ * 
+ * Each (sub)curve is subdivided only once, hence it is not possible that for 
+ * one final line intersection test the subdivision was at one level, while 
+ * for another final line intersection test the subdivision (of the same curve) 
+ * was at another. Since the line segments share endpoints, the intersection 
+ * is robust: a neartangential intersection will yield zero or two 
+ * intersections. 
+ */ 
+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> > ¶meters) 
+{ 
+ intersect_steps ++; 
+ if( deptha > 0 ) 
+ { 
+ OldBezier A[2]; 
+ a.split(0.5, A[0], A[1]); 
+ double tmid = (t0+t1)*0.5; 
+ deptha; 
+ if( depthb > 0 ) 
+ { 
+ OldBezier B[2]; 
+ b.split(0.5, B[0], B[1]); 
+ double umid = (u0+u1)*0.5; 
+ depthb; 
+ if( intersect_BB( A[0], B[0] ) ) 
+ recursively_intersect( A[0], t0, tmid, deptha, 
+ B[0], u0, umid, depthb, 
+ parameters ); 
+ if( intersect_BB( A[1], B[0] ) ) 
+ recursively_intersect( A[1], tmid, t1, deptha, 
+ B[0], u0, umid, depthb, 
+ parameters ); 
+ if( intersect_BB( A[0], B[1] ) ) 
+ recursively_intersect( A[0], t0, tmid, deptha, 
+ B[1], umid, u1, depthb, 
+ parameters ); 
+ if( intersect_BB( A[1], B[1] ) ) 
+ recursively_intersect( A[1], tmid, t1, deptha, 
+ B[1], umid, u1, depthb, 
+ parameters ); 
+ } 
+ else 
+ { 
+ if( intersect_BB( A[0], b ) ) 
+ recursively_intersect( A[0], t0, tmid, deptha, 
+ b, u0, u1, depthb, 
+ parameters ); 
+ if( intersect_BB( A[1], b ) ) 
+ recursively_intersect( A[1], tmid, t1, deptha, 
+ b, u0, u1, depthb, 
+ parameters ); 
+ } 
+ } 
+ else 
+ if( depthb > 0 ) 
+ { 
+ OldBezier B[2]; 
+ b.split(0.5, B[0], B[1]); 
+ double umid = (u0 + u1)*0.5; 
+ depthb; 
+ if( intersect_BB( a, B[0] ) ) 
+ recursively_intersect( a, t0, t1, deptha, 
+ B[0], u0, umid, depthb, 
+ parameters ); 
+ if( intersect_BB( a, B[1] ) ) 
+ recursively_intersect( a, t0, t1, deptha, 
+ B[0], umid, u1, depthb, 
+ parameters ); 
+ } 
+ else // Both segments are fully subdivided; now do line segments 
+ { 
+ double xlk = a.p.back()[X]  a.p[0][X]; 
+ double ylk = a.p.back()[Y]  a.p[0][Y]; 
+ double xnm = b.p.back()[X]  b.p[0][X]; 
+ double ynm = b.p.back()[Y]  b.p[0][Y]; 
+ double xmk = b.p[0][X]  a.p[0][X]; 
+ double ymk = b.p[0][Y]  a.p[0][Y]; 
+ double det = xnm * ylk  ynm * xlk; 
+ if( 1.0 + det == 1.0 ) 
+ return; 
+ else 
+ { 
+ double detinv = 1.0 / det; 
+ double s = ( xnm * ymk  ynm *xmk ) * detinv; 
+ double t = ( xlk * ymk  ylk * xmk ) * detinv; 
+ if( ( s < 0.0 )  ( s > 1.0 )  ( t < 0.0 )  ( t > 1.0 ) ) 
+ return; 
+ parameters.push_back(std::pair<double, double>(t0 + s * ( t1  t0 ), 
+ u0 + t * ( u1  u0 ))); 
+ } 
+ } 
+} 
+ 
+inline double log4( double x ) { return log(x)/log(4.); } 
+ 
+/* 
+ * Wang's theorem is used to estimate the level of subdivision required, 
+ * but only if the bounding boxes interfere at the top level. 
+ * Assuming there is a possible intersection, recursively_intersect is 
+ * used to find all the parameters corresponding to intersection points. 
+ * these are then sorted and returned in an array. 
+ */ 
+ 
+double Lmax(Point p) { 
+ return std::max(fabs(p[X]), fabs(p[Y])); 
+} 
+ 
+unsigned wangs_theorem(OldBezier a) { 
+ return 12; // seems a good approximation! 
+ double la1 = Lmax( ( a.p[2]  a.p[1] )  (a.p[1]  a.p[0]) ); 
+ double la2 = Lmax( ( a.p[3]  a.p[2] )  (a.p[2]  a.p[1]) ); 
+ double l0 = std::max(la1, la2); 
+ unsigned ra; 
+ if( l0 * 0.75 * M_SQRT2 + 1.0 == 1.0 ) 
+ ra = 0; 
+ else 
+ ra = (unsigned)ceil( log4( M_SQRT2 * 6.0 / 8.0 * INV_EPS * l0 ) ); 
+ std::cout << ra << std::endl; 
+ return ra; 
+} 
+ 
+std::vector<std::pair<double, double> > find_intersections( OldBezier a, OldBezier b) 
+{ 
+ std::vector<std::pair<double, double> > parameters; 
+ if( intersect_BB( a, b ) ) 
+ { 
+ recursively_intersect( a, 0., 1., wangs_theorem(a), 
+ b, 0., 1., wangs_theorem(b), 
+ parameters); 
+ } 
+ std::sort(parameters.begin(), parameters.end()); 
+ return parameters; 
+} 
+}; 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/path.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/path.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/path.cpp (revision 14937) 
@@ 0,0 +1,258 @@ 
+/* 
+ * Path  Series of continuous curves 
+ * 
+ * Copyright 2007 MenTaLguY <mental@rydia.net> 
+ * 
+ * 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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; 
+} 
+ 
+void Path::swap(Path &other) { 
+ std::swap(curves_, other.curves_); 
+ std::swap(closed_, other.closed_); 
+ std::swap(*final_, *other.final_); 
+ curves_[curves_.size()1] = final_; 
+ other.curves_[other.curves_.size()1] = other.final_; 
+} 
+ 
+Rect Path::boundsFast() const { 
+ Rect bounds=front().boundsFast(); 
+ for ( const_iterator iter=++begin(); iter != end() ; ++iter ) { 
+ bounds.unionWith(iter>boundsFast()); 
+ } 
+ return bounds; 
+} 
+ 
+Rect Path::boundsExact() const { 
+ Rect bounds=front().boundsExact(); 
+ for ( const_iterator iter=++begin(); iter != end() ; ++iter ) { 
+ bounds.unionWith(iter>boundsExact()); 
+ } 
+ return bounds; 
+} 
+ 
+template<typename iter> 
+iter inc(iter const &x, unsigned n) { 
+ iter ret = x; 
+ for(unsigned i = 0; i < n; i++) 
+ ret++; 
+ return ret; 
+} 
+ 
+//This assumes that you can't be perfect in your tvals, and as such, tweaks the start 
+void Path::appendPortionTo(Path &ret, double from, double to) const { 
+ assert(from >= 0 && to >= 0); 
+ if(to == 0) to = size()+0.999999; 
+ if(from == to) { return; } 
+ double fi, ti; 
+ double ff = modf(from, &fi), tf = modf(to, &ti); 
+ if(tf == 0) { ti; tf = 1; } 
+ const_iterator fromi = inc(begin(), (unsigned)fi); 
+ if(fi == ti && from < to) { 
+ Curve *v = fromi>portion(ff, tf); 
+ ret.append(*v); 
+ delete v; 
+ return; 
+ } 
+ const_iterator toi = inc(begin(), (unsigned)ti); 
+ if(ff != 1.) { 
+ Curve *fromv = fromi>portion(ff, 1.); 
+ //fromv>setInitial(ret.finalPoint()); 
+ ret.append(*fromv); 
+ delete fromv; 
+ } 
+ if(from >= to) { 
+ const_iterator ender = end(); 
+ if(ender>initialPoint() == ender>finalPoint()) ender++; 
+ ret.insert(ret.end(), ++fromi, ender); 
+ ret.insert(ret.end(), begin(), toi); 
+ } else { 
+ ret.insert(ret.end(), ++fromi, toi); 
+ } 
+ Curve *tov = toi>portion(0., tf); 
+ ret.append(*tov); 
+ delete tov; 
+} 
+ 
+const double eps = .1; 
+ 
+void Path::append(Curve const &curve) { 
+ if ( curves_.front() != final_ && !are_near(curve.initialPoint(), (*final_)[0], eps) ) { 
+ throwContinuityError(0); 
+ } 
+ do_append(curve.duplicate()); 
+} 
+ 
+void Path::append(D2<SBasis> const &curve) { 
+ if ( curves_.front() != final_ ) { 
+ for ( int i = 0 ; i < 2 ; ++i ) { 
+ if ( !are_near(curve[i][0][0], (*final_)[0][i], eps) ) { 
+ throwContinuityError(0); 
+ } 
+ } 
+ } 
+ do_append(new SBasisCurve(curve)); 
+} 
+ 
+void Path::do_update(Sequence::iterator first_replaced, 
+ Sequence::iterator last_replaced, 
+ Sequence::iterator first, 
+ Sequence::iterator last) 
+{ 
+ // note: modifies the contents of [first,last) 
+ 
+ check_continuity(first_replaced, last_replaced, first, last); 
+ delete_range(first_replaced, last_replaced); 
+ if ( ( last  first ) == ( last_replaced  first_replaced ) ) { 
+ std::copy(first, last, first_replaced); 
+ } else { 
+ // this approach depends on std::vector's behavior WRT iterator stability 
+ curves_.erase(first_replaced, last_replaced); 
+ curves_.insert(first_replaced, first, last); 
+ } 
+ 
+ if ( curves_.front() != final_ ) { 
+ final_>setPoint(0, back().finalPoint()); 
+ final_>setPoint(1, front().initialPoint()); 
+ } 
+} 
+ 
+void Path::do_append(Curve *curve) { 
+ if ( curves_.front() == final_ ) { 
+ final_>setPoint(1, curve>initialPoint()); 
+ } 
+ curves_.insert(curves_.end()1, curve); 
+ final_>setPoint(0, curve>finalPoint()); 
+} 
+ 
+void Path::delete_range(Sequence::iterator first, Sequence::iterator last) { 
+ for ( Sequence::iterator iter=first ; iter != last ; ++iter ) { 
+ delete *iter; 
+ } 
+} 
+ 
+void Path::check_continuity(Sequence::iterator first_replaced, 
+ Sequence::iterator last_replaced, 
+ Sequence::iterator first, 
+ Sequence::iterator last) 
+{ 
+ if ( first != last ) { 
+ if ( first_replaced != curves_.begin() ) { 
+ if ( !are_near( (*first_replaced)>initialPoint(), (*first)>initialPoint(), eps ) ) { 
+ throwContinuityError(0); 
+ } 
+ } 
+ if ( last_replaced != (curves_.end()1) ) { 
+ if ( !are_near( (*(last_replaced1))>finalPoint(), (*(last1))>finalPoint(), eps ) ) { 
+ throwContinuityError(0); 
+ } 
+ } 
+ } else if ( first_replaced != last_replaced && first_replaced != curves_.begin() && last_replaced != curves_.end()1) { 
+ if ( !are_near((*first_replaced)>initialPoint(), (*(last_replaced1))>finalPoint(), eps ) ) { 
+ throwContinuityError(0); 
+ } 
+ } 
+} 
+ 
+Rect SVGEllipticalArc::boundsFast() const { 
+ throwNotImplemented(0); 
+} 
+Rect SVGEllipticalArc::boundsExact() const { 
+ throwNotImplemented(0); 
+} 
+Rect SVGEllipticalArc::boundsLocal(Interval i, unsigned deg) const { 
+ throwNotImplemented(0); 
+} 
+ 
+std::vector<Point> SVGEllipticalArc::pointAndDerivatives(Coord t, unsigned n) const { 
+ throwNotImplemented(0); 
+} 
+ 
+std::vector<double> SVGEllipticalArc::roots(double v, Dim2 d) const { 
+ throwNotImplemented(0); 
+} 
+ 
+D2<SBasis> SVGEllipticalArc::toSBasis() const { 
+ return D2<SBasis>(Linear(initial_[X], final_[X]), Linear(initial_[Y], final_[Y])); 
+} 
+ 
+} 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(substatementopen . 0)) 
+ indenttabsmode:nil 
+ cbraceoffset:0 
+ fillcolumn:99 
+ End: 
+ vim: filetype=cpp:expandtab:shiftwidth=2:tabstop=8:softtabstop=2 : 
+*/ 
Index: Scribus/scribus/third_party/lib2geom/pathintersection.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/pathintersection.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/pathintersection.cpp (revision 14937) 
@@ 0,0 +1,597 @@ 
+#include "pathintersection.h" 
+ 
+#include "ord.h" 
+ 
+//for path_direction: 
+#include "sbasisgeometric.h" 
+ 
+namespace Geom { 
+ 
+/* This function computes the winding of the path, given a reference point. 
+ * Positive values correspond to counterclockwise in the mathematical coordinate system, 
+ * and clockwise in screen coordinates. This particular implementation casts a ray in 
+ * the positive x direction. It iterates the path, checking for intersection with the 
+ * bounding boxes. If an intersection is found, the initial/final Y value of the curve is 
+ * used to derive a delta on the winding value. If the point is within the bounding box, 
+ * the curve specific winding function is called. 
+ */ 
+int winding(Path const &path, Point p) { 
+ //start on a segment which is not a horizontal line with y = p[y] 
+ Path::const_iterator start; 
+ for(Path::const_iterator iter = path.begin(); ; ++iter) { 
+ if(iter == path.end_closed()) { return 0; } 
+ if(iter>initialPoint()[Y]!=p[Y]) { start = iter; break; } 
+ if(iter>finalPoint()[Y]!=p[Y]) { start = iter; break; } 
+ if(iter>boundsFast().height()!=0.){ start = iter; break; } 
+ } 
+ int wind = 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 ) 
+ { 
+ cnt++; 
+ if(cnt > path.size()) return wind; //some bug makes this required 
+ starting = false; 
+ Rect bounds = iter>boundsFast(); 
+ Coord x = p[X], y = p[Y]; 
+ 
+ if(x > bounds.right()  !bounds[Y].contains(y)) continue; //ray doesn't intersect box 
+ 
+ Point final = iter>finalPoint(); 
+ Point initial = iter>initialPoint(); 
+ Cmp final_to_ray = cmp(final[Y], y); 
+ Cmp initial_to_ray = cmp(initial[Y], y); 
+ 
+ // if y is included, these will have opposite values, giving order. 
+ Cmp c = cmp(final_to_ray, initial_to_ray); 
+ if(x < bounds.left()) { 
+ // ray goes through bbox 
+ // winding delta determined by position of endpoints 
+ if(final_to_ray != EQUAL_TO) { 
+ wind += int(c); // GT = counterclockwise = 1; LT = clockwise = 1; EQ = notincluded = 0 
+ //std::cout << int(c) << " "; 
+ goto cont; 
+ } 
+ } else { 
+ //inside bbox, use custom percurve winding thingie 
+ int delt = iter>winding(p); 
+ wind += delt; 
+ //std::cout << "n" << delt << " "; 
+ } 
+ //Handling the special case of an endpoint on the ray: 
+ if(final[Y] == y) { 
+ //Traverse segments until it breaks away from y 
+ //99.9% of the time this will happen the first go 
+ Path::const_iterator next = iter; 
+ next++; 
+ for(; ; next++) { 
+ if(next == path.end_closed()) next = path.begin(); 
+ Rect bnds = next>boundsFast(); 
+ //TODO: X considerations 
+ if(bnds.height() > 0) { 
+ //It has diverged 
+ if(bnds.contains(p)) { 
+ const double fudge = 0.01; 
+ if(cmp(y, next>valueAt(fudge, Y)) == initial_to_ray) { 
+ wind += int(c); 
+ // std::cout << "!!!!!" << int(c) << " "; 
+ } 
+ iter = next; // No increment, as the rest of the thing hasn't been counted. 
+ } else { 
+ Coord ny = next>initialPoint()[Y]; 
+ if(cmp(y, ny) == initial_to_ray) { 
+ //Is a continuation through the ray, so counts windingwise 
+ wind += int(c); 
+ // std::cout << "!!!!!" << int(c) << " "; 
+ } 
+ iter = ++next; 
+ } 
+ goto cont; 
+ } 
+ if(next==start) return wind; 
+ } 
+ //Looks like it looped, which means everything's flat 
+ return 0; 
+ } 
+ 
+ cont:(void)0; 
+ } 
+ return wind; 
+} 
+ 
+/* This function should only be applied to simple paths (regions), as otherwise 
+ * a boolean winding direction is undefined. It returns true for fill, false for 
+ * hole. Defaults to using the sign of area when it reaches funny cases. 
+ */ 
+bool path_direction(Path const &p) { 
+ if(p.empty()) return false; 
+ //could probably be more efficient, but this is a quick job 
+ double y = p.initialPoint()[Y]; 
+ double x = p.initialPoint()[X]; 
+ Cmp res = cmp(p[0].finalPoint()[Y], y); 
+ goto doh; 
+ for(unsigned i = 1; i <= p.size(); i++) { 
+ Cmp final_to_ray = cmp(p[i].finalPoint()[Y], y); 
+ Cmp initial_to_ray = cmp(p[i].initialPoint()[Y], y); 
+ // if y is included, these will have opposite values, giving order. 
+ Cmp c = cmp(final_to_ray, initial_to_ray); 
+ if(c != EQUAL_TO) { 
+ std::vector<double> rs = p[i].roots(y, Y); 
+ for(unsigned j = 0; j < rs.size(); j++) { 
+ double nx = p[i].valueAt(rs[j], X); 
+ if(nx > x) { 
+ x = nx; 
+ res = c; 
+ } 
+ } 
+ } else if(final_to_ray == EQUAL_TO) goto doh; 
+ } 
+ return res < 0; 
+ 
+ doh: 
+ //Otherwise fallback on area 
+ 
+ Piecewise<D2<SBasis> > pw = p.toPwSb(); 
+ double area; 
+ Point centre; 
+ Geom::centroid(pw, centre, area); 
+ return area > 0; 
+} 
+ 
+//pair intersect code based on njh's pairintersect 
+ 
+// A little sugar for appending a list to another 
+template<typename T> 
+void append(T &a, T const &b) { 
+ a.insert(a.end(), b.begin(), b.end()); 
+} 
+ 
+/* Finds the intersection between the lines defined by A0 & A1, and B0 & B1. 
+ * Returns through the last 3 parameters, returning the tvalues on the lines 
+ * and the crossproduct of the deltas (a useful byproduct). The return value 
+ * indicates if the time values are within their proper range on the line segments. 
+ */ 
+bool 
+linear_intersect(Point A0, Point A1, Point B0, Point B1, 
+ double &tA, double &tB, double &det) { 
+ // kramers rule as cross products 
+ Point Ad = A1  A0, 
+ Bd = B1  B0, 
+ d = B0  A0; 
+ det = cross(Ad, Bd); 
+ if( 1.0 + det == 1.0 ) 
+ return false; 
+ else 
+ { 
+ double detinv = 1.0 / det; 
+ tA = cross(d, Bd) * detinv; 
+ tB = cross(d, Ad) * detinv; 
+ return tA >= 0. && tA <= 1. && tB >= 0. && tB <= 1.; 
+ } 
+} 
+ 
+/* This uses the local bounds functions of curves to generically intersect two. 
+ * It passes in the curves, time intervals, and keeps track of depth, while 
+ * returning the results through the Crossings parameter. 
+ */ 
+void pair_intersect(Curve const & A, double Al, double Ah, 
+ Curve const & B, double Bl, double Bh, 
+ Crossings &ret, unsigned depth=0) { 
+ // std::cout << depth << "(" << Al << ", " << Ah << ")\n"; 
+ Rect Ar = A.boundsLocal(Interval(Al, Ah)); 
+ if(Ar.isEmpty()) return; 
+ 
+ Rect Br = B.boundsLocal(Interval(Bl, Bh)); 
+ if(Br.isEmpty()) return; 
+ 
+ if(!Ar.intersects(Br)) return; 
+ 
+ //Checks the general linearity of the function 
+ if((depth > 12)) { //  (A.boundsLocal(Interval(Al, Ah), 1).maxExtent() < 0.1 
+ //&& B.boundsLocal(Interval(Bl, Bh), 1).maxExtent() < 0.1)) { 
+ double tA, tB, c; 
+ if(linear_intersect(A.pointAt(Al), A.pointAt(Ah), 
+ B.pointAt(Bl), B.pointAt(Bh), 
+ tA, tB, c)) { 
+ tA = tA * (Ah  Al) + Al; 
+ tB = tB * (Bh  Bl) + Bl; 
+ if(depth % 2) 
+ ret.push_back(Crossing(tB, tA, c < 0)); 
+ else 
+ ret.push_back(Crossing(tA, tB, c > 0)); 
+ return; 
+ } 
+ } 
+ if(depth > 12) return; 
+ double mid = (Bl + Bh)/2; 
+ pair_intersect(B, Bl, mid, 
+ A, Al, Ah, 
+ ret, depth+1); 
+ pair_intersect(B, mid, Bh, 
+ A, Al, Ah, 
+ ret, depth+1); 
+} 
+ 
+// A simple wrapper around pair_intersect 
+Crossings SimpleCrosser::crossings(Curve const &a, Curve const &b) { 
+ Crossings ret; 
+ pair_intersect(a, 0, 1, b, 0, 1, ret); 
+ return ret; 
+} 
+ 
+/* Takes two paths and time ranges on them, with the invariant that the 
+ * paths are monotonic on the range. Splits A when the linear intersection 
+ * doesn't exist or is inaccurate. Uses the fact that it is monotonic to 
+ * do very fast local bounds. 
+ */ 
+void mono_pair(Path const &A, double Al, double Ah, 
+ Path const &B, double Bl, double Bh, 
+ Crossings &ret, double tol, unsigned depth = 0) { 
+ if( Al >= Ah  Bl >= Bh) return; 
+ // std::cout << " " << depth << "[" << Al << ", " << Ah << "]" << "[" << Bl << ", " << Bh << "]"; 
+ 
+ Point A0 = A.pointAt(Al), A1 = A.pointAt(Ah), 
+ B0 = B.pointAt(Bl), B1 = B.pointAt(Bh); 
+ //inline code that this implies? (without rect/interval construction) 
+ if(!Rect(A0, A1).intersects(Rect(B0, B1))  A0 == A1  B0 == B1) return; 
+ 
+ //Checks the general linearity of the function 
+ //if((depth > 12)  (A.boundsLocal(Interval(Al, Ah), 1).maxExtent() < 0.1 
+ // && B.boundsLocal(Interval(Bl, Bh), 1).maxExtent() < 0.1)) { 
+ double tA, tB, c; 
+ if(linear_intersect(A0, A1, B0, B1, 
+ tA, tB, c)) { 
+ tA = tA * (Ah  Al) + Al; 
+ tB = tB * (Bh  Bl) + Bl; 
+ if(depth % 2) 
+ ret.push_back(Crossing(tB, tA, c < 0)); 
+ else 
+ ret.push_back(Crossing(tA, tB, c > 0)); 
+ return; 
+ } 
+ //} 
+ if(depth > 12) return; 
+ double mid = (Bl + Bh)/2; 
+ mono_pair(B, Bl, mid, 
+ A, Al, Ah, 
+ ret, depth+1); 
+ mono_pair(B, mid, Bh, 
+ A, Al, Ah, 
+ ret, depth+1); 
+} 
+ 
+// This returns the times when the x or y derivative is 0 in the curve. 
+std::vector<double> curve_mono_splits(Curve const &d) { 
+ std::vector<double> rs = d.roots(0, X); 
+ append(rs, d.roots(0, Y)); 
+ std::sort(rs.begin(), rs.end()); 
+ return rs; 
+} 
+ 
+// Convenience function to add a value to each entry in a vector of doubles. 
+std::vector<double> offset_doubles(std::vector<double> const &x, double offs) { 
+ std::vector<double> ret; 
+ for(unsigned i = 0; i < x.size(); i++) { 
+ ret.push_back(x[i] + offs); 
+ } 
+ return ret; 
+} 
+ 
+/* Finds all the monotonic splits for a path. Only includes the split between 
+ * curves if they switch derivative directions at that point. 
+ */ 
+std::vector<double> path_mono_splits(Path const &p) { 
+ std::vector<double> ret; 
+ if(p.empty()) return ret; 
+ ret.push_back(0); 
+ 
+ Curve* deriv = p[0].derivative(); 
+ append(ret, curve_mono_splits(*deriv)); 
+ delete deriv; 
+ 
+ int pdx=2, pdy=2; //Previous derivative direction 
+ for(unsigned i = 0; i <= p.size(); i++) { 
+ deriv = p[i].derivative(); 
+ std::vector<double> spl = offset_doubles(curve_mono_splits(*deriv), i); 
+ delete deriv; 
+ int dx = p[i].initialPoint()[X] > (spl.empty()? p[i].finalPoint()[X] : 
+ p.valueAt(spl.front(), X)); 
+ int dy = p[i].initialPoint()[Y] > (spl.empty()? p[i].finalPoint()[Y] : 
+ p.valueAt(spl.front(), Y)); 
+ //The direction changed, include the split time 
+ if(dx != pdx  dy != pdy) { 
+ ret.push_back(i); 
+ pdx = dx; pdy = dy; 
+ } 
+ append(ret, spl); 
+ } 
+ return ret; 
+} 
+ 
+/* Applies path_mono_splits to multiple paths, and returns the results such that 
+ * timeset i corresponds to Path i. 
+ */ 
+std::vector<std::vector<double> > paths_mono_splits(std::vector<Path> const &ps) { 
+ std::vector<std::vector<double> > ret; 
+ for(unsigned i = 0; i < ps.size(); i++) 
+ ret.push_back(path_mono_splits(ps[i])); 
+ return ret; 
+} 
+ 
+/* Processes the bounds for a list of paths and a list of splits on them, yielding a list of rects for each. 
+ * Each entry i corresponds to path i of the input. The number of rects in each entry is guaranteed to be the 
+ * number of splits for that path, subtracted by one. 
+ */ 
+std::vector<std::vector<Rect> > split_bounds(std::vector<Path> const &p, std::vector<std::vector<double> > splits) { 
+ std::vector<std::vector<Rect> > ret; 
+ for(unsigned i = 0; i < p.size(); i++) { 
+ std::vector<Rect> res; 
+ for(unsigned j = 1; j < splits[i].size(); j++) 
+ res.push_back(Rect(p[i].pointAt(splits[i][j1]), p[i].pointAt(splits[i][j]))); 
+ ret.push_back(res); 
+ } 
+ return ret; 
+} 
+ 
+/* This is the main routine of "MonoCrosser", and implements a monotonic strategy on multiple curves. 
+ * Finds crossings between two sets of paths, yielding a CrossingSet. [0, a.size()) of the return correspond 
+ * to the sorted crossings of a with paths of b. The rest of the return, [a.size(), a.size() + b.size()], 
+ * corresponds to the sorted crossings of b with paths of a. 
+ * 
+ * This function does two sweeps, one on the bounds of each path, and after that cull, one on the curves within. 
+ * This leads to a certain amount of code complexity, however, most of that is factored into the above functions 
+ */ 
+CrossingSet MonoCrosser::crossings(std::vector<Path> const &a, std::vector<Path> const &b) { 
+ if(b.empty()) return CrossingSet(a.size(), Crossings()); 
+ CrossingSet results(a.size() + b.size(), Crossings()); 
+ if(a.empty()) return results; 
+ 
+ std::vector<std::vector<double> > splits_a = paths_mono_splits(a), splits_b = paths_mono_splits(b); 
+ std::vector<std::vector<Rect> > bounds_a = split_bounds(a, splits_a), bounds_b = split_bounds(b, splits_b); 
+ 
+ std::vector<Rect> bounds_a_union, bounds_b_union; 
+ for(unsigned i = 0; i < bounds_a.size(); i++) bounds_a_union.push_back(union_list(bounds_a[i])); 
+ for(unsigned i = 0; i < bounds_b.size(); i++) bounds_b_union.push_back(union_list(bounds_b[i])); 
+ 
+ std::vector<std::vector<unsigned> > cull = sweep_bounds(bounds_a_union, bounds_b_union); 
+ Crossings n; 
+ for(unsigned i = 0; i < cull.size(); i++) { 
+ for(unsigned jx = 0; jx < cull[i].size(); jx++) { 
+ unsigned j = cull[i][jx]; 
+ unsigned jc = j + a.size(); 
+ Crossings res; 
+ 
+ //Sweep of the monotonic portions 
+ std::vector<std::vector<unsigned> > cull2 = sweep_bounds(bounds_a[i], bounds_b[j]); 
+ for(unsigned k = 0; k < cull2.size(); k++) { 
+ for(unsigned lx = 0; lx < cull2[k].size(); lx++) { 
+ unsigned l = cull2[k][lx]; 
+ mono_pair(a[i], splits_a[i][k1], splits_a[i][k], 
+ b[j], splits_b[j][l1], splits_b[j][l], 
+ res, .1); 
+ } 
+ } 
+ 
+ for(unsigned k = 0; k < res.size(); k++) { res[k].a = i; res[k].b = jc; } 
+ 
+ merge_crossings(results[i], res, i); 
+ merge_crossings(results[i], res, jc); 
+ } 
+ } 
+ 
+ return results; 
+} 
+ 
+/* This function is similar codewise to the MonoCrosser, the main difference is that it deals with 
+ * only one set of paths and includes self intersection 
+CrossingSet crossings_among(std::vector<Path> const &p) { 
+ CrossingSet results(p.size(), Crossings()); 
+ if(p.empty()) return results; 
+ 
+ std::vector<std::vector<double> > splits = paths_mono_splits(p); 
+ std::vector<std::vector<Rect> > prs = split_bounds(p, splits); 
+ std::vector<Rect> rs; 
+ for(unsigned i = 0; i < prs.size(); i++) rs.push_back(union_list(prs[i])); 
+ 
+ std::vector<std::vector<unsigned> > cull = sweep_bounds(rs); 
+ 
+ //we actually want to do the selfintersections, so add em in: 
+ for(unsigned i = 0; i < cull.size(); i++) cull[i].push_back(i); 
+ 
+ for(unsigned i = 0; i < cull.size(); i++) { 
+ for(unsigned jx = 0; jx < cull[i].size(); jx++) { 
+ unsigned j = cull[i][jx]; 
+ Crossings res; 
+ 
+ //Sweep of the monotonic portions 
+ std::vector<std::vector<unsigned> > cull2 = sweep_bounds(prs[i], prs[j]); 
+ for(unsigned k = 0; k < cull2.size(); k++) { 
+ for(unsigned lx = 0; lx < cull2[k].size(); lx++) { 
+ unsigned l = cull2[k][lx]; 
+ mono_pair(p[i], splits[i][k1], splits[i][k], 
+ p[j], splits[j][l1], splits[j][l], 
+ res, .1); 
+ } 
+ } 
+ 
+ for(unsigned k = 0; k < res.size(); k++) { res[k].a = i; res[k].b = j; } 
+ 
+ merge_crossings(results[i], res, i); 
+ merge_crossings(results[j], res, j); 
+ } 
+ } 
+ 
+ return results; 
+} 
+*/ 
+ 
+ 
+Crossings curve_self_crossings(Curve const &a) { 
+ Crossings res; 
+ std::vector<double> spl; 
+ spl.push_back(0); 
+ append(spl, curve_mono_splits(a)); 
+ spl.push_back(1); 
+ for(unsigned i = 1; i < spl.size(); i++) 
+ for(unsigned j = i+1; j < spl.size(); j++) 
+ pair_intersect(a, spl[i1], spl[i], a, spl[j1], spl[j], res); 
+ return res; 
+} 
+ 
+/* 
+void mono_curve_intersect(Curve const & A, double Al, double Ah, 
+ Curve const & B, double Bl, double Bh, 
+ Crossings &ret, unsigned depth=0) { 
+ // std::cout << depth << "(" << Al << ", " << Ah << ")\n"; 
+ Point A0 = A.pointAt(Al), A1 = A.pointAt(Ah), 
+ B0 = B.pointAt(Bl), B1 = B.pointAt(Bh); 
+ //inline code that this implies? (without rect/interval construction) 
+ if(!Rect(A0, A1).intersects(Rect(B0, B1))  A0 == A1  B0 == B1) return; 
+ 
+ //Checks the general linearity of the function 
+ if((depth > 12)  (A.boundsLocal(Interval(Al, Ah), 1).maxExtent() < 0.1 
+ && B.boundsLocal(Interval(Bl, Bh), 1).maxExtent() < 0.1)) { 
+ double tA, tB, c; 
+ if(linear_intersect(A0, A1, B0, B1, tA, tB, c)) { 
+ tA = tA * (Ah  Al) + Al; 
+ tB = tB * (Bh  Bl) + Bl; 
+ if(depth % 2) 
+ ret.push_back(Crossing(tB, tA, c < 0)); 
+ else 
+ ret.push_back(Crossing(tA, tB, c > 0)); 
+ return; 
+ } 
+ } 
+ if(depth > 12) return; 
+ double mid = (Bl + Bh)/2; 
+ mono_curve_intersect(B, Bl, mid, 
+ A, Al, Ah, 
+ ret, depth+1); 
+ mono_curve_intersect(B, mid, Bh, 
+ A, Al, Ah, 
+ ret, depth+1); 
+} 
+ 
+std::vector<std::vector<double> > curves_mono_splits(Path const &p) { 
+ std::vector<std::vector<double> > ret; 
+ for(unsigned i = 0; i <= p.size(); i++) { 
+ std::vector<double> spl; 
+ spl.push_back(0); 
+ append(spl, curve_mono_splits(p[i])); 
+ spl.push_back(1); 
+ ret.push_back(spl); 
+ } 
+} 
+ 
+std::vector<std::vector<Rect> > curves_split_bounds(Path const &p, std::vector<std::vector<double> > splits) { 
+ std::vector<std::vector<Rect> > ret; 
+ for(unsigned i = 0; i < splits.size(); i++) { 
+ std::vector<Rect> res; 
+ for(unsigned j = 1; j < splits[i].size(); j++) 
+ res.push_back(Rect(p.pointAt(splits[i][j1]+i), p.pointAt(splits[i][j]+i))); 
+ ret.push_back(res); 
+ } 
+ return ret; 
+} 
+ 
+Crossings path_self_crossings(Path const &p) { 
+ Crossings ret; 
+ std::vector<std::vector<unsigned> > cull = sweep_bounds(bounds(p)); 
+ std::vector<std::vector<double> > spl = curves_mono_splits(p); 
+ std::vector<std::vector<Rect> > bnds = curves_split_bounds(p, spl); 
+ for(unsigned i = 0; i < cull.size(); i++) { 
+ Crossings res; 
+ for(unsigned k = 1; k < spl[i].size(); k++) 
+ for(unsigned l = k+1; l < spl[i].size(); l++) 
+ mono_curve_intersect(p[i], spl[i][k1], spl[i][k], p[i], spl[i][l1], spl[i][l], res); 
+ offset_crossings(res, i, i); 
+ append(ret, res); 
+ for(unsigned jx = 0; jx < cull[i].size(); jx++) { 
+ unsigned j = cull[i][jx]; 
+ res.clear(); 
+ 
+ std::vector<std::vector<unsigned> > cull2 = sweep_bounds(bnds[i], bnds[j]); 
+ for(unsigned k = 0; k < cull2.size(); k++) { 
+ for(unsigned lx = 0; lx < cull2[k].size(); lx++) { 
+ unsigned l = cull2[k][lx]; 
+ mono_curve_intersect(p[i], spl[i][k1], spl[i][k], p[j], spl[j][l1], spl[j][l], res); 
+ } 
+ } 
+ 
+ //if(fabs(int(i)j) == 1  fabs(int(i)j) == p.size()1) { 
+ Crossings res2; 
+ for(unsigned k = 0; k < res.size(); k++) { 
+ if(res[k].ta != 0 && res[k].ta != 1 && res[k].tb != 0 && res[k].tb != 1) { 
+ res.push_back(res[k]); 
+ } 
+ } 
+ res = res2; 
+ //} 
+ offset_crossings(res, i, j); 
+ append(ret, res); 
+ } 
+ } 
+ return ret; 
+} 
+*/ 
+ 
+Crossings self_crossings(Path const &p) { 
+ Crossings ret; 
+ std::vector<std::vector<unsigned> > cull = sweep_bounds(bounds(p)); 
+ for(unsigned i = 0; i < cull.size(); i++) { 
+ Crossings res = curve_self_crossings(p[i]); 
+ offset_crossings(res, i, i); 
+ append(ret, res); 
+ for(unsigned jx = 0; jx < cull[i].size(); jx++) { 
+ unsigned j = cull[i][jx]; 
+ res.clear(); 
+ pair_intersect(p[i], 0, 1, p[j], 0, 1, res); 
+ 
+ //if(fabs(int(i)j) == 1  fabs(int(i)j) == p.size()1) { 
+ Crossings res2; 
+ for(unsigned k = 0; k < res.size(); k++) { 
+ if(res[k].ta != 0 && res[k].ta != 1 && res[k].tb != 0 && res[k].tb != 1) { 
+ res2.push_back(res[k]); 
+ } 
+ } 
+ res = res2; 
+ //} 
+ offset_crossings(res, i, j); 
+ append(ret, res); 
+ } 
+ } 
+ return ret; 
+} 
+ 
+void flip_crossings(Crossings &crs) { 
+ for(unsigned i = 0; i < crs.size(); i++) 
+ crs[i] = Crossing(crs[i].tb, crs[i].ta, crs[i].b, crs[i].a, !crs[i].dir); 
+} 
+ 
+CrossingSet crossings_among(std::vector<Path> const &p) { 
+ CrossingSet results(p.size(), Crossings()); 
+ if(p.empty()) return results; 
+ 
+ SimpleCrosser cc; 
+ 
+ std::vector<std::vector<unsigned> > cull = sweep_bounds(bounds(p)); 
+ for(unsigned i = 0; i < cull.size(); i++) { 
+ Crossings res = self_crossings(p[i]); 
+ for(unsigned k = 0; k < res.size(); k++) { res[k].a = res[k].b = i; } 
+ merge_crossings(results[i], res, i); 
+ flip_crossings(res); 
+ merge_crossings(results[i], res, i); 
+ for(unsigned jx = 0; jx < cull[i].size(); jx++) { 
+ unsigned j = cull[i][jx]; 
+ 
+ Crossings res = cc.crossings(p[i], p[j]); 
+ for(unsigned k = 0; k < res.size(); k++) { res[k].a = i; res[k].b = j; } 
+ merge_crossings(results[i], res, i); 
+ merge_crossings(results[j], res, j); 
+ } 
+ } 
+ return results; 
+} 
+ 
+} 
Index: Scribus/scribus/third_party/lib2geom/exception.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/exception.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/exception.h (revision 14937) 
@@ 0,0 +1,116 @@ 
+#ifndef LIB2GEOM_EXCEPTION_HEADER 
+#define LIB2GEOM_EXCEPTION_HEADER 
+ 
+/** Defines the different types of exceptions that 2geom can throw. 
+ * 
+ * Copyright 2007 Johan Engelen <goejendaagh@zonnet.nl> 
+ * 
+ * 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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 <exception> 
+#include <sstream> 
+#include <string> 
+ 
+namespace Geom { 
+ 
+// Base exception class, all 2geom exceptions should be derrived from this one. 
+class Exception : public std::exception { 
+public: 
+ Exception(const char * message, const char *file, const int line) { 
+ std::ostringstream os; 
+ os << "lib2geom exception: " << message << " (" << file << ":" << line << ")"; 
+ msgstr = os.str(); 
+ } 
+ 
+ virtual ~Exception() throw() {} // necessary to destroy the string object!!! 
+ 
+ virtual const char* what() const throw () { 
+ return msgstr.c_str(); 
+ } 
+protected: 
+ std::string msgstr; 
+}; 
+#define throwException(message) throw(Geom::Exception(message, __FILE__, __LINE__)) 
+ 
+// 
+// Two main exception classes: LogicalError and RangeError. 
+// Logical errors are 2geom faults/bugs, RangeErrors are 'user' faults. 
+// This way, the 'user' can distinguish between groups of exceptions 
+// ('user' is the coder that uses lib2geom) 
+class LogicalError : public Exception { 
+public: 
+ LogicalError(const char * message, const char *file, const int line) 
+ : Exception(message, file, line) {} 
+}; 
+#define throwLogicalError(message) throw(LogicalError(message, __FILE__, __LINE__)) 
+ 
+class RangeError : public Exception { 
+public: 
+ RangeError(const char * message, const char *file, const int line) 
+ : Exception(message, file, line) {} 
+}; 
+#define throwRangeError(message) throw(RangeError(message, __FILE__, __LINE__)) 
+ 
+// 
+// Special case exceptions. Best used with the defines :) 
+ 
+class NotImplemented : public LogicalError { 
+public: 
+ NotImplemented(const char *file, const int line) 
+ : LogicalError("Method not implemented", file, line) {} 
+}; 
+#define throwNotImplemented(i) throw(NotImplemented(__FILE__, __LINE__)) 
+ 
+class InvariantsViolation : public LogicalError { 
+public: 
+ InvariantsViolation(const char *file, const int line) 
+ : LogicalError("Invariants violation", file, line) {} 
+}; 
+#define throwInvariantsViolation(i) throw(InvariantsViolation(__FILE__, __LINE__)) 
+#define assert_invariants(e) ((e) ? (void)0 : throwInvariantsViolation(0)) 
+ 
+class NotInvertible : public RangeError { 
+public: 
+ NotInvertible(const char *file, const int line) 
+ : RangeError("Function does not have a unique inverse", file, line) {} 
+}; 
+#define throwNotInvertible(i) throw(NotInvertible(__FILE__, __LINE__)) 
+ 
+class ContinuityError : public RangeError { 
+public: 
+ ContinuityError(const char *file, const int line) 
+ : RangeError("Noncontiguous path", file, line) {} 
+}; 
+#define throwContinuityError(i) throw(ContinuityError(__FILE__, __LINE__)) 
+ 
+struct SVGPathParseError : public std::exception { 
+ char const *what() const throw() { return "parse error"; } 
+}; 
+ 
+ 
+} // namespace Geom 
+ 
+#endif 
Index: Scribus/scribus/third_party/lib2geom/transforms.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/transforms.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/transforms.h (revision 14937) 
@@ 0,0 +1,135 @@ 
+#ifndef SEEN_Geom_TRANSFORMS_H 
+#define SEEN_Geom_TRANSFORMS_H 
+ 
+#include "matrix.h" 
+#include <cmath> 
+ 
+#ifndef M_PI 
+#define M_PI 3.14159265359; 
+#endif 
+ 
+namespace Geom { 
+ 
+template <typename T> 
+struct TransformConcept { 
+ T t; 
+ Matrix m; 
+ Point p; 
+ void constraints() { 
+ m = t; //implicit conversion 
+ t = t.inverse(); 
+ p = p * t; 
+ t = t * t; 
+ } 
+}; 
+ 
+ 
+class Rotate; 
+class Translate { 
+ private: 
+ Translate(); 
+ Point vec; 
+ public: 
+ explicit Translate(Point const &p) : vec(p) {} 
+ explicit Translate(Coord const x, Coord const y) : vec(x, y) {} 
+ inline operator Matrix() const { return Matrix(1, 0, 0, 1, vec[X], vec[Y]); } 
+ 
+ inline Coord operator[](Dim2 const dim) const { return vec[dim]; } 
+ inline Coord operator[](unsigned const dim) const { return vec[dim]; } 
+ inline bool operator==(Translate const &o) const { return vec == o.vec; } 
+ inline bool operator!=(Translate const &o) const { return vec != o.vec; } 
+ 
+ inline Translate inverse() const { return Translate(vec); } 
+ 
+ friend Point operator*(Point const &v, Translate const &t); 
+ inline Translate operator*(Translate const &b) const { return Translate(vec + b.vec); } 
+ 
+ friend Matrix operator*(Translate const &t, Rotate const &r); 
+}; 
+ 
+inline Point operator*(Point const &v, Translate const &t) { return v + t.vec; } 
+ 
+class Scale { 
+ private: 
+ Point vec; 
+ Scale(); 
+ public: 
+ explicit Scale(Point const &p) : vec(p) {} 
+ Scale(Coord const x, Coord const y) : vec(x, y) {} 
+ explicit Scale(Coord const s) : vec(s, s) {} 
+ inline operator Matrix() const { return Matrix(vec[X], 0, 0, vec[Y], 0, 0); } 
+ 
+ inline Coord operator[](Dim2 const d) const { return vec[d]; } 
+ inline Coord operator[](unsigned const d) const { return vec[d]; } 
+ //TODO: should we keep these mutators? add them to the other transforms? 
+ inline Coord &operator[](Dim2 const d) { return vec[d]; } 
+ inline Coord &operator[](unsigned const d) { return vec[d]; } 
+ inline bool operator==(Scale const &o) const { return vec == o.vec; } 
+ inline bool operator!=(Scale const &o) const { return vec != o.vec; } 
+ 
+ inline Scale inverse() const { return Scale(1./vec[0], 1./vec[1]); } 
+ 
+ friend Point operator*(Point const &v, Translate const &t); 
+ inline Scale operator*(Scale const &b) const { return Scale(vec[X]*b[X], vec[Y]*b[Y]); } 
+}; 
+ 
+inline Point operator*(Point const &p, Scale const &s) { return Point(p[X] * s[X], p[Y] * s[Y]); } 
+ 
+/** Notionally an Geom::Matrix corresponding to rotation about the origin. 
+ Behaves like Geom::Matrix for multiplication. 
+**/ 
+class Rotate { 
+ private: 
+ Rotate(); 
+ Point vec; 
+ public: 
+ explicit Rotate(Coord theta) : vec(std::cos(theta), std::sin(theta)) {} 
+ Rotate(Point const &p) {Point v = p; v.normalize(); vec = v;} //TODO: UGLY! 
+ explicit Rotate(Coord x, Coord y) { Rotate(Point(x, y)); } 
+ inline operator Matrix() const { return Matrix(vec[X], vec[Y], vec[Y], vec[X], 0, 0); } 
+ 
+ inline Coord operator[](Dim2 const dim) const { return vec[dim]; } 
+ inline Coord operator[](unsigned const dim) const { return vec[dim]; } 
+ inline bool operator==(Rotate const &o) const { return vec == o.vec; } 
+ inline bool operator!=(Rotate const &o) const { return vec != o.vec; } 
+ 
+ Rotate inverse() const { return Rotate( Point(vec[X], vec[Y]) ); } 
+ static Rotate from_degrees(Coord deg) { 
+ Coord rad = (deg / 180.0) * M_PI; 
+ return Rotate(rad); 
+ } 
+ 
+ friend Point operator*(Point const &v, Rotate const &r); 
+ inline Rotate operator*(Rotate const &b) const { return Rotate(vec * b); } 
+}; 
+ 
+inline Point operator*(Point const &v, Rotate const &r) { return v ^ r.vec; } 
+ 
+Matrix operator*(Translate const &t, Scale const &s); 
+Matrix operator*(Translate const &t, Rotate const &r); 
+ 
+Matrix operator*(Scale const &s, Translate const &t); 
+Matrix operator*(Scale const &s, Matrix const &m); 
+ 
+Matrix operator*(Matrix const &m, Translate const &t); 
+Matrix operator*(Matrix const &m, Scale const &s); 
+Matrix operator*(Matrix const &m, Rotate const &r); 
+Matrix operator*(Matrix const &m1, Matrix const &m2); 
+ 
+//TODO: matrix to trans/scale/rotate 
+ 
+} /* namespace Geom */ 
+ 
+ 
+#endif /* !SEEN_Geom_TRANSFORMS_H */ 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/isnan.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/isnan.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/isnan.h (revision 14937) 
@@ 0,0 +1,64 @@ 
+#ifndef __ISNAN_H__ 
+#define __ISNAN_H__ 
+ 
+/* 
+ * Temporary fix for various misdefinitions of isnan(). 
+ * isnan() is becoming undef'd in some .h files. 
+ * #include this last in your .cpp file to get it right. 
+ * 
+ * The problem is that isnan and isfinite are part of C99 but aren't part of 
+ * the C++ standard (which predates C99). 
+ * 
+ * Authors: 
+ * Inkscape groupies and obsessivecompulsives 
+ * 
+ * Copyright (C) 2004 authors 
+ * 
+ * Released under GNU GPL, read the file 'COPYING' for more information 
+ * 
+ * 2005 modification hereby placed in public domain. Probably supercedes the 2004 copyright 
+ * for the code itself. 
+ */ 
+ 
+#include <cmath> 
+#include <float.h> 
+/* You might try changing the above to <cmath> if you have problems. 
+ * Whether you use math.h or cmath, you may need to edit the .cpp file 
+ * and/or other .h files to use the same header file. 
+ */ 
+ 
+#if defined(__isnan) 
+# define is_nan(_a) (__isnan(_a)) 
+#elif defined(__APPLE__) && __GNUC__ == 3 
+# define is_nan(_a) (__isnan(_a)) /* MacOSX/Darwin definition < 10.4 */ 
+#elif defined(WIN32)  defined(_isnan) 
+# define is_nan(_a) (_isnan(_a)) /* Win32 definition */ 
+#elif defined(isnan)  defined(__FreeBSD__) 
+# define is_nan(_a) (isnan(_a)) /* GNU definition */ 
+#else 
+# define is_nan(_a) (std::isnan(_a)) 
+#endif 
+/* If the above doesn't work, then try (a != a). 
+ * Also, please report a bug as per http://www.inkscape.org/report_bugs.php, 
+ * giving information about what platform and compiler version you're using. 
+ */ 
+ 
+ 
+#if defined(__isfinite) 
+# define is_finite(_a) (__isfinite(_a)) 
+#elif defined(__APPLE__) && __GNUC__ == 3 
+# define is_finite(_a) (__isfinite(_a)) /* MacOSX/Darwin definition < 10.4 */ 
+#elif defined(isfinite) 
+# define is_finite(_a) (isfinite(_a)) 
+#elif defined(_MSC_VER) 
+# define is_finite(_a) (_finite(_a) && !_isnan(_a)) 
+#else 
+# define is_finite(_a) (std::isfinite(_a)) 
+#endif 
+/* If the above doesn't work, then try (finite(_a) && !isNaN(_a)) or (!isNaN((_a)  (_a))). 
+ * Also, please report a bug as per http://www.inkscape.org/report_bugs.php, 
+ * giving information about what platform and compiler version you're using. 
+ */ 
+ 
+ 
+#endif /* __ISNAN_H__ */ 
Index: Scribus/scribus/third_party/lib2geom/bezier.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/bezier.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/bezier.h (revision 14937) 
@@ 0,0 +1,321 @@ 
+/* 
+ * bezier.h 
+ * 
+ * Copyright 2007 MenTaLguY <mental@rydia.net> 
+ * Copyright 2007 Michael Sloan <mgsloan@gmail.com> 
+ * Copyright 2007 Nathan Hurst <njh@njhurst.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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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_BEZIER_H 
+#define SEEN_BEZIER_H 
+ 
+#include "coord.h" 
+#include <valarray> 
+#include "isnan.h" 
+#include "beziertosbasis.h" 
+#include "d2.h" 
+#include "solver.h" 
+#include <boost/optional/optional.hpp> 
+ 
+namespace Geom { 
+ 
+inline Coord subdivideArr(Coord t, Coord const *v, Coord *left, Coord *right, unsigned order) { 
+ const unsigned size=order+1; 
+ std::vector<Coord> vtemp(v,v+size); 
+ 
+ //storing left/right coordinates 
+ std::vector<Coord> nodata(size); 
+ if(left == NULL)left=&nodata[0]; 
+ if(right == NULL)right=&nodata[0]; 
+ 
+ /* Copy control points */ 
+ left[0] = vtemp[0]; 
+ right[order]= vtemp[order]; 
+ 
+ /* Triangle computation */ 
+ for (unsigned i = 1; i < size; ++i) { 
+ for (unsigned j = 0; j < size  i; ++j) { 
+ vtemp[j] = lerp(t, vtemp[j], vtemp[j+1]); 
+ } 
+ left[i] =vtemp[0]; 
+ right[orderi]=vtemp[orderi]; 
+ } 
+ 
+ return (vtemp[0]); 
+} 
+ 
+ 
+class Bezier { 
+private: 
+ std::vector<Coord> c_; 
+ 
+ friend Bezier portion(const Bezier & a, Coord from, Coord to); 
+ 
+ friend Interval bounds_fast(Bezier const & b); 
+ 
+ friend Bezier derivative(const Bezier & a); 
+ 
+protected: 
+ Bezier(Coord const c[], unsigned ord) : c_(c,c+ord+1){ 
+ //std::copy(c, c+order()+1, &c_[0]); 
+ } 
+ 
+public: 
+ unsigned int order() const { return c_.size()1;} 
+ unsigned int size() const { return c_.size();} 
+ 
+ Bezier() :c_(32) {} 
+ Bezier(const Bezier& b) :c_(b.c_) {} 
+ Bezier &operator=(Bezier const &other) { 
+ if ( c_.size() != other.c_.size() ) { 
+ c_.resize(other.c_.size()); 
+ } 
+ c_ = other.c_; 
+ return *this; 
+ } 
+ 
+ struct Order { 
+ unsigned order; 
+ explicit Order(Bezier const &b) : order(b.order()) {} 
+ explicit Order(unsigned o) : order(o) {} 
+ operator unsigned() const { return order; } 
+ }; 
+ 
+ //Construct an arbitrary order bezier 
+ Bezier(Order ord) : c_(ord.order+1) { 
+ assert(ord.order == order()); 
+ } 
+ 
+ explicit Bezier(Coord c0) : c_(1) { 
+ c_[0] = c0; 
+ } 
+ 
+ //Construct an order1 bezier (linear BÃ©zier) 
+ Bezier(Coord c0, Coord c1) : c_(2) { 
+ c_[0] = c0; c_[1] = c1; 
+ } 
+ 
+ //Construct an order2 bezier (quadratic BÃ©zier) 
+ Bezier(Coord c0, Coord c1, Coord c2) : c_(3) { 
+ c_[0] = c0; c_[1] = c1; c_[2] = c2; 
+ } 
+ 
+ //Construct an order3 bezier (cubic BÃ©zier) 
+ Bezier(Coord c0, Coord c1, Coord c2, Coord c3) : c_(4) { 
+ c_[0] = c0; c_[1] = c1; c_[2] = c2; c_[3] = c3; 
+ } 
+ 
+ inline unsigned degree() const { return order(); } 
+ 
+ //IMPL: FragmentConcept 
+ typedef Coord output_type; 
+ inline bool isZero() const { 
+ for(unsigned i = 0; i <= order(); i++) { 
+ if(c_[i] != 0) return false; 
+ } 
+ return true; 
+ } 
+ inline bool isConstant() const { 
+ for(unsigned i = 1; i <= order(); i++) { 
+ if(c_[i] != c_[0]) return false; 
+ } 
+ return true; 
+ } 
+ inline bool isFinite() const { 
+ for(unsigned i = 0; i <= order(); i++) { 
+ if(!is_finite(c_[i])) return false; 
+ } 
+ return true; 
+ } 
+ inline Coord at0() const { return c_[0]; } 
+ inline Coord at1() const { return c_[order()]; } 
+ 
+ inline Coord valueAt(double t) const { 
+ return subdivideArr(t, &c_[0], NULL, NULL, order()); 
+ } 
+ inline Coord operator()(double t) const { return valueAt(t); } 
+ 
+ inline SBasis toSBasis() const { 
+ return bezier_to_sbasis(&c_[0], order()); 
+ } 
+ 
+ //Only mutator 
+ inline Coord &operator[](unsigned ix) { return c_[ix]; } 
+ inline Coord const &operator[](unsigned ix) const { return c_[ix]; } 
+ inline void setPoint(unsigned ix, double val) { c_[ix] = val; } 
+ 
+ /* This is inelegant, as it uses several extra stores. I think there might be a way to 
+ * evaluate roughly in situ. */ 
+ 
+ std::vector<Coord> valueAndDerivatives(Coord t, unsigned n_derivs) const { 
+ std::vector<Coord> val_n_der; 
+ 
+ unsigned nn = n_derivs; 
+ if(nn > order()) 
+ nn = order(); 
+ val_n_der.reserve(n_derivs); 
+ 
+ std::vector<Coord> d_(c_); 
+ for(unsigned di = 0; di < nn; di++) { 
+ val_n_der.push_back(subdivideArr(t, &d_[0], NULL, NULL, order()  di)); 
+ for(unsigned i = 0; i < order()  di; i++) { 
+ d_[i] = (order()di)*(d_[i+1]  d_[i]); 
+ } 
+ } 
+ 
+ val_n_der.resize(n_derivs); 
+ return val_n_der; 
+ } 
+ 
+ std::pair<Bezier, Bezier > subdivide(Coord t) const { 
+ Bezier a(Bezier::Order(*this)), b(Bezier::Order(*this)); 
+ subdivideArr(t, &c_[0], &a.c_[0], &b.c_[0], order()); 
+ return std::pair<Bezier, Bezier >(a, b); 
+ } 
+ 
+ std::vector<double> roots() const { 
+ std::vector<double> solutions; 
+ find_bernstein_roots(&c_[0], order(), solutions, 0, 0.0, 1.0); 
+ return solutions; 
+ } 
+}; 
+ 
+//TODO: implement others 
+inline Bezier operator+(const Bezier & a, double v) { 
+ Bezier result = Bezier(Bezier::Order(a)); 
+ for(unsigned i = 0; i <= a.order(); i++) 
+ result[i] = a[i] + v; 
+ return result; 
+} 
+ 
+inline Bezier operator(const Bezier & a, double v) { 
+ Bezier result = Bezier(Bezier::Order(a)); 
+ for(unsigned i = 0; i <= a.order(); i++) 
+ result[i] = a[i]  v; 
+ return result; 
+} 
+ 
+inline Bezier operator*(const Bezier & a, double v) { 
+ Bezier result = Bezier(Bezier::Order(a)); 
+ for(unsigned i = 0; i <= a.order(); i++) 
+ result[i] = a[i] * v; 
+ return result; 
+} 
+ 
+inline Bezier operator/(const Bezier & a, double v) { 
+ Bezier result = Bezier(Bezier::Order(a)); 
+ for(unsigned i = 0; i <= a.order(); i++) 
+ result[i] = a[i] / v; 
+ return result; 
+} 
+ 
+inline Bezier reverse(const Bezier & a) { 
+ Bezier result = Bezier(Bezier::Order(a)); 
+ for(unsigned i = 0; i <= a.order(); i++) 
+ result[i] = a[a.order()  i]; 
+ return result; 
+} 
+ 
+inline Bezier portion(const Bezier & a, double from, double to) { 
+ //TODO: implement better? 
+ std::vector<Coord> res(a.order()+1); 
+ if(from == 0) { 
+ if(to == 1) { return Bezier(a); } 
+ subdivideArr(to, &a.c_[0], &res[0], NULL, a.order()); 
+ return Bezier(&res[0], a.order()); 
+ } 
+ subdivideArr(from, &a.c_[0], NULL, &res[0], a.order()); 
+ if(to == 1) return Bezier(&res[0], a.order()); 
+ std::vector<Coord> res2(a.order()+1); 
+ subdivideArr((to  from)/(1  from), &res[0], &res2[0], NULL, a.order()); 
+ return Bezier(&res2[0], a.order()); 
+} 
+ 
+// XXX Todo: how to handle differing orders 
+inline std::vector<Point> bezier_points(const D2<Bezier > & a) { 
+ std::vector<Point> result; 
+ for(unsigned i = 0; i <= a[0].order(); i++) { 
+ Point p; 
+ for(unsigned d = 0; d < 2; d++) p[d] = a[d][i]; 
+ result.push_back(p); 
+ } 
+ return result; 
+} 
+ 
+inline Bezier derivative(const Bezier & a) { 
+ if(a.order() == 1) return Bezier(0.0); 
+ Bezier der(Bezier::Order(a.order()1)); 
+ 
+ for(unsigned i = 0; i < a.order(); i++) { 
+ der.c_[i] = a.order()*(a.c_[i+1]  a.c_[i]); 
+ } 
+ return der; 
+} 
+ 
+inline Bezier integral(const Bezier & a) { 
+ Bezier inte(Bezier::Order(a.order()+1)); 
+ 
+ inte[0] = 0; 
+ for(unsigned i = 0; i < inte.order(); i++) { 
+ inte[i+1] = inte[i] + a[i]/(inte.order()); 
+ } 
+ return inte; 
+} 
+ 
+inline Interval bounds_fast(Bezier const & b) { 
+ return Interval::fromArray(&b.c_[0], b.size()); 
+} 
+ 
+//TODO: better bounds exact 
+inline Interval bounds_exact(Bezier const & b) { 
+ return bounds_exact(b.toSBasis()); 
+} 
+ 
+inline Interval bounds_local(Bezier const & b, Interval i) { 
+ return bounds_fast(portion(b, i.min(), i.max())); 
+ //return bounds_local(b.toSBasis(), i); 
+} 
+ 
+inline std::ostream &operator<< (std::ostream &out_file, const Bezier & b) { 
+ for(unsigned i = 0; i < b.size(); i++) { 
+ out_file << b[i] << ", "; 
+ } 
+ return out_file; 
+} 
+ 
+} 
+#endif //SEEN_BEZIER_H 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/polydksolve.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/polydksolve.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/polydksolve.cpp (revision 14937) 
@@ 0,0 +1,64 @@ 
+#include "polydksolve.h" 
+#include <iterator> 
+ 
+/*** implementation of the DurandKerner 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 *= Rroots[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++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/pathintersection.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/pathintersection.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/pathintersection.h (revision 14937) 
@@ 0,0 +1,65 @@ 
+#ifndef __GEOM_PATH_INTERSECTION_H 
+#define __GEOM_PATH_INTERSECTION_H 
+ 
+#include "path.h" 
+ 
+#include "crossing.h" 
+ 
+#include "sweep.h" 
+ 
+namespace Geom { 
+ 
+int winding(Path const &path, Point p); 
+bool path_direction(Path const &p); 
+ 
+inline bool contains(Path const & p, Point i, bool evenodd = true) { 
+ return (evenodd ? winding(p, i) % 2 : winding(p, i)) != 0; 
+} 
+ 
+template<typename T> 
+Crossings curve_sweep(Path const &a, Path const &b) { 
+ T t; 
+ Crossings ret; 
+ std::vector<Rect> bounds_a = bounds(a), bounds_b = bounds(b); 
+ std::vector<std::vector<unsigned> > ixs = sweep_bounds(bounds_a, bounds_b); 
+ for(unsigned i = 0; i < a.size(); i++) { 
+ for(std::vector<unsigned>::iterator jp = ixs[i].begin(); jp != ixs[i].end(); jp++) { 
+ Crossings cc = t.crossings(a[i], b[*jp]); 
+ offset_crossings(cc, i, *jp); 
+ ret.insert(ret.end(), cc.begin(), cc.end()); 
+ } 
+ } 
+ return ret; 
+} 
+ 
+struct SimpleCrosser : public Crosser<Path> { 
+ Crossings crossings(Curve const &a, Curve const &b); 
+ Crossings crossings(Path const &a, Path const &b) { return curve_sweep<SimpleCrosser>(a, b); } 
+ CrossingSet crossings(std::vector<Path> const &a, std::vector<Path> const &b) { return Crosser<Path>::crossings(a, b); } 
+}; 
+ 
+struct MonoCrosser : public Crosser<Path> { 
+ Crossings crossings(Path const &a, Path const &b) { return crossings(std::vector<Path>(1,a), std::vector<Path>(1,b))[0]; } 
+ CrossingSet crossings(std::vector<Path> const &a, std::vector<Path> const &b); 
+}; 
+ 
+typedef SimpleCrosser DefaultCrosser; 
+ 
+std::vector<double> path_mono_splits(Path const &p); 
+ 
+CrossingSet crossings_among(std::vector<Path> const & p); 
+Crossings self_crossings(Path const & a); 
+ 
+inline Crossings crossings(Path const & a, Path const & b) { 
+ DefaultCrosser c = DefaultCrosser(); 
+ return c.crossings(a, b); 
+} 
+ 
+inline CrossingSet crossings(std::vector<Path> const & a, std::vector<Path> const & b) { 
+ DefaultCrosser c = DefaultCrosser(); 
+ return c.crossings(a, b); 
+} 
+ 
+} 
+ 
+#endif 
Index: Scribus/scribus/third_party/lib2geom/utils.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/utils.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/utils.h (revision 14937) 
@@ 0,0 +1,81 @@ 
+#ifndef LIB2GEOM_UTILS_HEADER 
+#define LIB2GEOM_UTILS_HEADER 
+ 
+/** Various utility functions. 
+ * 
+ * Copyright 2007 Johan Engelen <goejendaagh@zonnet.nl> 
+ * Copyright 2006 Michael G. 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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> 
+ 
+namespace Geom { 
+ 
+// proper logical xor 
+inline bool logical_xor (bool a, bool b) { return (a  b) && !(a && b); } 
+ 
+/** Sign function  indicates the sign of a numeric type. 1 indicates negative, 1 indicates 
+ * positive, and 0 indicates, well, 0. Mathsy people will know this is basically the derivative 
+ * of abs, except for the fact that it is defined on 0. 
+ */ 
+template <class T> inline int sgn(const T& x) {return (x < 0 ? 1 : (x > 0 ? 1 : 0) );} 
+ 
+template <class T> inline T sqr(const T& x) {return x * x;} 
+template <class T> inline T cube(const T& x) {return x * x * x;} 
+ 
+/** Between function  returns true if a number x is within a range. The values delimiting the 
+ * range and the number must have the same type. 
+ */ 
+template <class T> inline const T& between (const T& min, const T& max, const T& x) 
+ { return min < x && max > x; } 
+ 
+/** Returns x rounded to the nearest integer. It is unspecified what happens 
+ * if x is half way between two integers: we may in future use rint/round 
+ * on platforms that have them. 
+ */ 
+inline double round(double const x) { return std::floor(x + .5); } 
+ 
+/** Returns x rounded to the nearest \a places decimal places. 
+ 
+ Implemented in terms of round, i.e. we make no guarantees as to what happens if x is 
+ half way between two rounded numbers. 
+ 
+ Note: places is the number of decimal places without using scientific (e) notation, not the 
+ number of significant figures. This function may not be suitable for values of x whose 
+ magnitude is so far from 1 that one would want to use scientific (e) notation. 
+ 
+ places may be negative: e.g. places = 2 means rounding to a multiple of .01 
+**/ 
+inline double decimal_round(double const x, int const places) { 
+ //TODO: possibly implement with modulus instead? 
+ double const multiplier = std::pow(10.0, places); 
+ return round( x * multiplier ) / multiplier; 
+} 
+ 
+} 
+ 
+#endif 
Index: Scribus/scribus/third_party/lib2geom/sbasismath.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/sbasismath.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/sbasismath.h (revision 14937) 
@@ 0,0 +1,95 @@ 
+/* 
+ * sbasismath.h  some std functions to work with (pw)sbasis 
+ * 
+ * Authors: 
+ * JeanFrancois Barraud 
+ * 
+ * Copyright (C) 20062007 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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. 
+ */ 
+ 
+//this a first try to define sqrt, cos, sin, etc... 
+//TODO: define a truncated compose(sb,sb, order) and extend it to pw<sb>. 
+//TODO: in all these functions, compute 'order' according to 'tol'. 
+//TODO: use template to define the pw version automatically from the sb version? 
+ 
+#ifndef SEEN_GEOM_SB_CALCULS_H 
+#define SEEN_GEOM_SB_CALCULS_H 
+ 
+ 
+#include "sbasis.h" 
+#include "piecewise.h" 
+ 
+namespace Geom{ 
+//x 
+Piecewise<SBasis> abs( SBasis const &f); 
+Piecewise<SBasis> abs(Piecewise<SBasis>const &f); 
+ 
+// max(f,g), min(f,g)  
+Piecewise<SBasis> max( SBasis const &f, SBasis const &g); 
+Piecewise<SBasis> max(Piecewise<SBasis> const &f, SBasis const &g); 
+Piecewise<SBasis> max( SBasis const &f, Piecewise<SBasis> const &g); 
+Piecewise<SBasis> max(Piecewise<SBasis> const &f, Piecewise<SBasis> const &g); 
+Piecewise<SBasis> min( SBasis const &f, SBasis const &g); 
+Piecewise<SBasis> min(Piecewise<SBasis> const &f, SBasis const &g); 
+Piecewise<SBasis> min( SBasis const &f, Piecewise<SBasis> const &g); 
+Piecewise<SBasis> min(Piecewise<SBasis> const &f, Piecewise<SBasis> const &g); 
+ 
+//sign(x) 
+Piecewise<SBasis> signSb( SBasis const &f); 
+Piecewise<SBasis> signSb(Piecewise<SBasis>const &f); 
+ 
+//Sqrt 
+Piecewise<SBasis> sqrt( SBasis const &f, double tol=1e3, int order=3); 
+Piecewise<SBasis> sqrt(Piecewise<SBasis>const &f, double tol=1e3, int order=3); 
+ 
+//sin/cos 
+Piecewise<SBasis> cos( SBasis const &f, double tol=1e3, int order=3); 
+Piecewise<SBasis> cos(Piecewise<SBasis> const &f, double tol=1e3, int order=3); 
+Piecewise<SBasis> sin( SBasis const &f, double tol=1e3, int order=3); 
+Piecewise<SBasis> sin(Piecewise<SBasis> const &f, double tol=1e3, int order=3); 
+//Log 
+Piecewise<SBasis> log( SBasis const &f, double tol=1e3, int order=3); 
+Piecewise<SBasis> log(Piecewise<SBasis>const &f, double tol=1e3, int order=3); 
+ 
+//1/x 
+//TODO: change this... 
+Piecewise<SBasis> reciprocalOnDomain(Interval range, double tol=1e3); 
+Piecewise<SBasis> reciprocal( SBasis const &f, double tol=1e3, int order=3); 
+Piecewise<SBasis> reciprocal(Piecewise<SBasis>const &f, double tol=1e3, int order=3); 
+ 
+} 
+ 
+#endif //SEEN_GEOM_PW_SB_CALCULUS_H 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype = cpp:expandtab:shiftwidth = 4:tabstop = 8:softtabstop = 4:encoding = utf8:textwidth = 99 : 
Index: Scribus/scribus/third_party/lib2geom/pointl.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/pointl.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/pointl.h (revision 14937) 
@@ 0,0 +1,86 @@ 
+#ifndef SEEN_Geom_POINT_L_H 
+#define SEEN_Geom_POINT_L_H 
+ 
+#include <stdexcept> 
+#include "point.h" 
+ 
+namespace Geom { 
+ 
+typedef long ICoord; 
+ 
+class IPoint { 
+ ICoord _pt[2]; 
+ 
+ public: 
+ IPoint() { } 
+ 
+ IPoint(ICoord x, ICoord y) { 
+ _pt[X] = x; 
+ _pt[Y] = y; 
+ } 
+ 
+ IPoint(NRPointL const &p) { 
+ _pt[X] = p.x; 
+ _pt[Y] = p.y; 
+ } 
+ 
+ IPoint(IPoint const &p) { 
+ for (unsigned i = 0; i < 2; ++i) { 
+ _pt[i] = p._pt[i]; 
+ } 
+ } 
+ 
+ IPoint &operator=(IPoint const &p) { 
+ for (unsigned i = 0; i < 2; ++i) { 
+ _pt[i] = p._pt[i]; 
+ } 
+ return *this; 
+ } 
+ 
+ operator Point() { 
+ return Point(_pt[X], _pt[Y]); 
+ } 
+ 
+ ICoord operator[](unsigned i) const throw(std::out_of_range) { 
+ if ( i > Y ) throw std::out_of_range("index out of range"); 
+ return _pt[i]; 
+ } 
+ 
+ ICoord &operator[](unsigned i) throw(std::out_of_range) { 
+ if ( i > Y ) throw std::out_of_range("index out of range"); 
+ return _pt[i]; 
+ } 
+ 
+ ICoord operator[](Dim2 d) const throw() { return _pt[d]; } 
+ ICoord &operator[](Dim2 d) throw() { return _pt[d]; } 
+ 
+ IPoint &operator+=(IPoint const &o) { 
+ for ( unsigned i = 0 ; i < 2 ; ++i ) { 
+ _pt[i] += o._pt[i]; 
+ } 
+ return *this; 
+ } 
+ 
+ IPoint &operator=(IPoint const &o) { 
+ for ( unsigned i = 0 ; i < 2 ; ++i ) { 
+ _pt[i] = o._pt[i]; 
+ } 
+ return *this; 
+ } 
+}; 
+ 
+ 
+} // namespace Geom 
+ 
+#endif /* !SEEN_Geom_POINT_L_H */ 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/sbasistobezier.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/sbasistobezier.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/sbasistobezier.h (revision 14937) 
@@ 0,0 +1,24 @@ 
+#ifndef _SBASIS_TO_BEZIER 
+#define _SBASIS_TO_BEZIER 
+ 
+#include "d2.h" 
+#include "path.h" 
+ 
+namespace Geom{ 
+// this produces a degree k bezier from a degree k sbasis 
+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); 
+ 
+std::vector<Path> path_from_piecewise(Piecewise<D2<SBasis> > const &B, double tol); 
+ 
+Path path_from_sbasis(D2<SBasis> const &B, double tol); 
+ 
+}; 
+#endif 
Index: Scribus/scribus/third_party/lib2geom/beziertosbasis.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/beziertosbasis.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/beziertosbasis.h (revision 14937) 
@@ 0,0 +1,73 @@ 
+/* 
+ * beziertosbasis.h 
+ * 
+ * Copyright 2006 Nathan Hurst <njh@mail.csse.monash.edu.au> 
+ * 
+ * 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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 _BEZIER_TO_SBASIS 
+#define _BEZIER_TO_SBASIS 
+ 
+#include "coord.h" 
+ 
+#include "d2.h" 
+#include "point.h" 
+ 
+namespace Geom{ 
+ 
+inline SBasis bezier_to_sbasis(Coord const *handles, unsigned order) { 
+ if(order == 0) 
+ return Linear(handles[0]); 
+ else if(order == 1) 
+ return Linear(handles[0], handles[1]); 
+ else 
+ return multiply(Linear(1, 0), bezier_to_sbasis(handles, order1)) + 
+ multiply(Linear(0, 1), bezier_to_sbasis(handles+1, order1)); 
+} 
+ 
+ 
+template <typename T> 
+inline D2<SBasis> handles_to_sbasis(T const &handles, unsigned order) { 
+ double v[2][order+1]; 
+ for(unsigned i = 0; i <= order; i++) 
+ for(unsigned j = 0; j < 2; j++) 
+ v[j][i] = handles[i][j]; 
+ return D2<SBasis>(bezier_to_sbasis(v[0], order), 
+ bezier_to_sbasis(v[1], order)); 
+} 
+ 
+}; 
+#endif 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/sbasis2d.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/sbasis2d.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/sbasis2d.h (revision 14937) 
@@ 0,0 +1,325 @@ 
+#ifndef SEEN_SBASIS_2D_H 
+#define SEEN_SBASIS_2D_H 
+#include <vector> 
+#include <cassert> 
+#include <algorithm> 
+#include "d2.h" 
+#include "sbasis.h" 
+#include <iostream> 
+ 
+namespace Geom{ 
+ 
+class Linear2d{ 
+public: 
+ /* 
+ u 0,1 
+ v 0,2 
+ */ 
+ double a[4]; 
+ Linear2d() {} 
+ Linear2d(double aa) { 
+ for(unsigned i = 0 ; i < 4; i ++) 
+ a[i] = aa; 
+ } 
+ Linear2d(double a00, double a01, double a10, double a11) 
+ { 
+ a[0] = a00; 
+ a[1] = a01; 
+ a[2] = a10; 
+ a[3] = a11; 
+ } 
+ 
+ double operator[](const int i) const { 
+ assert(i >= 0); 
+ assert(i < 4); 
+ return a[i]; 
+ } 
+ double& operator[](const int i) { 
+ assert(i >= 0); 
+ assert(i < 4); 
+ return a[i]; 
+ } 
+ double apply(double u, double v) { 
+ return (a[0]*(1u)*(1v) + 
+ a[1]*u*(1v) + 
+ a[2]*(1u)*v + 
+ a[3]*u*v); 
+ } 
+}; 
+ 
+inline Linear extract_u(Linear2d const &a, double u) { 
+ return Linear(a[0]*(1u) + 
+ a[1]*u, 
+ a[2]*(1u) + 
+ a[3]*u); 
+} 
+inline Linear extract_v(Linear2d const &a, double v) { 
+ return Linear(a[0]*(1v) + 
+ a[2]*v, 
+ a[1]*(1v) + 
+ a[3]*v); 
+} 
+inline Linear2d operator(Linear2d const &a) { 
+ return Linear2d(a.a[0], a.a[1], 
+ a.a[2], a.a[3]); 
+} 
+inline Linear2d operator+(Linear2d const & a, Linear2d const & b) { 
+ return Linear2d(a[0] + b[0], 
+ a[1] + b[1], 
+ a[2] + b[2], 
+ a[3] + b[3]); 
+} 
+inline Linear2d operator(Linear2d const & a, Linear2d const & b) { 
+ return Linear2d(a[0]  b[0], 
+ a[1]  b[1], 
+ a[2]  b[2], 
+ a[3]  b[3]); 
+} 
+inline Linear2d& operator+=(Linear2d & a, Linear2d const & b) { 
+ for(unsigned i = 0; i < 4; i++) 
+ a[i] += b[i]; 
+ return a; 
+} 
+inline Linear2d& operator=(Linear2d & a, Linear2d const & b) { 
+ for(unsigned i = 0; i < 4; i++) 
+ a[i] = b[i]; 
+ return a; 
+} 
+inline Linear2d& operator*=(Linear2d & a, double b) { 
+ for(unsigned i = 0; i < 4; i++) 
+ a[i] *= b; 
+ return a; 
+} 
+ 
+inline bool operator==(Linear2d const & a, Linear2d const & b) { 
+ for(unsigned i = 0; i < 4; i++) 
+ if(a[i] != b[i]) 
+ return false; 
+ return true; 
+} 
+inline bool operator!=(Linear2d const & a, Linear2d const & b) { 
+ for(unsigned i = 0; i < 4; i++) 
+ if(a[i] == b[i]) 
+ return false; 
+ return true; 
+} 
+inline Linear2d operator*(double const a, Linear2d const & b) { 
+ return Linear2d(a*b[0], a*b[1], 
+ a*b[2], a*b[3]); 
+} 
+ 
+class SBasis2d : public std::vector<Linear2d>{ 
+public: 
+ // vector in u,v 
+ unsigned us, vs; // number of u terms, v terms 
+ SBasis2d() {} 
+ SBasis2d(Linear2d const & bo) 
+ : us(1), vs(1) { 
+ push_back(bo); 
+ } 
+ SBasis2d(SBasis2d const & a) 
+ : std::vector<Linear2d>(a), us(a.us), vs(a.vs) {} 
+ 
+ Linear2d& index(unsigned ui, unsigned vi) { 
+ assert(ui < us); 
+ assert(vi < vs); 
+ return (*this)[ui + vi*us]; 
+ } 
+ 
+ Linear2d index(unsigned ui, unsigned vi) const { 
+ if(ui >= us) 
+ return Linear2d(0); 
+ if(vi >= vs) 
+ return Linear2d(0); 
+ return (*this)[ui + vi*us]; 
+ } 
+ 
+ double apply(double u, double v) const { 
+ double s = u*(1u); 
+ double t = v*(1v); 
+ Linear2d p; 
+ double tk = 1; 
+// XXX rewrite as horner 
+ for(unsigned vi = 0; vi < vs; vi++) { 
+ double sk = 1; 
+ for(unsigned ui = 0; ui < us; ui++) { 
+ p += (sk*tk)*index(ui, vi); 
+ sk *= s; 
+ } 
+ tk *= t; 
+ } 
+ return p.apply(u,v); 
+ } 
+ 
+ void clear() { 
+ fill(begin(), end(), Linear2d(0)); 
+ } 
+ 
+ void normalize(); // remove extra zeros 
+ 
+ double tail_error(unsigned tail) const; 
+ 
+ void truncate(unsigned k); 
+}; 
+ 
+inline SBasis2d operator(const SBasis2d& p) { 
+ SBasis2d result; 
+ result.reserve(p.size()); 
+ 
+ for(unsigned i = 0; i < p.size(); i++) { 
+ result.push_back(p[i]); 
+ } 
+ return result; 
+} 
+ 
+inline SBasis2d operator+(const SBasis2d& a, const SBasis2d& b) { 
+ SBasis2d result; 
+ result.us = std::max(a.us, b.us); 
+ result.vs = std::max(a.vs, b.vs); 
+ const unsigned out_size = result.us*result.vs; 
+ result.resize(out_size); 
+ 
+ for(unsigned vi = 0; vi < result.vs; vi++) { 
+ for(unsigned ui = 0; ui < result.us; ui++) { 
+ Linear2d bo; 
+ if(ui < a.us && vi < a.vs) 
+ bo += a.index(ui, vi); 
+ if(ui < b.us && vi < b.vs) 
+ bo += b.index(ui, vi); 
+ result.index(ui, vi) = bo; 
+ } 
+ } 
+ return result; 
+} 
+ 
+inline SBasis2d operator(const SBasis2d& a, const SBasis2d& b) { 
+ SBasis2d result; 
+ result.us = std::max(a.us, b.us); 
+ result.vs = std::max(a.vs, b.vs); 
+ const unsigned out_size = result.us*result.vs; 
+ result.resize(out_size); 
+ 
+ for(unsigned vi = 0; vi < result.vs; vi++) { 
+ for(unsigned ui = 0; ui < result.us; ui++) { 
+ Linear2d bo; 
+ if(ui < a.us && vi < a.vs) 
+ bo += a.index(ui, vi); 
+ if(ui < b.us && vi < b.vs) 
+ bo = b.index(ui, vi); 
+ result.index(ui, vi) = bo; 
+ } 
+ } 
+ return result; 
+} 
+ 
+ 
+inline SBasis2d& operator+=(SBasis2d& a, const Linear2d& b) { 
+ if(a.size() < 1) 
+ a.push_back(b); 
+ else 
+ a[0] += b; 
+ return a; 
+} 
+ 
+inline SBasis2d& operator=(SBasis2d& a, const Linear2d& b) { 
+ if(a.size() < 1) 
+ a.push_back(b); 
+ else 
+ a[0] = b; 
+ return a; 
+} 
+ 
+inline SBasis2d& operator+=(SBasis2d& a, double b) { 
+ if(a.size() < 1) 
+ a.push_back(Linear2d(b)); 
+ else { 
+ for(unsigned i = 0; i < 4; i++) 
+ a[0] += double(b); 
+ } 
+ return a; 
+} 
+ 
+inline SBasis2d& operator=(SBasis2d& a, double b) { 
+ if(a.size() < 1) 
+ a.push_back(Linear2d(b)); 
+ else { 
+ a[0] = b; 
+ } 
+ return a; 
+} 
+ 
+inline SBasis2d& operator*=(SBasis2d& a, double b) { 
+ for(unsigned i = 0; i < a.size(); i++) 
+ a[i] *= b; 
+ return a; 
+} 
+ 
+inline SBasis2d& operator/=(SBasis2d& a, double b) { 
+ for(unsigned i = 0; i < a.size(); i++) 
+ a[i] *= (1./b); 
+ return a; 
+} 
+ 
+SBasis2d operator*(double k, SBasis2d const &a); 
+SBasis2d operator*(SBasis2d const &a, SBasis2d const &b); 
+ 
+SBasis2d shift(SBasis2d const &a, int sh); 
+ 
+SBasis2d shift(Linear2d const &a, int sh); 
+ 
+SBasis2d truncate(SBasis2d const &a, unsigned terms); 
+ 
+SBasis2d multiply(SBasis2d const &a, SBasis2d const &b); 
+ 
+SBasis2d integral(SBasis2d const &c); 
+ 
+SBasis2d derivative(SBasis2d const &a); 
+ 
+SBasis2d sqrt(SBasis2d const &a, int k); 
+ 
+// return a kth order approx to 1/a) 
+SBasis2d reciprocal(Linear2d const &a, int k); 
+ 
+SBasis2d divide(SBasis2d const &a, SBasis2d const &b, int k); 
+ 
+// a(b(t)) 
+SBasis2d compose(SBasis2d const &a, SBasis2d const &b); 
+SBasis2d compose(SBasis2d const &a, SBasis2d const &b, unsigned k); 
+SBasis2d inverse(SBasis2d const &a, int k); 
+ 
+// these two should probably be replaced with compose 
+SBasis extract_u(SBasis2d const &a, double u); 
+SBasis extract_v(SBasis2d const &a, double v); 
+ 
+SBasis compose(Linear2d const &a, D2<SBasis> const &p); 
+ 
+SBasis compose(SBasis2d const &fg, D2<SBasis> const &p); 
+ 
+D2<SBasis> compose_each(D2<SBasis2d> const &fg, D2<SBasis> const &p); 
+ 
+inline std::ostream &operator<< (std::ostream &out_file, const Linear2d &bo) { 
+ out_file << "{" << bo[0] << ", " << bo[1] << "}, "; 
+ out_file << "{" << bo[2] << ", " << bo[3] << "}"; 
+ return out_file; 
+} 
+ 
+inline std::ostream &operator<< (std::ostream &out_file, const SBasis2d & p) { 
+ for(unsigned i = 0; i < p.size(); i++) { 
+ out_file << p[i] << "s^" << i << " + "; 
+ } 
+ return out_file; 
+} 
+ 
+}; 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
+#endif 
Index: Scribus/scribus/third_party/lib2geom/point.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/point.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/point.h (revision 14937) 
@@ 0,0 +1,229 @@ 
+#ifndef SEEN_Geom_POINT_H 
+#define SEEN_Geom_POINT_H 
+ 
+/** \file 
+ * Cartesian point class. 
+ */ 
+ 
+#include <iostream> 
+ 
+#include "coord.h" 
+#include "utils.h" 
+ 
+namespace Geom { 
+ 
+enum Dim2 { X=0, Y=1 }; 
+ 
+class Matrix; 
+ 
+/// Cartesian point. 
+class Point { 
+ Coord _pt[2]; 
+ 
+ public: 
+ inline Point() 
+ { _pt[X] = _pt[Y] = 0; } 
+ 
+ inline Point(Coord x, Coord y) { 
+ _pt[X] = x; _pt[Y] = y; 
+ } 
+ 
+ inline Point(Point const &p) { 
+ for (unsigned i = 0; i < 2; ++i) 
+ _pt[i] = p._pt[i]; 
+ } 
+ 
+ inline Point &operator=(Point const &p) { 
+ for (unsigned i = 0; i < 2; ++i) 
+ _pt[i] = p._pt[i]; 
+ return *this; 
+ } 
+ 
+ inline Coord operator[](unsigned i) const { return _pt[i]; } 
+ inline Coord &operator[](unsigned i) { return _pt[i]; } 
+ 
+ Coord operator[](Dim2 d) const throw() { return _pt[d]; } 
+ Coord &operator[](Dim2 d) throw() { return _pt[d]; } 
+ 
+ static inline Point polar(Coord angle, Coord radius) { 
+ return Point(radius * std::cos(angle), radius * std::sin(angle)); 
+ } 
+ 
+ inline Coord length() const { return hypot(_pt[0], _pt[1]); } 
+ 
+ /** Return a point like this point but rotated 90 degrees. 
+ (If the y axis grows downwards and the x axis grows to the 
+ right, then this is 90 degrees counterclockwise.) 
+ **/ 
+ Point ccw() const { 
+ return Point(_pt[Y], _pt[X]); 
+ } 
+ 
+ /** Return a point like this point but rotated +90 degrees. 
+ (If the y axis grows downwards and the x axis grows to the 
+ right, then this is 90 degrees clockwise.) 
+ **/ 
+ Point cw() const { 
+ return Point(_pt[Y], _pt[X]); 
+ } 
+ 
+ /** 
+ \brief A function to lower the precision of the point 
+ \param places The number of decimal places that should be in 
+ the final number. 
+ */ 
+ inline void round (int places = 0) { 
+ _pt[X] = (Coord)(decimal_round((double)_pt[X], places)); 
+ _pt[Y] = (Coord)(decimal_round((double)_pt[Y], places)); 
+ return; 
+ } 
+ 
+ void normalize(); 
+ 
+ inline Point operator+(Point const &o) const { 
+ return Point(_pt[X] + o._pt[X], _pt[Y] + o._pt[Y]); 
+ } 
+ inline Point operator(Point const &o) const { 
+ return Point(_pt[X]  o._pt[X], _pt[Y]  o._pt[Y]); 
+ } 
+ inline Point &operator+=(Point const &o) { 
+ for ( unsigned i = 0 ; i < 2 ; ++i ) { 
+ _pt[i] += o._pt[i]; 
+ } 
+ return *this; 
+ } 
+ inline Point &operator=(Point const &o) { 
+ for ( unsigned i = 0 ; i < 2 ; ++i ) { 
+ _pt[i] = o._pt[i]; 
+ } 
+ return *this; 
+ } 
+ 
+ inline Point operator() const { 
+ return Point(_pt[X], _pt[Y]); 
+ } 
+ inline Point operator*(double const s) const { 
+ return Point(_pt[X] * s, _pt[Y] * s); 
+ } 
+ inline Point operator/(double const s) const { 
+ //TODO: s == 0? 
+ return Point(_pt[X] / s, _pt[Y] / s); 
+ } 
+ inline Point &operator*=(double const s) { 
+ for ( unsigned i = 0 ; i < 2 ; ++i ) _pt[i] *= s; 
+ return *this; 
+ } 
+ inline Point &operator/=(double const s) { 
+ //TODO: s == 0? 
+ for ( unsigned i = 0 ; i < 2 ; ++i ) _pt[i] /= s; 
+ return *this; 
+ } 
+ 
+ Point &operator*=(Matrix const &m); 
+ 
+ inline int operator == (const Point &in_pnt) { 
+ return ((_pt[X] == in_pnt[X]) && (_pt[Y] == in_pnt[Y])); 
+ } 
+ 
+ friend inline std::ostream &operator<< (std::ostream &out_file, const Geom::Point &in_pnt); 
+}; 
+ 
+inline Point operator*(double const s, Point const &p) { return p * s; } 
+ 
+/** A function to print out the Point. It just prints out the coords 
+ on the given output stream */ 
+inline std::ostream &operator<< (std::ostream &out_file, const Geom::Point &in_pnt) { 
+ out_file << "X: " << in_pnt[X] << " Y: " << in_pnt[Y]; 
+ return out_file; 
+} 
+ 
+/** This is a rotation (sort of). */ 
+inline Point operator^(Point const &a, Point const &b) { 
+ Point const ret(a[0] * b[0]  a[1] * b[1], 
+ a[1] * b[0] + a[0] * b[1]); 
+ return ret; 
+} 
+ 
+//IMPL: boost::EqualityComparableConcept 
+inline bool operator==(Point const &a, Point const &b) { 
+ return (a[X] == b[X]) && (a[Y] == b[Y]); 
+} 
+inline bool operator!=(Point const &a, Point const &b) { 
+ return (a[X] != b[X])  (a[Y] != b[Y]); 
+} 
+ 
+/** This is a lexicographical ordering for points. It is remarkably useful for sweepline algorithms*/ 
+inline bool operator<=(Point const &a, Point const &b) { 
+ return ( ( a[Y] < b[Y] )  
+ (( a[Y] == b[Y] ) && ( a[X] < b[X] ))); 
+} 
+ 
+Coord L1(Point const &p); 
+ 
+/** Compute the L2, or euclidean, norm of \a p. */ 
+inline Coord L2(Point const &p) { return p.length(); } 
+ 
+/** Compute the square of L2 norm of \a p. Warning: this can overflow where L2 won't.*/ 
+inline Coord L2sq(Point const &p) { return p[0]*p[0] + p[1]*p[1]; } 
+ 
+double LInfty(Point const &p); 
+bool is_zero(Point const &p); 
+bool is_unit_vector(Point const &p); 
+ 
+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); 
+ 
+//IMPL: NearConcept 
+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) ); 
+} 
+ 
+/** Returns p * Geom::rotate_degrees(90), but more efficient. 
+ * 
+ * Angle direction in Inkscape code: If you use the traditional mathematics convention that y 
+ * increases upwards, then positive angles are anticlockwise as per the mathematics convention. If 
+ * you take the common nonmathematical convention that y increases downwards, then positive angles 
+ * are clockwise, as is common outside of mathematics. 
+ * 
+ * There is no rot_neg90 function: use rot90(p) instead. 
+ */ 
+inline Point rot90(Point const &p) { return Point(p[Y], p[X]); } 
+ 
+/** Given two points and a parameter t \in [0, 1], return a point 
+ * proportionally from a to b by t. Akin to 1 degree bezier.*/ 
+inline Point lerp(double const t, Point const a, Point const b) { return (a * (1  t) + b * t); } 
+ 
+Point unit_vector(Point const &a); 
+ 
+/** compute the dot product (inner product) between the vectors a and b. */ 
+inline Coord dot(Point const &a, Point const &b) { return a[0] * b[0] + a[1] * b[1]; } 
+/** Defined as dot(a, b.cw()). */ 
+inline Coord cross(Point const &a, Point const &b) { return dot(a, b.cw()); } 
+ 
+/** compute the euclidean distance between points a and b. TODO: hypot safer/faster? */ 
+inline Coord distance (Point const &a, Point const &b) { return L2(a  b); } 
+ 
+/** compute the square of the distance between points a and b. */ 
+inline Coord distanceSq (Point const &a, Point const &b) { return L2sq(a  b); } 
+ 
+Point abs(Point const &b); 
+ 
+Point operator*(Point const &v, Matrix const &m); 
+ 
+Point operator/(Point const &p, Matrix const &m); 
+ 
+} /* namespace Geom */ 
+ 
+#endif /* !SEEN_Geom_POINT_H */ 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/quadtree.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/quadtree.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/quadtree.cpp (revision 14937) 
@@ 0,0 +1,131 @@ 
+#include "quadtree.h" 
+ 
+Quad* QuadTree::search(double x0, double y0, double x1, double y1) { 
+ Quad *q = root; 
+ 
+ double bxx0 = bx1, bxx1 = bx1; 
+ double byy0 = by1, byy1 = by1; 
+ while(q) { 
+ double cx = (bxx0 + bxx1)/2; 
+ double cy = (byy0 + byy1)/2; 
+ unsigned i = 0; 
+ if(x0 >= cx) { 
+ i += 1; 
+ bxx0 = cx; // zoom in a quad 
+ } else if(x1 <= cx) { 
+ bxx1 = cx; 
+ } else 
+ break; 
+ if(y0 >= cy) { 
+ i += 2; 
+ byy0 = cy; 
+ } else if(y1 <= cy) { 
+ byy1 = cy; 
+ } else 
+ break; 
+ 
+ assert(i < 4); 
+ Quad *qq = q>children[i]; 
+ if(qq == 0) break; // last nonnull 
+ q = qq; 
+ } 
+ return q; 
+} 
+ 
+void QuadTree::insert(double x0, double y0, double x1, double y1, int shape) { 
+ // loop until a quad would break the box. 
+ if(root == 0) { 
+ root = new Quad; 
+ 
+ bx0 = 0; 
+ bx1 = 1; 
+ by0 = 0; 
+ by1 = 1; 
+ } 
+ Quad *q = root; 
+ 
+ double bxx0 = bx0, bxx1 = bx1; 
+ double byy0 = by0, byy1 = by1; 
+ while((bxx0 > x0)  
+ (bxx1 < x1)  
+ (byy0 > y0)  
+ (byy1 < y1)) { // too small initial size  double 
+ unsigned i = 0; 
+ if(bxx0 > x0) { 
+ bxx0 = 2*bxx0  bxx1; 
+ i += 1; 
+ } else { 
+ bxx1 = 2*bxx1  bxx0; 
+ } 
+ if(byy0 > y0) { 
+ byy0 = 2*byy0  byy1; 
+ i += 2; 
+ } else { 
+ byy1 = 2*byy1  byy0; 
+ } 
+ q = new Quad; 
+ q>children[i] = root; 
+ root = q; 
+ bx0 = bxx0; 
+ bx1 = bxx1; 
+ by0 = byy0; 
+ by1 = byy1; 
+ } 
+ 
+ while(q) { 
+ double cx = (bxx0 + bxx1)/2; 
+ double cy = (byy0 + byy1)/2; 
+ unsigned i = 0; 
+ assert(x0 >= bxx0); 
+ assert(x1 <= bxx1); 
+ assert(y0 >= byy0); 
+ assert(y1 <= byy1); 
+ if(x0 >= cx) { 
+ i += 1; 
+ bxx0 = cx; // zoom in a quad 
+ } else if(x1 <= cx) { 
+ bxx1 = cx; 
+ } else 
+ break; 
+ if(y0 >= cy) { 
+ i += 2; 
+ byy0 = cy; 
+ } else if(y1 <= cy) { 
+ byy1 = cy; 
+ } else 
+ break; 
+ 
+ assert(i < 4); 
+ Quad *qq = q>children[i]; 
+ if(qq == 0) { 
+ qq = new Quad; 
+ q>children[i] = qq; 
+ } 
+ q = qq; 
+ } 
+ q>data.push_back(shape); 
+} 
+void QuadTree::erase(Quad *q, int shape) { 
+ for(Quad::iterator i = q>data.begin(); i != q>data.end(); i++) { 
+ if(*i == shape) { 
+ q>data.erase(i); 
+ if(q>data.empty()) { 
+ 
+ } 
+ } 
+ } 
+ return; 
+} 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(substatementopen . 0)) 
+ indenttabsmode:nil 
+ cbraceoffset:0 
+ fillcolumn:99 
+ End: 
+ vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : 
+*/ 
+ 
Index: Scribus/scribus/third_party/lib2geom/convexcover.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/convexcover.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/convexcover.cpp (revision 14937) 
@@ 0,0 +1,450 @@ 
+/* 
+ * convexcover.cpp 
+ * 
+ * Copyright 2006 Nathan Hurst <njh@mail.csse.monash.edu.au> 
+ * Copyright 2006 Michael G. 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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 "convexcover.h" 
+#include <algorithm> 
+#include <map> 
+/** Todo: 
+ + modify graham scan to work top to bottom, rather than around angles 
+ + intersection 
+ + minimum distance between convex hulls 
+ + maximum distance between convex hulls 
+ + hausdorf metric? 
+ + check all degenerate cases carefully 
+ + check all algorithms meet all invariants 
+ + generalise rotating caliper algorithm (iterator/circulator?) 
+*/ 
+ 
+using std::vector; 
+using std::map; 
+using std::pair; 
+ 
+namespace Geom{ 
+ 
+/*** SignedTriangleArea 
+ * returns the area of the triangle defined by p0, p1, p2. A clockwise triangle has positive area. 
+ */ 
+double 
+SignedTriangleArea(Point p0, Point p1, Point p2) { 
+ return cross((p1  p0), (p2  p0)); 
+} 
+ 
+class angle_cmp{ 
+public: 
+ Point o; 
+ angle_cmp(Point o) : o(o) {} 
+ 
+ bool 
+ operator()(Point a, Point b) { 
+ Point da = a  o; 
+ Point db = b  o; 
+ 
+#if 1 
+ double aa = da[0]; 
+ double ab = db[0]; 
+ if((da[1] == 0) && (db[1] == 0)) 
+ return da[0] < db[0]; 
+ if(da[1] == 0) 
+ return true; // infinite tangent 
+ if(db[1] == 0) 
+ return false; // infinite tangent 
+ aa = da[0] / da[1]; 
+ ab = db[0] / db[1]; 
+ if(aa > ab) 
+ return true; 
+#else 
+ //assert((ata > atb) == (aa < ab)); 
+ double aa = atan2(da); 
+ double ab = atan2(db); 
+ if(aa < ab) 
+ return true; 
+#endif 
+ if(aa == ab) 
+ return L2sq(da) < L2sq(db); 
+ return false; 
+ } 
+}; 
+ 
+void 
+ConvexHull::find_pivot() { 
+ // Find pivot P; 
+ unsigned pivot = 0; 
+ for(unsigned i = 1; i < boundary.size(); i++) 
+ if(boundary[i] <= boundary[pivot]) 
+ pivot = i; 
+ 
+ std::swap(boundary[0], boundary[pivot]); 
+} 
+ 
+void 
+ConvexHull::angle_sort() { 
+// sort points by angle (resolve ties in favor of point farther from P); 
+// we leave the first one in place as our pivot 
+ std::sort(boundary.begin()+1, boundary.end(), angle_cmp(boundary[0])); 
+} 
+ 
+void 
+ConvexHull::graham_scan() { 
+ unsigned stac = 2; 
+ for(unsigned i = 2; i < boundary.size(); i++) { 
+ double o = SignedTriangleArea(boundary[stac2], 
+ boundary[stac1], 
+ boundary[i]); 
+ if(o == 0) { // colinear  dangerous... 
+ stac; 
+ } else if(o < 0) { // anticlockwise 
+ } else { // remove concavity 
+ while(o >= 0 && stac > 2) { 
+ stac; 
+ o = SignedTriangleArea(boundary[stac2], 
+ boundary[stac1], 
+ boundary[i]); 
+ } 
+ } 
+ boundary[stac++] = boundary[i]; 
+ } 
+ boundary.resize(stac); 
+} 
+ 
+void 
+ConvexHull::graham() { 
+ find_pivot(); 
+ angle_sort(); 
+ graham_scan(); 
+} 
+ 
+//Mathematically incorrect mod, but more useful. 
+int mod(int i, int l) { 
+ return i >= 0 ? 
+ i % l : (i % l) + l; 
+} 
+//OPT: usages can often be replaced by conditions 
+ 
+/*** ConvexHull::left 
+ * Tests if a point is left (outside) of a particular segment, n. */ 
+bool 
+ConvexHull::is_left(Point p, int n) { 
+ return SignedTriangleArea((*this)[n], (*this)[n+1], p) > 0; 
+} 
+ 
+/*** ConvexHull::find_positive 
+ * May return any number n where the segment n > n + 1 (possibly looped around) in the hull such 
+ * that the point is on the wrong side to be within the hull. Returns 1 if it is within the hull.*/ 
+int 
+ConvexHull::find_left(Point p) { 
+ int l = boundary.size(); //Who knows if C++ is smart enough to optimize this? 
+ for(int i = 0; i < l; i++) { 
+ if(is_left(p, i)) return i; 
+ } 
+ return 1; 
+} 
+//OPT: do a spread iteration  quasirandom with no repeats and full coverage. 
+ 
+/*** ConvexHull::contains_point 
+ * In order to test whether a point is inside a convex hull we can travel once around the outside making 
+ * sure that each triangle made from an edge and the point has positive area. */ 
+bool 
+ConvexHull::contains_point(Point p) { 
+ return find_left(p) == 1; 
+} 
+ 
+/*** ConvexHull::add_point 
+ * to add a point we need to find whether the new point extends the boundary, and if so, what it 
+ * obscures. Tarjan? Jarvis?*/ 
+void 
+ConvexHull::merge(Point p) { 
+ std::vector<Point> out; 
+ 
+ int l = boundary.size(); 
+ 
+ if(l < 2) { 
+ boundary.push_back(p); 
+ return; 
+ } 
+ 
+ bool pushed = false; 
+ 
+ bool pre = is_left(p, 1); 
+ for(int i = 0; i < l; i++) { 
+ bool cur = is_left(p, i); 
+ if(pre) { 
+ if(cur) { 
+ if(!pushed) { 
+ out.push_back(p); 
+ pushed = true; 
+ } 
+ continue; 
+ } 
+ else if(!pushed) { 
+ out.push_back(p); 
+ pushed = true; 
+ } 
+ } 
+ out.push_back(boundary[i]); 
+ pre = cur; 
+ } 
+ 
+ boundary = out; 
+} 
+//OPT: quickly find an obscured point and find the bounds by extending from there. then push all points not within the bounds in order. 
+ //OPT: use binary searches to find the actual starts/ends, use known rights as boundaries. may require cooperation of find_left algo. 
+ 
+/*** ConvexHull::is_clockwise 
+ * We require that successive pairs of edges always turn right. 
+ * proposed algorithm: walk successive edges and require triangle area is positive. 
+ */ 
+bool 
+ConvexHull::is_clockwise() const { 
+ if(is_degenerate()) 
+ return true; 
+ Point first = boundary[0]; 
+ Point second = boundary[1]; 
+ for(std::vector<Point>::const_iterator it(boundary.begin()+2), e(boundary.end()); 
+ it != e;) { 
+ if(SignedTriangleArea(first, second, *it) > 0) 
+ return false; 
+ first = second; 
+ second = *it; 
+ ++it; 
+ } 
+ return true; 
+} 
+ 
+/*** ConvexHull::top_point_first 
+ * We require that the first point in the convex hull has the least y coord, and that off all such points on the hull, it has the least x coord. 
+ * proposed algorithm: track lexicographic minimum while walking the list. 
+ */ 
+bool 
+ConvexHull::top_point_first() const { 
+ std::vector<Point>::const_iterator pivot = boundary.begin(); 
+ for(std::vector<Point>::const_iterator it(boundary.begin()+1), 
+ e(boundary.end()); 
+ it != e; it++) { 
+ if((*it)[1] < (*pivot)[1]) 
+ pivot = it; 
+ else if(((*it)[1] == (*pivot)[1]) && 
+ ((*it)[0] < (*pivot)[0])) 
+ pivot = it; 
+ } 
+ return pivot == boundary.begin(); 
+} 
+//OPT: since the Y values are orderly there should be something like a binary search to do this. 
+ 
+/*** ConvexHull::no_colinear_points 
+ * We require that no three vertices are colinear. 
+proposed algorithm: We must be very careful about rounding here. 
+*/ 
+bool 
+ConvexHull::no_colinear_points() const { 
+ return true; 
+} 
+ 
+bool 
+ConvexHull::meets_invariants() const { 
+ return is_clockwise() && top_point_first() && no_colinear_points(); 
+} 
+ 
+/*** ConvexHull::is_degenerate 
+ * We allow three degenerate cases: empty, 1 point and 2 points. In many cases these should be handled explicitly. 
+ */ 
+bool 
+ConvexHull::is_degenerate() const { 
+ return boundary.size() < 3; 
+} 
+ 
+ 
+/* Here we really need a rotating calipers implementation. This implementation is slow and incorrect. 
+ This incorrectness is a problem because it throws off the algorithms. Perhaps I will come up with 
+ something better tomorrow. The incorrectness is in the order of the bridges  they must be in the 
+ order of traversal around. Since the a>b and b>a bridges are seperated, they don't need to be merge 
+ order, just the order of the traversal of the host hull. Currently some situations make a n>0 bridge 
+ first.*/ 
+pair< map<int, int>, map<int, int> > 
+bridges(ConvexHull a, ConvexHull b) { 
+ map<int, int> abridges; 
+ map<int, int> bbridges; 
+ 
+ for(unsigned ia = 0; ia < a.boundary.size(); ia++) { 
+ for(unsigned ib = 0; ib < b.boundary.size(); ib++) { 
+ Point d = b[ib]  a[ia]; 
+ Geom::Coord e = cross(d, a[ia  1]  a[ia]), f = cross(d, a[ia + 1]  a[ia]); 
+ Geom::Coord g = cross(d, b[ib  1]  a[ia]), h = cross(d, b[ib + 1]  a[ia]); 
+ if (e > 0 && f > 0 && g > 0 && h > 0) abridges[ia] = ib; 
+ else if(e < 0 && f < 0 && g < 0 && h < 0) bbridges[ib] = ia; 
+ } 
+ } 
+ 
+ return make_pair(abridges, bbridges); 
+} 
+ 
+std::vector<Point> bridge_points(ConvexHull a, ConvexHull b) { 
+ vector<Point> ret; 
+ pair< map<int, int>, map<int, int> > indices = bridges(a, b); 
+ for(map<int, int>::iterator it = indices.first.begin(); it != indices.first.end(); it++) { 
+ ret.push_back(a[it>first]); 
+ ret.push_back(b[it>second]); 
+ } 
+ for(map<int, int>::iterator it = indices.second.begin(); it != indices.second.end(); it++) { 
+ ret.push_back(b[it>first]); 
+ ret.push_back(a[it>second]); 
+ } 
+ return ret; 
+} 
+ 
+unsigned find_bottom_right(ConvexHull const &a) { 
+ unsigned it = 1; 
+ while(it < a.boundary.size() && 
+ a.boundary[it][Y] > a.boundary[it1][Y]) 
+ it++; 
+ return it1; 
+} 
+ 
+/*** ConvexHull sweepline_intersection(ConvexHull a, ConvexHull b); 
+ * find the intersection between two convex hulls. The intersection is also a convex hull. 
+ * (Proof: take any two points both in a and in b. Any point between them is in a by convexity, 
+ * and in b by convexity, thus in both. Need to prove still finite bounds.) 
+ * This algorithm works by sweeping a line down both convex hulls in parallel, working out the left and right edges of the new hull. 
+ */ 
+ConvexHull sweepline_intersection(ConvexHull const &a, ConvexHull const &b) { 
+ ConvexHull ret; 
+ 
+ unsigned al = 0; 
+ unsigned bl = 0; 
+ 
+ while(al+1 < a.boundary.size() && 
+ (a.boundary[al+1][Y] > b.boundary[bl][Y])) { 
+ al++; 
+ } 
+ while(bl+1 < b.boundary.size() && 
+ (b.boundary[bl+1][Y] > a.boundary[al][Y])) { 
+ bl++; 
+ } 
+ return ret; 
+ // al and bl now point to the top of the first pair of edges that overlap in y value 
+// double sweep_y = std::min(a.boundary[al][Y], 
+// b.boundary[bl][Y]); 
+} 
+ 
+/*** ConvexHull intersection(ConvexHull a, ConvexHull b); 
+ * find the intersection between two convex hulls. The intersection is also a convex hull. 
+ * (Proof: take any two points both in a and in b. Any point between them is in a by convexity, 
+ * and in b by convexity, thus in both. Need to prove still finite bounds.) 
+ */ 
+ConvexHull intersection(ConvexHull a, ConvexHull b) { 
+ ConvexHull ret; 
+// int ai = 0, bi = 0; 
+// unsigned aj = a.boundary.size()  1; 
+// unsigned bj = b.boundary.size()  1; 
+ 
+ /*while (true) { 
+ if(a[ai] 
+ }*/ 
+ return ret; 
+} 
+ 
+/*** ConvexHull merge(ConvexHull a, ConvexHull b); 
+ * find the smallest convex hull that surrounds a and b. 
+ */ 
+ConvexHull merge(ConvexHull a, ConvexHull b) { 
+ ConvexHull ret; 
+ 
+ pair< map<int, int>, map<int, int> > bpair = bridges(a, b); 
+ map<int, int> ab = bpair.first; 
+ map<int, int> bb = bpair.second; 
+ 
+ ab[1] = 0; 
+ bb[1] = 0; 
+ 
+ int i = 1; 
+ 
+ if(a.boundary[0][1] > b.boundary[0][1]) goto start_b; 
+ while(true) { 
+ for(; ab.count(i) == 0; i++) { 
+ ret.boundary.push_back(a[i]); 
+ if(i >= static_cast<int>(a.boundary.size())) return ret; 
+ } 
+ if(ab[i] == 0 && i != 1) break; 
+ i = ab[i]; 
+ start_b: 
+ 
+ for(; bb.count(i) == 0; i++) { 
+ ret.boundary.push_back(b[i]); 
+ if(i >= static_cast<int>(b.boundary.size())) return ret; 
+ } 
+ if(bb[i] == 0 && i != 1) break; 
+ i = bb[i]; 
+ } 
+ return ret; 
+} 
+ 
+ConvexHull graham_merge(ConvexHull a, ConvexHull b) { 
+ ConvexHull result; 
+ 
+ // we can avoid the find pivot step because of top_point_first 
+ if(b.boundary[0] <= a.boundary[0]) 
+ std::swap(a, b); 
+ 
+ result.boundary = a.boundary; 
+ result.boundary.insert(result.boundary.end(), 
+ b.boundary.begin(), b.boundary.end()); 
+ 
+/** if we modified graham scan to work top to bottom as proposed in lect754.pdf we could replace the 
+ angle sort with a simple merge sort type algorithm. furthermore, we could do the graham scan 
+ online, avoiding a bunch of memory copies. That would probably be linear.  njh*/ 
+ result.angle_sort(); 
+ result.graham_scan(); 
+ 
+ return result; 
+} 
+//TODO: reinstate 
+/*ConvexCover::ConvexCover(Path const &sp) : path(&sp) { 
+ cc.reserve(sp.size()); 
+ for(Geom::Path::const_iterator it(sp.begin()), end(sp.end()); it != end; ++it) { 
+ cc.push_back(ConvexHull((*it).begin(), (*it).end())); 
+ } 
+}*/ 
+ 
+ 
+}; 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(substatementopen . 0)) 
+ indenttabsmode:nil 
+ cbraceoffset:0 
+ fillcolumn:99 
+ End: 
+ vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : 
+*/ 
+ 
+ 
Index: Scribus/scribus/third_party/lib2geom/solver.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/solver.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/solver.h (revision 14937) 
@@ 0,0 +1,33 @@ 
+#ifndef _SOLVE_SBASIS_H 
+#define _SOLVE_SBASIS_H 
+#include "point.h" 
+#include "sbasis.h" 
+ 
+namespace Geom{ 
+ 
+ class Point; 
+ 
+unsigned 
+crossing_count(Geom::Point const *V, /* Control pts of Bezier curve */ 
+ unsigned degree); /* Degree of Bezier curve */ 
+void 
+find_parametric_bezier_roots( 
+ Geom::Point const *w, /* The control points */ 
+ unsigned degree, /* The degree of the polynomial */ 
+ std::vector<double> & solutions, /* RETURN candidate tvalues */ 
+ unsigned depth); /* The depth of the recursion */ 
+ 
+unsigned 
+crossing_count(double const *V, /* Control pts of Bezier curve */ 
+ unsigned degree, /* Degree of Bezier curve */ 
+ double left_t, double right_t); 
+void 
+find_bernstein_roots( 
+ double const *w, /* The control points */ 
+ unsigned degree, /* The degree of the polynomial */ 
+ std::vector<double> & solutions, /* RETURN candidate tvalues */ 
+ unsigned depth, /* The depth of the recursion */ 
+ double left_t=0, double right_t=1); 
+ 
+}; 
+#endif 
Index: Scribus/scribus/third_party/lib2geom/linear.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/linear.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/linear.h (revision 14937) 
@@ 0,0 +1,173 @@ 
+/* 
+ * linear.h  Linear fragment function class 
+ * 
+ * Authors: 
+ * Nathan Hurst <njh@mail.csse.monash.edu.au> 
+ * Michael Sloan <mgsloan@gmail.com> 
+ * 
+ * Copyright (C) 20062007 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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_LINEAR_H 
+#define SEEN_LINEAR_H 
+#include "isnan.h" 
+#include "interval.h" 
+ 
+namespace Geom{ 
+ 
+inline double lerp(double t, double a, double b) { return a*(1t) + b*t; } 
+ 
+class SBasis; 
+ 
+class Hat{ 
+public: 
+ Hat () {} 
+ Hat(double d) :d(d) {} 
+ operator double() const { return d; } 
+ double d; 
+}; 
+ 
+class Tri{ 
+public: 
+ Tri () {} 
+ Tri(double d) :d(d) {} 
+ operator double() const { return d; } 
+ double d; 
+}; 
+ 
+class Linear{ 
+public: 
+ double a[2]; 
+ Linear() {} 
+ Linear(double aa, double b) {a[0] = aa; a[1] = b;} 
+ Linear(Hat h, Tri t) { 
+ a[0] = double(h)  double(t)/2; 
+ a[1] = double(h) + double(t)/2; 
+ } 
+ 
+ Linear(Hat h) { 
+ a[0] = double(h); 
+ a[1] = double(h); 
+ } 
+ 
+ double operator[](const int i) const { 
+ assert(i >= 0); 
+ assert(i < 2); 
+ return a[i]; 
+ } 
+ double& operator[](const int i) { 
+ assert(i >= 0); 
+ assert(i < 2); 
+ return a[i]; 
+ } 
+ 
+ //IMPL: FragmentConcept 
+ typedef double output_type; 
+ inline bool isZero() const { return a[0] == 0 && a[1] == 0; } 
+ inline bool isConstant() const { return a[0] == a[1]; } 
+ inline bool isFinite() const { return is_finite(a[0]) && is_finite(a[1]); } 
+ 
+ inline double at0() const { return a[0]; } 
+ inline double at1() const { return a[1]; } 
+ 
+ inline double valueAt(double t) const { return lerp(t, a[0], a[1]); } 
+ inline double operator()(double t) const { return valueAt(t); } 
+ 
+ //defined in sbasis.h 
+ inline SBasis toSBasis() const; 
+ 
+ inline Interval bounds_exact() const { return Interval(a[0], a[1]); } 
+ inline Interval bounds_fast() const { return bounds_exact(); } 
+ inline Interval bounds_local(double u, double v) const { return Interval(valueAt(u), valueAt(v)); } 
+ 
+ operator Tri() const { 
+ return a[1]  a[0]; 
+ } 
+ operator Hat() const { 
+ return (a[1] + a[0])/2; 
+ } 
+}; 
+ 
+inline Linear reverse(Linear const &a) { return Linear(a[1], a[0]); } 
+ 
+//IMPL: AddableConcept 
+inline Linear operator+(Linear const & a, Linear const & b) { 
+ return Linear(a[0] + b[0], a[1] + b[1]); 
+} 
+inline Linear operator(Linear const & a, Linear const & b) { 
+ return Linear(a[0]  b[0], a[1]  b[1]); 
+} 
+inline Linear& operator+=(Linear & a, Linear const & b) { 
+ a[0] += b[0]; a[1] += b[1]; 
+ return a; 
+} 
+inline Linear& operator=(Linear & a, Linear const & b) { 
+ a[0] = b[0]; a[1] = b[1]; 
+ return a; 
+} 
+//IMPL: OffsetableConcept 
+inline Linear operator+(Linear const & a, double b) { 
+ return Linear(a[0] + b, a[1] + b); 
+} 
+inline Linear operator(Linear const & a, double b) { 
+ return Linear(a[0]  b, a[1]  b); 
+} 
+inline Linear& operator+=(Linear & a, double b) { 
+ a[0] += b; a[1] += b; 
+ return a; 
+} 
+inline Linear& operator=(Linear & a, double b) { 
+ a[0] = b; a[1] = b; 
+ return a; 
+} 
+//IMPL: boost::EqualityComparableConcept 
+inline bool operator==(Linear const & a, Linear const & b) { 
+ return a[0] == b[0] && a[1] == b[1]; 
+} 
+inline bool operator!=(Linear const & a, Linear const & b) { 
+ return a[0] != b[0]  a[1] != b[1]; 
+} 
+//IMPL: ScalableConcept 
+inline Linear operator(Linear const &a) { 
+ return Linear(a[0], a[1]); 
+} 
+inline Linear operator*(Linear const & a, double b) { 
+ return Linear(a[0]*b, a[1]*b); 
+} 
+inline Linear operator/(Linear const & a, double b) { 
+ return Linear(a[0]/b, a[1]/b); 
+} 
+inline Linear operator*=(Linear & a, double b) { 
+ a[0] *= b; a[1] *= b; 
+ return a; 
+} 
+inline Linear operator/=(Linear & a, double b) { 
+ a[0] /= b; a[1] /= b; 
+ return a; 
+} 
+}; 
+ 
+#endif //SEEN_LINEAR_H 
Index: Scribus/scribus/third_party/lib2geom/choose.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/choose.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/choose.h (revision 14937) 
@@ 0,0 +1,67 @@ 
+/* 
+ * choose.h 
+ * 
+ * Copyright 2006 Nathan Hurst <njh@mail.csse.monash.edu.au> 
+ * 
+ * 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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 _CHOOSE_H 
+#define _CHOOSE_H 
+ 
+// XXX: Can we keep only the left terms easily? 
+// this would more than halve the array 
+// row index becomes n2 = n/2, row2 = n2*(n2+1)/2, row = row2*2+(n&1)?n2:0 
+// we could also leave off the ones 
+ 
+template <typename T> 
+T choose(unsigned n, unsigned k) { 
+ static std::vector<T> pascals_triangle; 
+ static unsigned rows_done = 0; 
+ // indexing is (0,0,), (1,0), (1,1), (2, 0)... 
+ // to get (i, j) i*(i+1)/2 + j 
+ if(k < 0  k > n) return 0; 
+ if(rows_done <= n) {// we haven't got there yet 
+ if(rows_done == 0) { 
+ pascals_triangle.push_back(1); 
+ rows_done = 1; 
+ } 
+ while(rows_done <= n) { 
+ unsigned p = pascals_triangle.size()  rows_done; 
+ pascals_triangle.push_back(1); 
+ for(unsigned i = 0; i < rows_done1; i++) { 
+ pascals_triangle.push_back(pascals_triangle[p] 
+ + pascals_triangle[p+1]); 
+ p++; 
+ } 
+ pascals_triangle.push_back(1); 
+ rows_done ++; 
+ } 
+ } 
+ unsigned row = (n*(n+1))/2; 
+ return pascals_triangle[row+k]; 
+} 
+ 
+#endif 
Index: Scribus/scribus/third_party/lib2geom/sbasis2d.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/sbasis2d.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/sbasis2d.cpp (revision 14937) 
@@ 0,0 +1,72 @@ 
+#include "sbasis2d.h" 
+ 
+namespace Geom{ 
+ 
+SBasis extract_u(SBasis2d const &a, double u) { 
+ SBasis sb; 
+ double s = u*(1u); 
+ 
+ for(unsigned vi = 0; vi < a.vs; vi++) { 
+ double sk = 1; 
+ Linear bo(0,0); 
+ for(unsigned ui = 0; ui < a.us; ui++) { 
+ bo += (extract_u(a.index(ui, vi), u))*sk; 
+ sk *= s; 
+ } 
+ sb.push_back(bo); 
+ } 
+ 
+ return sb; 
+} 
+ 
+SBasis extract_v(SBasis2d const &a, double v) { 
+ SBasis sb; 
+ double s = v*(1v); 
+ 
+ for(unsigned ui = 0; ui < a.us; ui++) { 
+ double sk = 1; 
+ Linear bo(0,0); 
+ for(unsigned vi = 0; vi < a.vs; vi++) { 
+ bo += (extract_v(a.index(ui, vi), v))*sk; 
+ sk *= s; 
+ } 
+ sb.push_back(bo); 
+ } 
+ 
+ return sb; 
+} 
+ 
+SBasis compose(Linear2d const &a, D2<SBasis> const &p) { 
+ D2<SBasis> omp(p[X] + 1, p[Y] + 1); 
+ return multiply(omp[0], omp[1])*a[0] + 
+ multiply(p[0], omp[1])*a[1] + 
+ multiply(omp[0], p[1])*a[2] + 
+ multiply(p[0], p[1])*a[3]; 
+} 
+ 
+SBasis 
+compose(SBasis2d const &fg, D2<SBasis> const &p) { 
+ SBasis B; 
+ SBasis s[2]; 
+ SBasis ss[2]; 
+ for(unsigned dim = 0; dim < 2; dim++) 
+ s[dim] = p[dim]*(Linear(1)  p[dim]); 
+ ss[1] = Linear(1); 
+ for(unsigned vi = 0; vi < fg.vs; vi++) { 
+ ss[0] = ss[1]; 
+ for(unsigned ui = 0; ui < fg.us; ui++) { 
+ unsigned i = ui + vi*fg.us; 
+ B += ss[0]*compose(fg[i], p); 
+ ss[0] *= s[0]; 
+ } 
+ ss[1] *= s[1]; 
+ } 
+ return B; 
+} 
+ 
+D2<SBasis> 
+compose_each(D2<SBasis2d> const &fg, D2<SBasis> const &p) { 
+ return D2<SBasis>(compose(fg[X], p), compose(fg[Y], p)); 
+} 
+ 
+}; 
Index: Scribus/scribus/third_party/lib2geom/sbasisroots.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/sbasisroots.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/sbasisroots.cpp (revision 14937) 
@@ 0,0 +1,350 @@ 
+/** root finding for sbasis functions. 
+ * Copyright 2006 N Hurst 
+ * Copyright 2007 JF Barraud 
+ * 
+ * It is more efficient to find roots of f(t) = c_0, c_1, ... all at once, rather than iterating. 
+ * 
+ * Todo/think about: 
+ * multiroots using bernstein method, one approach would be: 
+ sort c 
+ take median and find roots of that 
+ whenever a segment lies entirely on one side of the median, 
+ find the median of the half and recurse. 
+ 
+ in essence we are implementing quicksort on a continuous function 
+ 
+ * the gsl poly roots finder is faster than bernstein too, but we don't use it for 3 reasons: 
+ 
+ a) it requires convertion to poly, which is numerically unstable 
+ 
+ b) it requires gsl (which is currently not a dependency, and would bring in a whole slew of unrelated stuff) 
+ 
+ c) it finds all roots, even complex ones. We don't want to accidently treat a nearly real root as a real root 
+ 
+From memory gsl poly roots was about 10 times faster than bernstein in the case where all the roots 
+are in [0,1] for polys of order 5. I spent some time working out whether eigenvalue root finding 
+could be done directly in sbasis space, but the maths was too hard for me.  njh 
+ 
+jfbarraud: eigenvalue root finding could be done directly in sbasis space ? 
+ 
+njh: I don't know, I think it should. You would make a matrix whose characteristic polynomial was 
+correct, but do it by putting the sbasis terms in the right spots in the matrix. normal eigenvalue 
+root finding makes a matrix that is a diagonal + a row along the top. This matrix has the property 
+that its characteristic poly is just the poly whose coefficients are along the top row. 
+ 
+Now an sbasis function is a linear combination of the poly coeffs. So it seems to me that you 
+should be able to put the sbasis coeffs directly into a matrix in the right spots so that the 
+characteristic poly is the sbasis. You'll still have problems b) and c). 
+ 
+We might be able to lift an eigenvalue solver and include that directly into 2geom. Eigenvalues 
+also allow you to find intersections of multiple curves but require solving n*m x n*m matrices. 
+ 
+ **/ 
+ 
+#include <cmath> 
+#include <map> 
+ 
+#include "sbasis.h" 
+#include "sbasistobezier.h" 
+#include "solver.h" 
+ 
+using namespace std; 
+ 
+namespace Geom{ 
+ 
+Interval bounds_exact(SBasis const &a) { 
+ Interval result = Interval(a.at0(), a.at1()); 
+ SBasis df = derivative(a); 
+ vector<double>extrema = roots(df); 
+ for (unsigned i=0; i<extrema.size(); i++){ 
+ result.extendTo(a(extrema[i])); 
+ } 
+ return result; 
+} 
+ 
+Interval bounds_fast(const SBasis &sb, int order) { 
+ Interval res; 
+ for(int j = sb.size()1; j>=order; j) { 
+ double a=sb[j][0]; 
+ double b=sb[j][1]; 
+ 
+ double v, t = 0; 
+ v = res[0]; 
+ if (v<0) t = ((ba)/v+1)*0.5; 
+ if (v>=0  t<0  t>1) { 
+ res[0] = std::min(a,b); 
+ }else{ 
+ res[0]=lerp(t, a+v*t, b); 
+ } 
+ 
+ v = res[1]; 
+ if (v>0) t = ((ba)/v+1)*0.5; 
+ if (v<=0  t<0  t>1) { 
+ res[1] = std::max(a,b); 
+ }else{ 
+ res[1]=lerp(t, a+v*t, b); 
+ } 
+ } 
+ if (order>0) res*=pow(.25,order); 
+ return res; 
+} 
+ 
+Interval bounds_local(const SBasis &sb, const Interval &i, int order) { 
+ double t0=i.min(), t1=i.max(), lo=0., hi=0.; 
+ for(int j = sb.size()1; j>=order; j) { 
+ double a=sb[j][0]; 
+ double b=sb[j][1]; 
+ 
+ double t = 0; 
+ if (lo<0) t = ((ba)/lo+1)*0.5; 
+ if (lo>=0  t<t0  t>t1) { 
+ lo = std::min(a*(1t0)+b*t0+lo*t0*(1t0),a*(1t1)+b*t1+lo*t1*(1t1)); 
+ }else{ 
+ lo = lerp(t, a+lo*t, b); 
+ } 
+ 
+ if (hi>0) t = ((ba)/hi+1)*0.5; 
+ if (hi<=0  t<t0  t>t1) { 
+ hi = std::max(a*(1t0)+b*t0+hi*t0*(1t0),a*(1t1)+b*t1+hi*t1*(1t1)); 
+ }else{ 
+ hi = lerp(t, a+hi*t, b); 
+ } 
+ } 
+ Interval res = Interval(lo,hi); 
+ if (order>0) res*=pow(.25,order); 
+ return res; 
+} 
+ 
+// multi_roots  
+// goal: solve f(t)=c for several c at once. 
+/* algo: compute f at both ends of the given segment [a,b]. 
+ compute bounds m<df(t)<M for df on the segment. 
+ let c and C be the levels below and above f(a): 
+ going from f(a) down to c with slope m takes at least time (f(a)c)/m 
+ going from f(a) up to C with slope M takes at least time (Cf(a))/M 
+ From this we conclude there are no roots before a'=a+min((f(a)c)/m,(Cf(a))/M). 
+ Do the same for b: compute some b' such that there are no roots in (b',b]. 
+ if [a',b'] is not empty, repeat the process with [a',(a'+b')/2] and [(a'+b')/2,b']. 
+ unfortunately, extra care is needed about rounding errors, and also to avoid the repetition of roots, 
+ making things tricky and unpleasant... 
+*/ 
+//TODO: Make sure the code is "roundingerrors proof" and take care about repetition of roots! 
+ 
+ 
+static int upper_level(vector<double> const &levels,double x,double tol=0.){ 
+ return(upper_bound(levels.begin(),levels.end(),xtol)levels.begin()); 
+} 
+ 
+static void multi_roots_internal(SBasis const &f, 
+ SBasis const &df, 
+ std::vector<double> const &levels, 
+ std::vector<std::vector<double> > &roots, 
+ double htol, 
+ double vtol, 
+ double a, 
+ double fa, 
+ double b, 
+ double fb){ 
+ 
+ if (f.size()==0){ 
+ int idx; 
+ idx=upper_level(levels,0,vtol); 
+ if (idx<(int)levels.size()&&fabs(levels.at(idx))<=vtol){ 
+ roots[idx].push_back(a); 
+ roots[idx].push_back(b); 
+ } 
+ return; 
+ } 
+////usefull? 
+// if (f.size()==1){ 
+// int idxa=upper_level(levels,fa); 
+// int idxb=upper_level(levels,fb); 
+// if (fa==fb){ 
+// if (fa==levels[idxa]){ 
+// roots[a]=idxa; 
+// roots[b]=idxa; 
+// } 
+// return; 
+// } 
+// int idx_min=std::min(idxa,idxb); 
+// int idx_max=std::max(idxa,idxb); 
+// if (idx_max==levels.size()) idx_max=1; 
+// for(int i=idx_min;i<=idx_max; i++){ 
+// double t=a+(ba)*(levels[i]fa)/(fbfa); 
+// if(a<t&&t<b) roots[t]=i; 
+// } 
+// return; 
+// } 
+ if ((ba)<htol){ 
+ //TODO: use different tol for t and f ? 
+ //TODO: unsigned idx ? (remove int casts when fixed) 
+ int idx=std::min(upper_level(levels,fa,vtol),upper_level(levels,fb,vtol)); 
+ if (idx==(int)levels.size()) idx=1; 
+ double c=levels.at(idx); 
+ if((fac)*(fbc)<=0fabs(fac)<vtolfabs(fbc)<vtol){ 
+ roots[idx].push_back((a+b)/2); 
+ } 
+ return; 
+ } 
+ 
+ int idxa=upper_level(levels,fa,vtol); 
+ int idxb=upper_level(levels,fb,vtol); 
+ 
+ Interval bs = bounds_local(df,Interval(a,b)); 
+ 
+ //first times when a level (higher or lower) can be reached from a or b. 
+ double ta_hi,tb_hi,ta_lo,tb_lo; 
+ ta_hi=ta_lo=b+1;//default values => no root there. 
+ tb_hi=tb_lo=a1;//default values => no root there. 
+ 
+ if (idxa<(int)levels.size() && fabs(falevels.at(idxa))<vtol){//a can be considered a root. 
+ //ta_hi=ta_lo=a; 
+ roots[idxa].push_back(a); 
+ ta_hi=ta_lo=a+htol; 
+ }else{ 
+ if (bs.max()>0 && idxa<(int)levels.size()) 
+ ta_hi=a+(levels.at(idxa )fa)/bs.max(); 
+ if (bs.min()<0 && idxa>0) 
+ ta_lo=a+(levels.at(idxa1)fa)/bs.min(); 
+ } 
+ if (idxb<(int)levels.size() && fabs(fblevels.at(idxb))<vtol){//b can be considered a root. 
+ //tb_hi=tb_lo=b; 
+ roots[idxb].push_back(b); 
+ tb_hi=tb_lo=bhtol; 
+ }else{ 
+ if (bs.min()<0 && idxb<(int)levels.size()) 
+ tb_hi=b+(levels.at(idxb )fb)/bs.min(); 
+ if (bs.max()>0 && idxb>0) 
+ tb_lo=b+(levels.at(idxb1)fb)/bs.max(); 
+ } 
+ 
+ double t0,t1; 
+ t0=std::min(ta_hi,ta_lo); 
+ t1=std::max(tb_hi,tb_lo); 
+ //hum, rounding errors frighten me! so I add this +tol... 
+ if (t0>t1+htol) return;//no root here. 
+ 
+ if (fabs(t1t0)<htol){ 
+ multi_roots_internal(f,df,levels,roots,htol,vtol,t0,f(t0),t1,f(t1)); 
+ }else{ 
+ double t,t_left,t_right,ft,ft_left,ft_right; 
+ t_left =t_right =t =(t0+t1)/2; 
+ ft_left=ft_right=ft=f(t); 
+ int idx=upper_level(levels,ft,vtol); 
+ if (idx<(int)levels.size() && fabs(ftlevels.at(idx))<vtol){//t can be considered a root. 
+ roots[idx].push_back(t); 
+ //we do not want to count it twice (from the left and from the right) 
+ t_left =thtol/2; 
+ t_right=t+htol/2; 
+ ft_left =f(t_left); 
+ ft_right=f(t_right); 
+ } 
+ multi_roots_internal(f,df,levels,roots,htol,vtol,t0 ,f(t0) ,t_left,ft_left); 
+ multi_roots_internal(f,df,levels,roots,htol,vtol,t_right,ft_right,t1 ,f(t1) ); 
+ } 
+} 
+ 
+std::vector<std::vector<double> > multi_roots(SBasis const &f, 
+ std::vector<double> const &levels, 
+ double htol, 
+ double vtol, 
+ double a, 
+ double b){ 
+ 
+ std::vector<std::vector<double> > roots(levels.size(), std::vector<double>()); 
+ 
+ SBasis df=derivative(f); 
+ multi_roots_internal(f,df,levels,roots,htol,vtol,a,f(a),b,f(b)); 
+ 
+ return(roots); 
+} 
+// 
+ 
+#if 0 
+double Laguerre_internal(SBasis const & p, 
+ double x0, 
+ double tol, 
+ bool & quad_root) { 
+ double a = 2*tol; 
+ double xk = x0; 
+ double n = p.size(); 
+ quad_root = false; 
+ while(a > tol) { 
+ //std::cout << "xk = " << xk << std::endl; 
+ Linear b = p.back(); 
+ Linear d(0), f(0); 
+ double err = fabs(b); 
+ double abx = fabs(xk); 
+ for(int j = p.size()2; j >= 0; j) { 
+ f = xk*f + d; 
+ d = xk*d + b; 
+ b = xk*b + p[j]; 
+ err = fabs(b) + abx*err; 
+ } 
+ 
+ err *= 1e7; // magic epsilon for convergence, should be computed from tol 
+ 
+ double px = b; 
+ if(fabs(b) < err) 
+ return xk; 
+ //if(std::norm(px) < tol*tol) 
+ // return xk; 
+ double G = d / px; 
+ double H = G*G  f / px; 
+ 
+ //std::cout << "G = " << G << "H = " << H; 
+ double radicand = (n  1)*(n*HG*G); 
+ //assert(radicand.real() > 0); 
+ if(radicand < 0) 
+ quad_root = true; 
+ //std::cout << "radicand = " << radicand << std::endl; 
+ if(G.real() < 0) // here we try to maximise the denominator avoiding cancellation 
+ a =  std::sqrt(radicand); 
+ else 
+ a = std::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; 
+} 
+#endif 
+ 
+void subdiv_sbasis(SBasis const & s, 
+ std::vector<double> & roots, 
+ double left, double right) { 
+ Interval bs = bounds_fast(s); 
+ if(bs.min() > 0  bs.max() < 0) 
+ return; // no roots here 
+ if(s.tailError(1) < 1e7) { 
+ double t = s[0][0] / (s[0][0]  s[0][1]); 
+ roots.push_back(left*(1t) + t*right); 
+ return; 
+ } 
+ double middle = (left + right)/2; 
+ subdiv_sbasis(compose(s, Linear(0, 0.5)), roots, left, middle); 
+ subdiv_sbasis(compose(s, Linear(0.5, 1.)), roots, middle, right); 
+} 
+ 
+// It is faster to use the bernstein root finder for small degree polynomials (<100?. 
+ 
+std::vector<double> roots(SBasis const & s) { 
+ if(s.size() == 0) return std::vector<double>(); 
+ 
+ return sbasis_to_bezier(s).roots(); 
+} 
+ 
+}; 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/basicintersection.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/basicintersection.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/basicintersection.h (revision 14937) 
@@ 0,0 +1,34 @@ 
+#include "sbasis.h" 
+#include "beziertosbasis.h" 
+#include "sbasistobezier.h" 
+#include "d2.h" 
+ 
+namespace Geom { 
+ 
+std::vector<std::pair<double, double> > 
+find_intersections( D2<SBasis> const & A, 
+ D2<SBasis> const & B); 
+ 
+std::vector<std::pair<double, double> > 
+find_self_intersections(D2<SBasis> const & A); 
+ 
+// Bezier form 
+std::vector<std::pair<double, double> > 
+find_intersections( std::vector<Point> const & A, 
+ std::vector<Point> const & B); 
+ 
+std::vector<std::pair<double, double> > 
+find_self_intersections(std::vector<Point> const & A); 
+ 
+}; 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/geom.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/geom.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/geom.h (revision 14937) 
@@ 0,0 +1,76 @@ 
+/** 
+ * \file geom.h 
+ * \brief Various geometrical calculations 
+ * 
+ * Authors: 
+ * Nathan Hurst <njh@mail.csse.monash.edu.au> 
+ * 
+ * Copyright (C) 19992002 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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 LIB2GEOM_SEEN_GEOM_H 
+#define LIB2GEOM_SEEN_GEOM_H 
+ 
+//TODO: move somewhere else 
+ 
+#include <vector> 
+#include "point.h" 
+ 
+namespace Geom { 
+ 
+enum IntersectorKind { 
+ intersects = 0, 
+ parallel, 
+ coincident, 
+ no_intersection 
+}; 
+ 
+int 
+intersector_ccw(const Geom::Point& p0, const Geom::Point& p1, 
+ const Geom::Point& p2); 
+ 
+/* intersectors */ 
+ 
+IntersectorKind 
+line_intersection(Geom::Point const &n0, double const d0, 
+ Geom::Point const &n1, double const d1, 
+ Geom::Point &result); 
+ 
+IntersectorKind 
+segment_intersect(Geom::Point const &p00, Geom::Point const &p01, 
+ Geom::Point const &p10, Geom::Point const &p11, 
+ Geom::Point &result); 
+ 
+IntersectorKind 
+line_twopoint_intersect(Geom::Point const &p00, Geom::Point const &p01, 
+ Geom::Point const &p10, Geom::Point const &p11, 
+ Geom::Point &result); 
+ 
+int centroid(std::vector<Geom::Point> p, Geom::Point& centroid, double &area); 
+ 
+} 
+ 
+#endif 
Index: Scribus/scribus/third_party/lib2geom/d2sbasis.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/d2sbasis.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/d2sbasis.h (revision 14937) 
@@ 0,0 +1,91 @@ 
+#ifdef _2GEOM_D2 /*This is intentional: we don't actually want anyone to 
+ include this, other than D2.h. If somone else tries, D2 
+ won't be defined. If it is, this will already be included. */ 
+#ifndef __2GEOM_SBASIS_CURVE_H 
+#define __2GEOM_SBASIS_CURVE_H 
+ 
+#include "sbasis.h" 
+#include "sbasis2d.h" 
+#include "piecewise.h" 
+#include "matrix.h" 
+ 
+//TODO: implement intersect 
+ 
+namespace Geom { 
+ 
+inline D2<SBasis> compose(D2<SBasis> const & a, SBasis const & b) { 
+ return D2<SBasis>(compose(a[X], b), compose(a[Y], b)); 
+} 
+ 
+SBasis L2(D2<SBasis> const & a, unsigned k); 
+double L2(D2<double> const & a); 
+ 
+D2<SBasis> multiply(Linear const & a, D2<SBasis> const & b); 
+inline D2<SBasis> operator*(Linear const & a, D2<SBasis> const & b) { return multiply(a, b); } 
+D2<SBasis> multiply(SBasis const & a, D2<SBasis> const & b); 
+inline D2<SBasis> operator*(SBasis const & a, D2<SBasis> const & b) { return multiply(a, b); } 
+D2<SBasis> truncate(D2<SBasis> const & a, unsigned terms); 
+ 
+unsigned sbasis_size(D2<SBasis> const & a); 
+double tail_error(D2<SBasis> const & a, unsigned tail); 
+ 
+//Piecewise<D2<SBasis> > specific decls: 
+ 
+Piecewise<D2<SBasis> > sectionize(D2<Piecewise<SBasis> > const &a); 
+D2<Piecewise<SBasis> > make_cuts_independant(Piecewise<D2<SBasis> > const &a); 
+Piecewise<D2<SBasis> > rot90(Piecewise<D2<SBasis> > const &a); 
+Piecewise<SBasis> dot(Piecewise<D2<SBasis> > const &a, Piecewise<D2<SBasis> > const &b); 
+Piecewise<SBasis> cross(Piecewise<D2<SBasis> > const &a, Piecewise<D2<SBasis> > const &b); 
+ 
+Piecewise<D2<SBasis> > operator*(Piecewise<D2<SBasis> > const &a, Matrix const &m); 
+ 
+Piecewise<D2<SBasis> > force_continuity(Piecewise<D2<SBasis> > const &f, 
+ double tol=0, 
+ bool closed=false); 
+ 
+class CoordIterator 
+: public std::iterator<std::input_iterator_tag, SBasis const> 
+{ 
+public: 
+ CoordIterator(std::vector<D2<SBasis> >::const_iterator const &iter, unsigned d) : impl_(iter), ix_(d) {} 
+ 
+ inline bool operator==(CoordIterator const &other) { return other.impl_ == impl_; } 
+ inline bool operator!=(CoordIterator const &other) { return other.impl_ != impl_; } 
+ 
+ inline SBasis operator*() const { 
+ return (*impl_)[ix_]; 
+ } 
+ 
+ inline CoordIterator &operator++() { 
+ ++impl_; 
+ return *this; 
+ } 
+ inline CoordIterator operator++(int) { 
+ CoordIterator old=*this; 
+ ++(*this); 
+ return old; 
+ } 
+ 
+private: 
+ std::vector<D2<SBasis> >::const_iterator impl_; 
+ unsigned ix_; 
+}; 
+ 
+inline CoordIterator iterateCoord(Piecewise<D2<SBasis> > const &a, unsigned d) { 
+ return CoordIterator(a.segs.begin(), d); 
+} 
+ 
+//bounds specializations with order 
+inline Rect bounds_fast(D2<SBasis> const & s, unsigned order=0) { 
+ return Rect(bounds_fast(s[X], order), 
+ bounds_fast(s[Y], order)); 
+} 
+inline Rect bounds_local(D2<SBasis> const & s, Interval i, unsigned order=0) { 
+ return Rect(bounds_local(s[X], i, order), 
+ bounds_local(s[Y], i, order)); 
+} 
+ 
+} 
+ 
+#endif 
+#endif 
Index: Scribus/scribus/third_party/lib2geom/svgpath.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/svgpath.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/svgpath.h (revision 14937) 
@@ 0,0 +1,127 @@ 
+/* 
+ * callback interface for SVG path data 
+ * 
+ * Copyright 2007 MenTaLguY <mental@rydia.net> 
+ * 
+ * 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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_SVG_PATH_H 
+#define SEEN_SVG_PATH_H 
+ 
+#include "path.h" 
+#include <iterator> 
+ 
+namespace Geom { 
+ 
+class SVGPathSink { 
+public: 
+ virtual void moveTo(Point p) = 0; 
+ virtual void lineTo(Point p) = 0; 
+ virtual void curveTo(Point c0, Point c1, Point p) = 0; 
+ virtual void quadTo(Point c, Point p) = 0; 
+ virtual void arcTo(double rx, double ry, double angle, 
+ bool large_arc, bool sweep, Point p) = 0; 
+ virtual void closePath() = 0; 
+ virtual void finish() = 0; 
+ virtual ~SVGPathSink() {} 
+}; 
+ 
+void output_svg_path(Path &path, SVGPathSink &sink); 
+ 
+template <typename OutputIterator> 
+class SVGPathGenerator : public SVGPathSink { 
+public: 
+ explicit SVGPathGenerator(OutputIterator out) 
+ : _in_path(false), _out(out) {} 
+ 
+ void moveTo(Point p) { 
+ finish(); 
+ _path.start(p); 
+ _in_path = true; 
+ } 
+//TODO: what if _in_path = false? 
+ void lineTo(Point p) { 
+ _path.template appendNew<LineSegment>(p); 
+ } 
+ 
+ void quadTo(Point c, Point p) { 
+ _path.template appendNew<QuadraticBezier>(c, p); 
+ } 
+ 
+ void curveTo(Point c0, Point c1, Point p) { 
+ _path.template appendNew<CubicBezier>(c0, c1, p); 
+ } 
+ 
+ void arcTo(double rx, double ry, double angle, 
+ bool large_arc, bool sweep, Point p) 
+ { 
+ _path.template appendNew<SVGEllipticalArc>(rx, ry, angle, 
+ large_arc, sweep, p); 
+ } 
+ 
+ void closePath() { 
+ _path.close(); 
+ finish(); 
+ } 
+ 
+ void finish() { 
+ if (_in_path) { 
+ _in_path = false; 
+ *_out = _path; 
+ _path.clear(); 
+ _path.close(false); 
+ } 
+ } 
+ 
+protected: 
+ bool _in_path; 
+ OutputIterator _out; 
+ Path _path; 
+}; 
+ 
+typedef std::back_insert_iterator<std::vector<Path> > iter; 
+ 
+class PathBuilder : public SVGPathGenerator<iter> { 
+private: 
+ std::vector<Path> _pathset; 
+public: 
+ PathBuilder() : SVGPathGenerator<iter>(iter(_pathset)) {} 
+ std::vector<Path> const &peek() const {return _pathset;} 
+}; 
+ 
+} 
+ 
+#endif 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/transforms.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/transforms.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/transforms.cpp (revision 14937) 
@@ 0,0 +1,48 @@ 
+#include "transforms.h" 
+ 
+namespace Geom { 
+ 
+Matrix operator*(Translate const &t, Scale const &s) { 
+ Matrix ret(s); 
+ ret[4] = t[X] * s[X]; 
+ ret[5] = t[Y] * s[Y]; 
+ return ret; 
+} 
+ 
+Matrix operator*(Translate const &t, Rotate const &r) { 
+ Matrix ret(r); 
+ ret.setTranslation(t.vec * ret); 
+ return ret; 
+} 
+ 
+Matrix operator*(Scale const &s, Translate const &t) { 
+ return Matrix(s[0], 0, 
+ 0 , s[1], 
+ t[0], t[1]); 
+} 
+ 
+Matrix operator*(Scale const &s, Matrix const &m) { 
+ Matrix ret(m); 
+ ret[0] *= s[X]; 
+ ret[1] *= s[X]; 
+ ret[2] *= s[Y]; 
+ ret[3] *= s[Y]; 
+ return ret; 
+} 
+ 
+Matrix operator*(Matrix const &m, Translate const &t) { 
+ Matrix ret(m); 
+ ret[4] += t[X]; 
+ ret[5] += t[Y]; 
+ return ret; 
+} 
+ 
+Matrix operator*(Matrix const &m, Scale const &s) { 
+ Matrix ret(m); 
+ ret[0] *= s[X]; ret[1] *= s[Y]; 
+ ret[2] *= s[X]; ret[3] *= s[Y]; 
+ ret[4] *= s[X]; ret[5] *= s[Y]; 
+ return ret; 
+} 
+ 
+} 
Index: Scribus/scribus/third_party/lib2geom/sbasisgeometric.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/sbasisgeometric.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/sbasisgeometric.cpp (revision 14937) 
@@ 0,0 +1,378 @@ 
+#include "sbasisgeometric.h" 
+#include "sbasis.h" 
+#include "sbasismath.h" 
+//#include "solver.h" 
+#include "sbasisgeometric.h" 
+ 
+/** Geometric operators on D2<SBasis> (1D>2D). 
+ * Copyright 2007 JF Barraud 
+ * Copyright 2007 N Hurst 
+ * 
+ * The functions defined in this header related to 2d geometric operations such as arc length, 
+ * unit_vector, curvature, and centroid. Most are built on top of unit_vector, which takes an 
+ * arbitrary D2 and returns a D2 with unit length with the same direction. 
+ * 
+ * Todo/think about: 
+ * arclength D2 > sbasis (giving arclength function) 
+ * does uniform_speed return natural parameterisation? 
+ * integrate sb2d code from normalbundle 
+ * angle(md<2>) > sbasis (gives angle from vector  discontinuous?) 
+ * osculating circle center? 
+ * 
+ **/ 
+ 
+//namespace Geom{ 
+using namespace Geom; 
+using namespace std; 
+ 
+//Some utils first. 
+//TODO: remove this!! 
+static vector<double> 
+vect_intersect(vector<double> const &a, vector<double> const &b, double tol=0.){ 
+ vector<double> inter; 
+ unsigned i=0,j=0; 
+ while ( i<a.size() && j<b.size() ){ 
+ if (fabs(a[i]b[j])<tol){ 
+ inter.push_back(a[i]); 
+ i+=1; 
+ j+=1; 
+ }else if (a[i]<b[j]){ 
+ i+=1; 
+ }else if (a[i]>b[j]){ 
+ j+=1; 
+ } 
+ } 
+ return inter; 
+} 
+ 
+static SBasis divide_by_sk(SBasis const &a, int k) { 
+ assert( k<(int)a.size()); 
+ if(k < 0) return shift(a,k); 
+ SBasis c; 
+ c.insert(c.begin(), a.begin()+k, a.end()); 
+ return c; 
+} 
+ 
+static SBasis divide_by_t0k(SBasis const &a, int k) { 
+ if(k < 0) { 
+ SBasis c = Linear(0,1); 
+ for (int i=2; i<=k; i++){ 
+ c*=c; 
+ } 
+ c*=a; 
+ return(c); 
+ }else{ 
+ SBasis c = Linear(1,0); 
+ for (int i=2; i<=k; i++){ 
+ c*=c; 
+ } 
+ c*=a; 
+ return(divide_by_sk(c,k)); 
+ } 
+} 
+ 
+static SBasis divide_by_t1k(SBasis const &a, int k) { 
+ if(k < 0) { 
+ SBasis c = Linear(1,0); 
+ for (int i=2; i<=k; i++){ 
+ c*=c; 
+ } 
+ c*=a; 
+ return(c); 
+ }else{ 
+ SBasis c = Linear(0,1); 
+ for (int i=2; i<=k; i++){ 
+ c*=c; 
+ } 
+ c*=a; 
+ return(divide_by_sk(c,k)); 
+ } 
+} 
+ 
+static D2<SBasis> RescaleForNonVanishingEnds(D2<SBasis> const &MM, double ZERO=1.e4){ 
+ D2<SBasis> M = MM; 
+ //TODO: divide by all the s at once!!! 
+ while (fabs(M[0].at0())<ZERO && 
+ fabs(M[1].at0())<ZERO && 
+ fabs(M[0].at1())<ZERO && 
+ fabs(M[1].at1())<ZERO){ 
+ M[0] = divide_by_sk(M[0],1); 
+ M[1] = divide_by_sk(M[1],1); 
+ } 
+ while (fabs(M[0].at0())<ZERO && fabs(M[1].at0())<ZERO){ 
+ M[0] = divide_by_t0k(M[0],1); 
+ M[1] = divide_by_t0k(M[1],1); 
+ } 
+ while (fabs(M[0].at1())<ZERO && fabs(M[1].at1())<ZERO){ 
+ M[0] = divide_by_t1k(M[0],1); 
+ M[1] = divide_by_t1k(M[1],1); 
+ } 
+ return M; 
+} 
+ 
+//================================================================= 
+//TODO: what's this for?!?! 
+Piecewise<D2<SBasis> > 
+Geom::cutAtRoots(Piecewise<D2<SBasis> > const &M, double ZERO){ 
+ vector<double> rts; 
+ for (unsigned i=0; i<M.size(); i++){ 
+ vector<double> seg_rts = roots((M.segs[i])[0]); 
+ seg_rts = vect_intersect(seg_rts, roots((M.segs[i])[1]), ZERO); 
+ Linear mapToDom = Linear(M.cuts[i],M.cuts[i+1]); 
+ for (unsigned r=0; r<seg_rts.size(); r++){ 
+ seg_rts[r]= mapToDom(seg_rts[r]); 
+ } 
+ rts.insert(rts.end(),seg_rts.begin(),seg_rts.end()); 
+ } 
+ return partition(M,rts); 
+} 
+ 
+Piecewise<SBasis> 
+Geom::atan2(Piecewise<D2<SBasis> > const &vect, double tol, unsigned order){ 
+ Piecewise<SBasis> result; 
+ Piecewise<D2<SBasis> > v = cutAtRoots(vect); 
+ result.cuts.push_back(v.cuts.front()); 
+ for (unsigned i=0; i<v.size(); i++){ 
+ 
+ D2<SBasis> vi = RescaleForNonVanishingEnds(v.segs[i]); 
+ SBasis x=vi[0], y=vi[1]; 
+ Piecewise<SBasis> angle; 
+ angle = divide (x*derivative(y)y*derivative(x), x*x+y*y, tol, order); 
+ 
+ //TODO: I don't understand this  sign. 
+ angle = integral(angle); 
+ Point vi0 = vi.at0(); 
+ angle += std::atan2(vi0[1],vi0[0])  angle[0].at0(); 
+ //TODO: deal with 2*pi jumps form one seg to the other... 
+ //TODO: not exact at t=1 because of the integral. 
+ //TODO: force continuity? 
+ 
+ angle.setDomain(Interval(v.cuts[i],v.cuts[i+1])); 
+ result.concat(angle); 
+ } 
+ return result; 
+} 
+Piecewise<SBasis> 
+Geom::atan2(D2<SBasis> const &vect, double tol, unsigned order){ 
+ return atan2(Piecewise<D2<SBasis> >(vect),tol,order); 
+} 
+ 
+//unitVector(x,y) is computed as (b,a) where a and b are solutions of: 
+// ax+by=0 (eqn1) and a^2+b^2=1 (eqn2) 
+Piecewise<D2<SBasis> > 
+Geom::unitVector(D2<SBasis> const &V_in, double tol, unsigned order){ 
+ D2<SBasis> V = RescaleForNonVanishingEnds(V_in); 
+ if (V[0].empty() && V[1].empty()) 
+ return Piecewise<D2<SBasis> >(D2<SBasis>(Linear(1),SBasis())); 
+ SBasis x = V[0], y = V[1], a, b; 
+ SBasis r_eqn1, r_eqn2; 
+ 
+ Point v0 = unit_vector(V.at0()); 
+ Point v1 = unit_vector(V.at1()); 
+ a.push_back(Linear(v0[1],v1[1])); 
+ b.push_back(Linear( v0[0], v1[0])); 
+ 
+ r_eqn1 = (a*x+b*y); 
+ r_eqn2 = Linear(1.)(a*a+b*b); 
+ 
+ for (unsigned k=1; k<=order; k++){ 
+ double r0 = (k<r_eqn1.size())? r_eqn1.at(k).at0() : 0; 
+ double r1 = (k<r_eqn1.size())? r_eqn1.at(k).at1() : 0; 
+ double rr0 = (k<r_eqn2.size())? r_eqn2.at(k).at0() : 0; 
+ double rr1 = (k<r_eqn2.size())? r_eqn2.at(k).at1() : 0; 
+ double a0,a1,b0,b1;// coeffs in a[k] and b[k] 
+ 
+ //the equations to solve at this point are: 
+ // a0*x(0)+b0*y(0)=r0 & 2*a0*a(0)+2*b0*b(0)=rr0 
+ //and 
+ // a1*x(1)+b1*y(1)=r1 & 2*a1*a(1)+2*b1*b(1)=rr1 
+ a0 = r0/dot(v0,V(0))*v0[0]rr0/2*v0[1]; 
+ b0 = r0/dot(v0,V(0))*v0[1]+rr0/2*v0[0]; 
+ a1 = r1/dot(v1,V(1))*v1[0]rr1/2*v1[1]; 
+ b1 = r1/dot(v1,V(1))*v1[1]+rr1/2*v1[0]; 
+ 
+ a.push_back(Linear(a0,a1)); 
+ b.push_back(Linear(b0,b1)); 
+ //TODO: use "incremental" rather than explicit formulas. 
+ r_eqn1 = (a*x+b*y); 
+ r_eqn2 = Linear(1)(a*a+b*b); 
+ } 
+ 
+ //our candidate is: 
+ D2<SBasis> unitV; 
+ unitV[0] = b; 
+ unitV[1] = a; 
+ 
+ //is it good? 
+ double rel_tol = std::max(1.,std::max(V_in[0].tailError(0),V_in[1].tailError(0)))*tol; 
+ 
+ if (r_eqn1.tailError(order)>rel_tol  r_eqn2.tailError(order)>tol){ 
+ //if not: subdivide and concat results. 
+ Piecewise<D2<SBasis> > unitV0, unitV1; 
+ unitV0 = unitVector(compose(V,Linear(0,.5)),tol,order); 
+ unitV1 = unitVector(compose(V,Linear(.5,1)),tol,order); 
+ unitV0.setDomain(Interval(0.,.5)); 
+ unitV1.setDomain(Interval(.5,1.)); 
+ unitV0.concat(unitV1); 
+ return(unitV0); 
+ }else{ 
+ //if yes: return it as pw. 
+ Piecewise<D2<SBasis> > result; 
+ result=(Piecewise<D2<SBasis> >)unitV; 
+ return result; 
+ } 
+} 
+ 
+Piecewise<D2<SBasis> > 
+Geom::unitVector(Piecewise<D2<SBasis> > const &V, double tol, unsigned order){ 
+ Piecewise<D2<SBasis> > result; 
+ Piecewise<D2<SBasis> > VV = cutAtRoots(V); 
+ result.cuts.push_back(VV.cuts.front()); 
+ for (unsigned i=0; i<VV.size(); i++){ 
+ Piecewise<D2<SBasis> > unit_seg; 
+ unit_seg = unitVector(VV.segs[i],tol, order); 
+ unit_seg.setDomain(Interval(VV.cuts[i],VV.cuts[i+1])); 
+ result.concat(unit_seg); 
+ } 
+ return result; 
+} 
+ 
+Piecewise<SBasis> 
+Geom::arcLengthSb(Piecewise<D2<SBasis> > const &M, double tol){ 
+ Piecewise<D2<SBasis> > dM = derivative(M); 
+ Piecewise<SBasis> dMlength = sqrt(dot(dM,dM),tol,3); 
+ Piecewise<SBasis> length = integral(dMlength); 
+ length=length.segs.front().at0(); 
+ return length; 
+} 
+Piecewise<SBasis> 
+Geom::arcLengthSb(D2<SBasis> const &M, double tol){ 
+ return arcLengthSb(Piecewise<D2<SBasis> >(M), tol); 
+} 
+ 
+double 
+Geom::length(D2<SBasis> const &M, 
+ double tol){ 
+ Piecewise<SBasis> length = arcLengthSb(M, tol); 
+ return length.segs.back().at1(); 
+} 
+double 
+Geom::length(Piecewise<D2<SBasis> > const &M, 
+ double tol){ 
+ Piecewise<SBasis> length = arcLengthSb(M, tol); 
+ return length.segs.back().at1(); 
+} 
+ 
+ 
+// incomplete. 
+Piecewise<SBasis> 
+Geom::curvature(D2<SBasis> const &M, double tol) { 
+ D2<SBasis> dM=derivative(M); 
+ Piecewise<SBasis> result; 
+ Piecewise<D2<SBasis> > unitv = unitVector(dM,tol); 
+ Piecewise<SBasis> dMlength = dot(Piecewise<D2<SBasis> >(dM),unitv); 
+ Piecewise<SBasis> k = cross(derivative(unitv),unitv); 
+ k = divide(k,dMlength,tol,3); 
+ return(k); 
+} 
+ 
+Piecewise<SBasis> 
+Geom::curvature(Piecewise<D2<SBasis> > const &V, double tol){ 
+ Piecewise<SBasis> result; 
+ Piecewise<D2<SBasis> > VV = cutAtRoots(V); 
+ result.cuts.push_back(VV.cuts.front()); 
+ for (unsigned i=0; i<VV.size(); i++){ 
+ Piecewise<SBasis> curv_seg; 
+ curv_seg = curvature(VV.segs[i],tol); 
+ curv_seg.setDomain(Interval(VV.cuts[i],VV.cuts[i+1])); 
+ result.concat(curv_seg); 
+ } 
+ return result; 
+} 
+ 
+//================================================================= 
+ 
+Piecewise<D2<SBasis> > 
+Geom::arc_length_parametrization(D2<SBasis> const &M, 
+ unsigned order, 
+ double tol){ 
+ Piecewise<D2<SBasis> > u; 
+ u.push_cut(0); 
+ 
+ Piecewise<SBasis> s = arcLengthSb(Piecewise<D2<SBasis> >(M),tol); 
+ for (unsigned i=0; i < s.size();i++){ 
+ double t0=s.cuts[i],t1=s.cuts[i+1]; 
+ D2<SBasis> sub_M = compose(M,Linear(t0,t1)); 
+ D2<SBasis> sub_u; 
+ for (unsigned dim=0;dim<2;dim++){ 
+ SBasis sub_s = s.segs[i]; 
+ sub_s=sub_s.at0(); 
+ sub_s/=sub_s.at1(); 
+ sub_u[dim]=compose_inverse(sub_M[dim],sub_s, order, tol); 
+ } 
+ u.push(sub_u,s(t1)); 
+ } 
+ return u; 
+} 
+ 
+Piecewise<D2<SBasis> > 
+Geom::arc_length_parametrization(Piecewise<D2<SBasis> > const &M, 
+ unsigned order, 
+ double tol){ 
+ Piecewise<D2<SBasis> > result; 
+ for (unsigned i=0; i<M.size(); i++ ){ 
+ Piecewise<D2<SBasis> > uniform_seg=arc_length_parametrization(M[i],order,tol); 
+ result.concat(uniform_seg); 
+ } 
+ return(result); 
+} 
+ 
+/** centroid using sbasis integration. 
+ * This approach uses green's theorem to compute the area and centroid using integrals. For curved 
+ * shapes this is much faster than converting to polyline. 
+ 
+ * Returned values: 
+ 0 for normal execution; 
+ 2 if area is zero, meaning centroid is meaningless. 
+ 
+ * Copyright Nathan Hurst 2006 
+ */ 
+ 
+unsigned Geom::centroid(Piecewise<D2<SBasis> > const &p, Point& centroid, double &area) { 
+ Point centroid_tmp(0,0); 
+ double atmp = 0; 
+ for(unsigned i = 0; i < p.size(); i++) { 
+ SBasis curl = dot(p[i], rot90(derivative(p[i]))); 
+ SBasis A = integral(curl); 
+ D2<SBasis> C = integral(multiply(curl, p[i])); 
+ atmp += A.at1()  A.at0(); 
+ centroid_tmp += C.at1() C.at0(); // first moment. 
+ } 
+// join ends 
+ centroid_tmp *= 2; 
+ Point final = p[p.size()1].at1(), initial = p[0].at0(); 
+ const double ai = cross(final, initial); 
+ atmp += ai; 
+ centroid_tmp += (final + initial)*ai; // first moment. 
+ 
+ area = atmp / 2; 
+ if (atmp != 0) { 
+ centroid = centroid_tmp / (3 * atmp); 
+ return 0; 
+ } 
+ return 2; 
+} 
+ 
+//}; // namespace 
+ 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/circlecircle.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/circlecircle.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/circlecircle.cpp (revision 14937) 
@@ 0,0 +1,131 @@ 
+/* circle_circle_intersection() * 
+ * Determine the points where 2 circles in a common plane intersect. 
+ * 
+ * int circle_circle_intersection( 
+ * // center and radius of 1st circle 
+ * double x0, double y0, double r0, 
+ * // center and radius of 2nd circle 
+ * double x1, double y1, double r1, 
+ * // 1st intersection point 
+ * double *xi, double *yi, 
+ * // 2nd intersection point 
+ * double *xi_prime, double *yi_prime) 
+ * 
+ * This is a public domain work. 3/26/2005 Tim Voght 
+ * Ported to lib2geom, 2006 Nathan Hurst 
+ * 
+ * Copyright 2006 Nathan Hurst <njh@mail.csse.monash.edu.au> 
+ * 
+ * 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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 <stdio.h> 
+#include <math.h> 
+#include "point.h" 
+ 
+namespace Geom{ 
+ 
+int circle_circle_intersection(Point X0, double r0, 
+ Point X1, double r1, 
+ Point & p0, Point & p1) 
+{ 
+ /* dx and dy are the vertical and horizontal distances between 
+ * the circle centers. 
+ */ 
+ Point D = X1  X0; 
+ 
+ /* Determine the straightline distance between the centers. */ 
+ double d = L2(D); 
+ 
+ /* Check for solvability. */ 
+ if (d > (r0 + r1)) 
+ { 
+ /* no solution. circles do not intersect. */ 
+ return 0; 
+ } 
+ if (d <= fabs(r0  r1)) 
+ { 
+ /* no solution. one circle is contained in the other */ 
+ return 1; 
+ } 
+ 
+ /* 'point 2' is the point where the line through the circle 
+ * intersection points crosses the line between the circle 
+ * centers. 
+ */ 
+ 
+ /* Determine the distance from point 0 to point 2. */ 
+ double a = ((r0*r0)  (r1*r1) + (d*d)) / (2.0 * d) ; 
+ 
+ /* Determine the coordinates of point 2. */ 
+ Point p2 = X0 + D * (a/d); 
+ 
+ /* Determine the distance from point 2 to either of the 
+ * intersection points. 
+ */ 
+ double h = sqrt((r0*r0)  (a*a)); 
+ 
+ /* Now determine the offsets of the intersection points from 
+ * point 2. 
+ */ 
+ Point r = (h/d)*rot90(D); 
+ 
+ /* Determine the absolute intersection points. */ 
+ p0 = p2 + r; 
+ p1 = p2  r; 
+ 
+ return 2; 
+} 
+ 
+}; 
+ 
+ 
+#ifdef TEST 
+ 
+void run_test(double x0, double y0, double r0, 
+ double x1, double y1, double r1) 
+{ 
+ double x3, y3, x3_prime, y3_prime; 
+ 
+ printf("x0=%F, y0=%F, r0=%F, x1=%F, y1=%F, r1=%F :\n", 
+ x0, y0, r0, x1, y1, r1); 
+ Geom::Point p0, p1; 
+ Geom::circle_circle_intersection(Geom::Point(x0, y0), r0, 
+ Geom::Point(x1, y1), r1, 
+ p0, p1); 
+ printf(" x3=%F, y3=%F, x3_prime=%F, y3_prime=%F\n", 
+ p0[0], p0[1], p1[0], p1[1]); 
+} 
+ 
+int main(void) 
+{ 
+ /* Add more! */ 
+ run_test(1.0, 1.0, 1.5, 1.0, 1.0, 2.0); 
+ run_test(1.0, 1.0, 1.5, 1.0, 1.0, 2.0); 
+ run_test(1.0, 1.0, 1.5, 1.0, 1.0, 2.0); 
+ run_test(1.0, 1.0, 1.5, 1.0, 1.0, 2.0); 
+ exit(0); 
+} 
+#endif 
+ 
Index: Scribus/scribus/third_party/lib2geom/matrix.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/matrix.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/matrix.cpp (revision 14937) 
@@ 0,0 +1,253 @@ 
+#define __Geom_MATRIX_C__ 
+ 
+/** \file 
+ * Various matrix routines. Currently includes some Geom::Rotate etc. routines too. 
+ */ 
+ 
+/* 
+ * Authors: 
+ * Lauris Kaplinski <lauris@kaplinski.com> 
+ * Michael G. Sloan <mgsloan@gmail.com> 
+ * 
+ * This code is in public domain 
+ */ 
+ 
+#include "utils.h" 
+#include "matrix.h" 
+#include "point.h" 
+ 
+namespace Geom { 
+ 
+/** Creates a Matrix given an axis and origin point. 
+ * The axis is represented as two vectors, which represent skew, rotation, and scaling in two dimensions. 
+ * from_basis(Point(1, 0), Point(0, 1), Point(0, 0)) would return the identity matrix. 
+ 
+ \param x_basis the vector for the xaxis. 
+ \param y_basis the vector for the yaxis. 
+ \param offset the translation applied by the matrix. 
+ \return The new Matrix. 
+ */ 
+//NOTE: Inkscape's version is broken, so when including this version, you'll have to search for code with this func 
+//TODO: move to Matrix::from_basis 
+Matrix from_basis(Point const x_basis, Point const y_basis, Point const offset) { 
+ return Matrix(x_basis[X], x_basis[Y], 
+ y_basis[X], y_basis[Y], 
+ offset [X], offset [Y]); 
+} 
+ 
+Point Matrix::xAxis() const { 
+ return Point(_c[0], _c[1]); 
+} 
+ 
+Point Matrix::yAxis() const { 
+ return Point(_c[2], _c[3]); 
+} 
+ 
+/** Gets the translation imparted by the Matrix. 
+ */ 
+Point Matrix::translation() const { 
+ return Point(_c[4], _c[5]); 
+} 
+ 
+void Matrix::setXAxis(Point const &vec) { 
+ for(int i = 0; i < 2; i++) 
+ _c[i] = vec[i]; 
+} 
+ 
+void Matrix::setYAxis(Point const &vec) { 
+ for(int i = 0; i < 2; i++) 
+ _c[i + 2] = vec[i]; 
+} 
+ 
+/** Sets the translation imparted by the Matrix. 
+ */ 
+void Matrix::setTranslation(Point const &loc) { 
+ for(int i = 0; i < 2; i++) 
+ _c[i + 4] = loc[i]; 
+} 
+ 
+/** Calculates the amount of xscaling imparted by the Matrix. This is the scaling applied to 
+ * the original xaxis region. It is \emph{not} the overall xscaling of the transformation. 
+ * Equivalent to L2(m.xAxis()) 
+ */ 
+double Matrix::expansionX() const { 
+ return sqrt(_c[0] * _c[0] + _c[1] * _c[1]); 
+} 
+ 
+/** Calculates the amount of yscaling imparted by the Matrix. This is the scaling applied before 
+ * the other transformations. It is \emph{not} the overall yscaling of the transformation. 
+ * Equivalent to L2(m.yAxis()) 
+ */ 
+double Matrix::expansionY() const { 
+ return sqrt(_c[2] * _c[2] + _c[3] * _c[3]); 
+} 
+ 
+void Matrix::setExpansionX(double val) { 
+ double exp_x = expansionX(); 
+ 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; 
+ } 
+} 
+ 
+void Matrix::setExpansionY(double val) { 
+ double exp_y = expansionY(); 
+ 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; 
+ } 
+} 
+ 
+/** Sets this matrix to be the Identity Matrix. */ 
+void Matrix::setIdentity() { 
+ _c[0] = 1.0; _c[1] = 0.0; 
+ _c[2] = 0.0; _c[3] = 1.0; 
+ _c[4] = 0.0; _c[5] = 0.0; 
+} 
+ 
+//TODO: use eps 
+ 
+bool Matrix::isIdentity(Coord const eps) const { 
+ 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?" 
+ \param eps an epsilon value defaulting to EPSILON 
+ \return A bool representing yes/no. 
+ */ 
+bool Matrix::isTranslation(Coord const eps) const { 
+ 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?" 
+ \param eps an epsilon value defaulting to EPSILON 
+ \return A bool representing yes/no. 
+ */ 
+bool Matrix::isScale(Coord const eps) const { 
+ 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?" 
+ \param eps an epsilon value defaulting to EPSILON 
+ \return A bool representing yes/no. 
+ */ 
+bool Matrix::isUniformScale(Coord const eps) const { 
+ 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?" 
+ \param eps an epsilon value defaulting to EPSILON 
+ \return A bool representing yes/no. 
+ */ 
+bool Matrix::isRotation(Coord const eps) const { 
+ 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 are_near(_c[0], _c[3]) && are_near(_c[1], 0) && are_near(_c[2], 0); 
+} 
+ 
+bool Matrix::flips() const { 
+ return cross(xAxis(), yAxis()) > 0; 
+} 
+ 
+/** Returns the Scale/Rotate/skew part of the matrix without the translation part. */ 
+Matrix Matrix::without_translation() const { 
+ return Matrix(_c[0], _c[1], _c[2], _c[3], 0, 0); 
+} 
+ 
+/** Attempts to calculate the inverse of a matrix. 
+ * This is a Matrix such that m * m.inverse() is very near (hopefully < epsilon difference) the identity Matrix. 
+ * \textbf{The Identity Matrix is returned if the matrix has no inverse.} 
+ \return The inverse of the Matrix if defined, otherwise the Identity Matrix. 
+ */ 
+Matrix Matrix::inverse() const { 
+ Matrix d; 
+ 
+ Geom::Coord const determ = det(); 
+ if (!are_near(determ, 0.0)) { 
+ Geom::Coord const ideterm = 1.0 / determ; 
+ 
+ d._c[0] = _c[3] * ideterm; 
+ d._c[1] = _c[1] * ideterm; 
+ d._c[2] = _c[2] * ideterm; 
+ d._c[3] = _c[0] * ideterm; 
+ d._c[4] = _c[4] * d._c[0]  _c[5] * d._c[2]; 
+ d._c[5] = _c[4] * d._c[1]  _c[5] * d._c[3]; 
+ } else { 
+ d.setIdentity(); 
+ } 
+ 
+ return d; 
+} 
+ 
+/** Calculates the determinant of a Matrix. */ 
+Geom::Coord Matrix::det() const { 
+ return _c[0] * _c[3]  _c[1] * _c[2]; 
+} 
+ 
+/** Calculates the scalar of the descriminant of the Matrix. 
+ * This is simply the absolute value of the determinant. 
+ */ 
+Geom::Coord Matrix::descrim2() const { 
+ return fabs(det()); 
+} 
+ 
+/** Calculates the descriminant of the Matrix. */ 
+Geom::Coord Matrix::descrim() const { 
+ return sqrt(descrim2()); 
+} 
+ 
+Matrix operator*(Matrix const &m0, Matrix const &m1) { 
+ Matrix ret; 
+ for(int a = 0; a < 5; a += 2) { 
+ for(int b = 0; b < 2; b++) { 
+ ret[a + b] = m0[a] * m1[b] + m0[a + 1] * m1[b + 2]; 
+ } 
+ } 
+ ret[4] += m1[4]; 
+ ret[5] += m1[5]; 
+ return ret; 
+} 
+ 
+//TODO: What's this!?! 
+Matrix elliptic_quadratic_form(Matrix const &m) { 
+ double const od = m[0] * m[1] + m[2] * m[3]; 
+ return Matrix(m[0]*m[0] + m[1]*m[1], od, 
+ od, m[2]*m[2] + m[3]*m[3], 
+ 0, 0); 
+} 
+ 
+Eigen::Eigen(Matrix const &m) { 
+ double const B = m[0]  m[3]; 
+ double const C = m[0]*m[3]  m[1]*m[2]; 
+ double const center = B/2.0; 
+ double const delta = sqrt(B*B4*C)/2.0; 
+ values[0] = center + delta; values[1] = center  delta; 
+ for (int i = 0; i < 2; i++) { 
+ vectors[i] = unit_vector(rot90(Point(m[0]values[i], m[1]))); 
+ } 
+} 
+ 
+} //namespace Geom 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/sbasispoly.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/sbasispoly.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/sbasispoly.h (revision 14937) 
@@ 0,0 +1,29 @@ 
+#ifndef _SBASIS_TO_POLY 
+#define _SBASIS_TO_POLY 
+ 
+#include "poly.h" 
+#include "sbasis.h" 
+ 
+/*** Conversion between SBasis and Poly. Not recommended for general 
+ * use due to instability. 
+ */ 
+ 
+namespace Geom{ 
+ 
+SBasis poly_to_sbasis(Poly const & p); 
+Poly sbasis_to_poly(SBasis const & s); 
+ 
+}; 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
+ 
+#endif 
Index: Scribus/scribus/third_party/lib2geom/coord.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/coord.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/coord.h (revision 14937) 
@@ 0,0 +1,66 @@ 
+/* 
+ * coord.h 
+ * 
+ * Copyright 2006 Nathan Hurst <njh@mail.csse.monash.edu.au> 
+ * 
+ * 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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_COORD_H 
+#define SEEN_Geom_COORD_H 
+ 
+#include <cmath> 
+ 
+namespace Geom { 
+ 
+/** 
+ * A "real" type with sufficient precision for coordinates. 
+ * 
+ * You may safely assume that double (or even float) provides enough precision for storing 
+ * oncanvas points, and hence that double provides enough precision for dot products of 
+ * differences of oncanvas points. 
+ */ 
+typedef double Coord; 
+ 
+const Coord EPSILON = 1e5; //1e18; 
+ 
+//IMPL: NearConcept 
+inline bool are_near(Coord a, Coord b, double eps=EPSILON) { return fabs(ab) <= eps; } 
+ 
+} /* namespace Geom */ 
+ 
+ 
+#endif /* !SEEN_Geom_COORD_H */ 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/circulator.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/circulator.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/circulator.h (revision 14937) 
@@ 0,0 +1,149 @@ 
+/* 
+ * ciculator.h 
+ * 
+ * Copyright 2006 MenTaLguY <mental@rydia.net> 
+ * 
+ * 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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_Circulator_H 
+#define SEEN_Circulator_H 
+ 
+#include <iterator> 
+ 
+namespace Geom { 
+ 
+template <typename Iterator> 
+class Circulator { 
+public: 
+ typedef std::random_access_iterator_tag iterator_category; 
+ typedef typename std::iterator_traits<Iterator>::value_type value_type; 
+ typedef typename std::iterator_traits<Iterator>::difference_type difference_type; 
+ typedef typename std::iterator_traits<Iterator>::pointer pointer; 
+ typedef typename std::iterator_traits<Iterator>::reference reference; 
+ 
+ Circulator(Iterator const &first, 
+ Iterator const &last, 
+ Iterator const &pos) 
+ : _first(first), _last(last), _pos(pos) 
+ { 
+ match_random_access(iterator_category(first)); 
+ } 
+ 
+ reference operator*() const { 
+ return *_pos; 
+ } 
+ pointer operator>() const { 
+ return &*_pos; 
+ } 
+ 
+ Circulator &operator++() { 
+ if ( _first == _last ) return *this; 
+ ++_pos; 
+ if ( _pos == _last ) _pos = _first; 
+ return *this; 
+ } 
+ Circulator operator++(int) { 
+ Circulator saved=*this; 
+ ++(*this); 
+ return saved; 
+ } 
+ 
+ Circulator &operator() { 
+ if ( _pos == _first ) _pos = _last; 
+ _pos; 
+ return *this; 
+ } 
+ Circulator operator(int) { 
+ Circulator saved=*this; 
+ (*this); 
+ return saved; 
+ } 
+ 
+ Circulator &operator+=(int n) { 
+ _pos = _offset(n); 
+ return *this; 
+ } 
+ Circulator operator+(int n) const { 
+ return Circulator(_first, _last, _offset(n)); 
+ } 
+ Circulator &operator=(int n) { 
+ _pos = _offset(n); 
+ return *this; 
+ } 
+ Circulator operator(int n) const { 
+ return Circulator(_first, _last, _offset(n)); 
+ } 
+ 
+ difference_type operator(Circulator const &other) { 
+ return _pos  other._pos; 
+ } 
+ 
+ reference operator[](int n) const { 
+ return *_offset(n); 
+ } 
+ 
+private: 
+ void match_random_access(iterator_category) {} 
+ 
+ Iterator _offset(int n) { 
+ difference_type range=( _last  _first ); 
+ difference_type offset=( _pos  _first + n ); 
+ 
+ if ( offset < 0 ) { 
+ // modulus not welldefined for negative numbers in C++ 
+ offset += ( ( offset / range ) + 1 ) * range; 
+ } else if ( offset >= range ) { 
+ offset %= range; 
+ } 
+ return _first + offset; 
+ } 
+ 
+ Iterator _first; 
+ Iterator _last; 
+ Iterator _pos; 
+}; 
+ 
+} 
+ 
+template <typename T> 
+Geom::Circulator<T> operator+(int n, Geom::Circulator<T> const &c) { 
+ return c + n; 
+} 
+ 
+#endif // SEEN_Circulator_H 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(substatementopen . 0)) 
+ indenttabsmode:nil 
+ cbraceoffset:0 
+ fillcolumn:99 
+ End: 
+ vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : 
+*/ 
+ 
Index: Scribus/scribus/third_party/lib2geom/bezierutils.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/bezierutils.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/bezierutils.cpp (revision 14937) 
@@ 0,0 +1,1004 @@ 
+#define __SP_BEZIER_UTILS_C__ 
+ 
+/** \file 
+ * Bezier interpolation for inkscape drawing code. 
+ */ 
+/* 
+ * Original code published in: 
+ * An Algorithm for Automatically Fitting Digitized Curves 
+ * by Philip J. Schneider 
+ * "Graphics Gems", Academic Press, 1990 
+ * 
+ * Authors: 
+ * Philip J. Schneider 
+ * Lauris Kaplinski <lauris@kaplinski.com> 
+ * Peter Moulder <pmoulder@mail.csse.monash.edu.au> 
+ * 
+ * Copyright (C) 1990 Philip J. Schneider 
+ * Copyright (C) 2001 Lauris Kaplinski 
+ * Copyright (C) 2001 Ximian, Inc. 
+ * Copyright (C) 2003,2004 Monash University 
+ * 
+ * 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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. 
+ * 
+ */ 
+ 
+#define SP_HUGE 1e5 
+#define noBEZIER_DEBUG 
+ 
+#ifdef HAVE_IEEEFP_H 
+# include <ieefp.h> 
+#endif 
+ 
+#include "bezierutils.h" 
+ 
+#include "isnan.h" 
+#include <assert.h> 
+ 
+namespace Geom{ 
+ 
+typedef Point BezierCurve[]; 
+ 
+/* Forward declarations */ 
+static void generate_bezier(Point b[], Point const d[], double const u[], unsigned len, 
+ Point const &tHat1, Point const &tHat2, double tolerance_sq); 
+static void estimate_lengths(Point bezier[], 
+ Point const data[], double const u[], unsigned len, 
+ Point const &tHat1, Point const &tHat2); 
+static void estimate_bi(Point b[4], unsigned ei, 
+ Point const data[], double const u[], unsigned len); 
+static void reparameterize(Point const d[], unsigned len, double u[], BezierCurve const bezCurve); 
+static double NewtonRaphsonRootFind(BezierCurve const Q, Point const &P, double u); 
+static Point darray_center_tangent(Point const d[], unsigned center, unsigned length); 
+static Point darray_right_tangent(Point const d[], unsigned const len); 
+static unsigned copy_without_nans_or_adjacent_duplicates(Point const src[], unsigned src_len, Point dest[]); 
+static void chord_length_parameterize(Point const d[], double u[], unsigned len); 
+static double compute_max_error_ratio(Point const d[], double const u[], unsigned len, 
+ BezierCurve const bezCurve, double tolerance, 
+ unsigned *splitPoint); 
+static double compute_hook(Point const &a, Point const &b, double const u, BezierCurve const bezCurve, 
+ double const tolerance); 
+ 
+ 
+static Point const unconstrained_tangent(0, 0); 
+ 
+ 
+/* 
+ * B0, B1, B2, B3 : Bezier multipliers 
+ */ 
+ 
+#define B0(u) ( ( 1.0  u ) * ( 1.0  u ) * ( 1.0  u ) ) 
+#define B1(u) ( 3 * u * ( 1.0  u ) * ( 1.0  u ) ) 
+#define B2(u) ( 3 * u * u * ( 1.0  u ) ) 
+#define B3(u) ( u * u * u ) 
+ 
+#ifdef BEZIER_DEBUG 
+# define DOUBLE_ASSERT(x) assert( ( (x) > SP_HUGE ) && ( (x) < SP_HUGE ) ) 
+# define BEZIER_ASSERT(b) do { \ 
+ DOUBLE_ASSERT((b)[0][X]); DOUBLE_ASSERT((b)[0][Y]); \ 
+ DOUBLE_ASSERT((b)[1][X]); DOUBLE_ASSERT((b)[1][Y]); \ 
+ DOUBLE_ASSERT((b)[2][X]); DOUBLE_ASSERT((b)[2][Y]); \ 
+ DOUBLE_ASSERT((b)[3][X]); DOUBLE_ASSERT((b)[3][Y]); \ 
+ } while(0) 
+#else 
+# define DOUBLE_ASSERT(x) do { } while(0) 
+# define BEZIER_ASSERT(b) do { } while(0) 
+#endif 
+ 
+ 
+/** 
+ * Fit a singlesegment Bezier curve to a set of digitized points. 
+ * 
+ * \return Number of segments generated, or 1 on error. 
+ */ 
+int 
+bezier_fit_cubic(Point *bezier, Point const *data, int len, double error) 
+{ 
+ return bezier_fit_cubic_r(bezier, data, len, error, 1); 
+} 
+ 
+/** 
+ * Fit a multisegment Bezier curve to a set of digitized points, with 
+ * possible weedout of identical points and NaNs. 
+ * 
+ * \param max_beziers Maximum number of generated segments 
+ * \param Result array, must be large enough for n. segments * 4 elements. 
+ * 
+ * \return Number of segments generated, or 1 on error. 
+ */ 
+int 
+bezier_fit_cubic_r(Point bezier[], Point const data[], int const len, double const error, unsigned const max_beziers) 
+{ 
+ if(bezier == NULL  
+ data == NULL  
+ len <= 0  
+ max_beziers >= (1ul << (31  2  1  3))) 
+ return 1; 
+ 
+ Point *uniqued_data = new Point[len]; 
+ unsigned uniqued_len = copy_without_nans_or_adjacent_duplicates(data, len, uniqued_data); 
+ 
+ if ( uniqued_len < 2 ) { 
+ delete[] uniqued_data; 
+ return 0; 
+ } 
+ 
+ /* Call fitcubic function with recursion. */ 
+ int const ret = bezier_fit_cubic_full(bezier, NULL, uniqued_data, uniqued_len, 
+ unconstrained_tangent, unconstrained_tangent, 
+ error, max_beziers); 
+ delete[] uniqued_data; 
+ return ret; 
+} 
+ 
+/** 
+ * Copy points from src to dest, filter out points containing NaN and 
+ * adjacent points with equal x and y. 
+ * \return length of dest 
+ */ 
+static unsigned 
+copy_without_nans_or_adjacent_duplicates(Point const src[], unsigned src_len, Point dest[]) 
+{ 
+ unsigned si = 0; 
+ for (;;) { 
+ if ( si == src_len ) { 
+ return 0; 
+ } 
+ if (!is_nan(src[si][X]) && 
+ !is_nan(src[si][Y])) { 
+ dest[0] = Point(src[si]); 
+ ++si; 
+ break; 
+ } 
+ } 
+ unsigned di = 0; 
+ for (; si < src_len; ++si) { 
+ Point const src_pt = Point(src[si]); 
+ if ( src_pt != dest[di] 
+ && !is_nan(src_pt[X]) 
+ && !is_nan(src_pt[Y])) { 
+ dest[++di] = src_pt; 
+ } 
+ } 
+ unsigned dest_len = di + 1; 
+ assert( dest_len <= src_len ); 
+ return dest_len; 
+} 
+ 
+/** 
+ * Fit a multisegment Bezier curve to a set of digitized points, without 
+ * possible weedout of identical points and NaNs. 
+ * 
+ * \pre data is uniqued, i.e. not exist i: data[i] == data[i + 1]. 
+ * \param max_beziers Maximum number of generated segments 
+ * \param Result array, must be large enough for n. segments * 4 elements. 
+ */ 
+int 
+bezier_fit_cubic_full(Point bezier[], int split_points[], 
+ Point const data[], int const len, 
+ Point const &tHat1, Point const &tHat2, 
+ double const error, unsigned const max_beziers) 
+{ 
+ int const maxIterations = 4; /* std::max times to try iterating */ 
+ 
+ if(!(bezier != NULL)  
+ !(data != NULL)  
+ !(len > 0)  
+ !(max_beziers >= 1)  
+ !(error >= 0.0)) 
+ return 1; 
+ 
+ if ( len < 2 ) return 0; 
+ 
+ if ( len == 2 ) { 
+ /* We have 2 points, which can be fitted trivially. */ 
+ bezier[0] = data[0]; 
+ bezier[3] = data[len  1]; 
+ double const dist = distance(bezier[0], bezier[3]) / 3.0; 
+ if (is_nan(dist)) { 
+ /* Numerical problem, fall back to straight line segment. */ 
+ bezier[1] = bezier[0]; 
+ bezier[2] = bezier[3]; 
+ } else { 
+ bezier[1] = ( is_zero(tHat1) 
+ ? ( 2 * bezier[0] + bezier[3] ) / 3. 
+ : bezier[0] + dist * tHat1 ); 
+ bezier[2] = ( is_zero(tHat2) 
+ ? ( bezier[0] + 2 * bezier[3] ) / 3. 
+ : bezier[3] + dist * tHat2 ); 
+ } 
+ BEZIER_ASSERT(bezier); 
+ return 1; 
+ } 
+ 
+ /* Parameterize points, and attempt to fit curve */ 
+ unsigned splitPoint; /* Point to split point set at. */ 
+ bool is_corner; 
+ { 
+ double *u = new double[len]; 
+ chord_length_parameterize(data, u, len); 
+ if ( u[len  1] == 0.0 ) { 
+ /* Zerolength path: every point in data[] is the same. 
+ * 
+ * (Clients aren't allowed to pass such data; handling the case is defensive 
+ * programming.) 
+ */ 
+ delete[] u; 
+ return 0; 
+ } 
+ 
+ generate_bezier(bezier, data, u, len, tHat1, tHat2, error); 
+ reparameterize(data, len, u, bezier); 
+ 
+ /* Find max deviation of points to fitted curve. */ 
+ double const tolerance = sqrt(error + 1e9); 
+ double maxErrorRatio = compute_max_error_ratio(data, u, len, bezier, tolerance, &splitPoint); 
+ 
+ if ( fabs(maxErrorRatio) <= 1.0 ) { 
+ BEZIER_ASSERT(bezier); 
+ delete[] u; 
+ return 1; 
+ } 
+ 
+ /* If error not too large, then try some reparameterization and iteration. */ 
+ if ( 0.0 <= maxErrorRatio && maxErrorRatio <= 3.0 ) { 
+ for (int i = 0; i < maxIterations; i++) { 
+ generate_bezier(bezier, data, u, len, tHat1, tHat2, error); 
+ reparameterize(data, len, u, bezier); 
+ maxErrorRatio = compute_max_error_ratio(data, u, len, bezier, tolerance, &splitPoint); 
+ if ( fabs(maxErrorRatio) <= 1.0 ) { 
+ BEZIER_ASSERT(bezier); 
+ delete[] u; 
+ return 1; 
+ } 
+ } 
+ } 
+ delete[] u; 
+ is_corner = (maxErrorRatio < 0); 
+ } 
+ 
+ if (is_corner) { 
+ assert(splitPoint < unsigned(len)); 
+ if (splitPoint == 0) { 
+ if (is_zero(tHat1)) { 
+ /* Got spike even with unconstrained initial tangent. */ 
+ ++splitPoint; 
+ } else { 
+ return bezier_fit_cubic_full(bezier, split_points, data, len, unconstrained_tangent, tHat2, 
+ error, max_beziers); 
+ } 
+ } else if (splitPoint == unsigned(len  1)) { 
+ if (is_zero(tHat2)) { 
+ /* Got spike even with unconstrained final tangent. */ 
+ splitPoint; 
+ } else { 
+ return bezier_fit_cubic_full(bezier, split_points, data, len, tHat1, unconstrained_tangent, 
+ error, max_beziers); 
+ } 
+ } 
+ } 
+ 
+ if ( 1 < max_beziers ) { 
+ /* 
+ * Fitting failed  split at max error point and fit recursively 
+ */ 
+ unsigned const rec_max_beziers1 = max_beziers  1; 
+ 
+ Point recTHat2, recTHat1; 
+ if (is_corner) { 
+ if(!(0 < splitPoint && splitPoint < unsigned(len  1))) 
+ return 1; 
+ recTHat1 = recTHat2 = unconstrained_tangent; 
+ } else { 
+ /* Unit tangent vector at splitPoint. */ 
+ recTHat2 = darray_center_tangent(data, splitPoint, len); 
+ recTHat1 = recTHat2; 
+ } 
+ int const nsegs1 = bezier_fit_cubic_full(bezier, split_points, data, splitPoint + 1, 
+ tHat1, recTHat2, error, rec_max_beziers1); 
+ if ( nsegs1 < 0 ) { 
+#ifdef BEZIER_DEBUG 
+ g_print("fit_cubic[1]: recursive call failed\n"); 
+#endif 
+ return 1; 
+ } 
+ assert( nsegs1 != 0 ); 
+ if (split_points != NULL) { 
+ split_points[nsegs1  1] = splitPoint; 
+ } 
+ unsigned const rec_max_beziers2 = max_beziers  nsegs1; 
+ int const nsegs2 = bezier_fit_cubic_full(bezier + nsegs1*4, 
+ ( split_points == NULL 
+ ? NULL 
+ : split_points + nsegs1 ), 
+ data + splitPoint, len  splitPoint, 
+ recTHat1, tHat2, error, rec_max_beziers2); 
+ if ( nsegs2 < 0 ) { 
+#ifdef BEZIER_DEBUG 
+ g_print("fit_cubic[2]: recursive call failed\n"); 
+#endif 
+ return 1; 
+ } 
+ 
+#ifdef BEZIER_DEBUG 
+ g_print("fit_cubic: success[nsegs: %d+%d=%d] on max_beziers:%u\n", 
+ nsegs1, nsegs2, nsegs1 + nsegs2, max_beziers); 
+#endif 
+ return nsegs1 + nsegs2; 
+ } else { 
+ return 1; 
+ } 
+} 
+ 
+ 
+/** 
+ * Fill in \a bezier[] based on the given data and tangent requirements, using 
+ * a leastsquares fit. 
+ * 
+ * Each of tHat1 and tHat2 should be either a zero vector or a unit vector. 
+ * If it is zero, then bezier[1 or 2] is estimated without constraint; otherwise, 
+ * it bezier[1 or 2] is placed in the specified direction from bezier[0 or 3]. 
+ * 
+ * \param tolerance_sq Used only for an initial guess as to tangent directions 
+ * when \a tHat1 or \a tHat2 is zero. 
+ */ 
+static void 
+generate_bezier(Point bezier[], 
+ Point const data[], double const u[], unsigned const len, 
+ Point const &tHat1, Point const &tHat2, 
+ double const tolerance_sq) 
+{ 
+ bool const est1 = is_zero(tHat1); 
+ bool const est2 = is_zero(tHat2); 
+ Point est_tHat1( est1 
+ ? darray_left_tangent(data, len, tolerance_sq) 
+ : tHat1 ); 
+ Point est_tHat2( est2 
+ ? darray_right_tangent(data, len, tolerance_sq) 
+ : tHat2 ); 
+ estimate_lengths(bezier, data, u, len, est_tHat1, est_tHat2); 
+ /* We find that darray_right_tangent tends to produce better results 
+ for our current freehand tool than full estimation. */ 
+ if (est1) { 
+ estimate_bi(bezier, 1, data, u, len); 
+ if (bezier[1] != bezier[0]) { 
+ est_tHat1 = unit_vector(bezier[1]  bezier[0]); 
+ } 
+ estimate_lengths(bezier, data, u, len, est_tHat1, est_tHat2); 
+ } 
+} 
+ 
+ 
+static void 
+estimate_lengths(Point bezier[], 
+ Point const data[], double const uPrime[], unsigned const len, 
+ Point const &tHat1, Point const &tHat2) 
+{ 
+ double C[2][2]; /* Matrix C. */ 
+ double X[2]; /* Matrix X. */ 
+ 
+ /* Create the C and X matrices. */ 
+ C[0][0] = 0.0; 
+ C[0][1] = 0.0; 
+ C[1][0] = 0.0; 
+ C[1][1] = 0.0; 
+ X[0] = 0.0; 
+ X[1] = 0.0; 
+ 
+ /* First and last control points of the Bezier curve are positioned exactly at the first and 
+ last data points. */ 
+ bezier[0] = data[0]; 
+ bezier[3] = data[len  1]; 
+ 
+ for (unsigned i = 0; i < len; i++) { 
+ /* Bezier control point coefficients. */ 
+ double const b0 = B0(uPrime[i]); 
+ double const b1 = B1(uPrime[i]); 
+ double const b2 = B2(uPrime[i]); 
+ double const b3 = B3(uPrime[i]); 
+ 
+ /* rhs for eqn */ 
+ Point const a1 = b1 * tHat1; 
+ Point const a2 = b2 * tHat2; 
+ 
+ C[0][0] += dot(a1, a1); 
+ C[0][1] += dot(a1, a2); 
+ C[1][0] = C[0][1]; 
+ C[1][1] += dot(a2, a2); 
+ 
+ /* Additional offset to the data point from the predicted point if we were to set bezier[1] 
+ to bezier[0] and bezier[2] to bezier[3]. */ 
+ Point const shortfall 
+ = ( data[i] 
+  ( ( b0 + b1 ) * bezier[0] ) 
+  ( ( b2 + b3 ) * bezier[3] ) ); 
+ X[0] += dot(a1, shortfall); 
+ X[1] += dot(a2, shortfall); 
+ } 
+ 
+ /* We've constructed a pair of equations in the form of a matrix product C * alpha = X. 
+ Now solve for alpha. */ 
+ double alpha_l, alpha_r; 
+ 
+ /* Compute the determinants of C and X. */ 
+ double const det_C0_C1 = C[0][0] * C[1][1]  C[1][0] * C[0][1]; 
+ if ( det_C0_C1 != 0 ) { 
+ /* Apparently Kramer's rule. */ 
+ double const det_C0_X = C[0][0] * X[1]  C[0][1] * X[0]; 
+ double const det_X_C1 = X[0] * C[1][1]  X[1] * C[0][1]; 
+ alpha_l = det_X_C1 / det_C0_C1; 
+ alpha_r = det_C0_X / det_C0_C1; 
+ } else { 
+ /* The matrix is underdetermined. Try requiring alpha_l == alpha_r. 
+ * 
+ * One way of implementing the constraint alpha_l == alpha_r is to treat them as the same 
+ * variable in the equations. We can do this by adding the columns of C to form a single 
+ * column, to be multiplied by alpha to give the column vector X. 
+ * 
+ * We try each row in turn. 
+ */ 
+ double const c0 = C[0][0] + C[0][1]; 
+ if (c0 != 0) { 
+ alpha_l = alpha_r = X[0] / c0; 
+ } else { 
+ double const c1 = C[1][0] + C[1][1]; 
+ if (c1 != 0) { 
+ alpha_l = alpha_r = X[1] / c1; 
+ } else { 
+ /* Let the below code handle this. */ 
+ alpha_l = alpha_r = 0.; 
+ } 
+ } 
+ } 
+ 
+ /* If alpha negative, use the Wu/Barsky heuristic (see text). (If alpha is 0, you get 
+ coincident control points that lead to divide by zero in any subsequent 
+ NewtonRaphsonRootFind() call.) */ 
+ /// \todo Check whether this specialcasing is necessary now that 
+ /// NewtonRaphsonRootFind handles nonpositive denominator. 
+ if ( alpha_l < 1.0e6  
+ alpha_r < 1.0e6 ) 
+ { 
+ alpha_l = alpha_r = distance(data[0], data[len1]) / 3.0; 
+ } 
+ 
+ /* Control points 1 and 2 are positioned an alpha distance out on the tangent vectors, left and 
+ right, respectively. */ 
+ bezier[1] = alpha_l * tHat1 + bezier[0]; 
+ bezier[2] = alpha_r * tHat2 + bezier[3]; 
+ 
+ return; 
+} 
+ 
+static double lensq(Point const p) { 
+ return dot(p, p); 
+} 
+ 
+static void 
+estimate_bi(Point bezier[4], unsigned const ei, 
+ Point const data[], double const u[], unsigned const len) 
+{ 
+ if(!(1 <= ei && ei <= 2)) 
+ return; 
+ unsigned const oi = 3  ei; 
+ double num[2] = {0., 0.}; 
+ double den = 0.; 
+ for (unsigned i = 0; i < len; ++i) { 
+ double const ui = u[i]; 
+ double const b[4] = { 
+ B0(ui), 
+ B1(ui), 
+ B2(ui), 
+ B3(ui) 
+ }; 
+ 
+ for (unsigned d = 0; d < 2; ++d) { 
+ num[d] += b[ei] * (b[0] * bezier[0][d] + 
+ b[oi] * bezier[oi][d] + 
+ b[3] * bezier[3][d] + 
+  data[i][d]); 
+ } 
+ den = b[ei] * b[ei]; 
+ } 
+ 
+ if (den != 0.) { 
+ for (unsigned d = 0; d < 2; ++d) { 
+ bezier[ei][d] = num[d] / den; 
+ } 
+ } else { 
+ bezier[ei] = ( oi * bezier[0] + ei * bezier[3] ) / 3.; 
+ } 
+} 
+ 
+/** 
+ * Given set of points and their parameterization, try to find a better assignment of parameter 
+ * values for the points. 
+ * 
+ * \param d Array of digitized points. 
+ * \param u Current parameter values. 
+ * \param bezCurve Current fitted curve. 
+ * \param len Number of values in both d and u arrays. 
+ * Also the size of the array that is allocated for return. 
+ */ 
+static void 
+reparameterize(Point const d[], 
+ unsigned const len, 
+ double u[], 
+ BezierCurve const bezCurve) 
+{ 
+ assert( 2 <= len ); 
+ 
+ unsigned const last = len  1; 
+ assert( bezCurve[0] == d[0] ); 
+ assert( bezCurve[3] == d[last] ); 
+ assert( u[0] == 0.0 ); 
+ assert( u[last] == 1.0 ); 
+ /* Otherwise, consider including 0 and last in the below loop. */ 
+ 
+ for (unsigned i = 1; i < last; i++) { 
+ u[i] = NewtonRaphsonRootFind(bezCurve, d[i], u[i]); 
+ } 
+} 
+ 
+/** 
+ * Use NewtonRaphson iteration to find better root. 
+ * 
+ * \param Q Current fitted curve 
+ * \param P Digitized point 
+ * \param u Parameter value for "P" 
+ * 
+ * \return Improved u 
+ */ 
+static double 
+NewtonRaphsonRootFind(BezierCurve const Q, Point const &P, double const u) 
+{ 
+ assert( 0.0 <= u ); 
+ assert( u <= 1.0 ); 
+ 
+ /* Generate control vertices for Q'. */ 
+ Point Q1[3]; 
+ for (unsigned i = 0; i < 3; i++) { 
+ Q1[i] = 3.0 * ( Q[i+1]  Q[i] ); 
+ } 
+ 
+ /* Generate control vertices for Q''. */ 
+ Point Q2[2]; 
+ for (unsigned i = 0; i < 2; i++) { 
+ Q2[i] = 2.0 * ( Q1[i+1]  Q1[i] ); 
+ } 
+ 
+ /* Compute Q(u), Q'(u) and Q''(u). */ 
+ Point const Q_u = bezier_pt(3, Q, u); 
+ Point const Q1_u = bezier_pt(2, Q1, u); 
+ Point const Q2_u = bezier_pt(1, Q2, u); 
+ 
+ /* Compute f(u)/f'(u), where f is the derivative wrt u of distsq(u) = 0.5 * the square of the 
+ distance from P to Q(u). Here we're using NewtonRaphson to find a stationary point in the 
+ distsq(u), hopefully corresponding to a local minimum in distsq (and hence a local minimum 
+ distance from P to Q(u)). */ 
+ Point const diff = Q_u  P; 
+ double numerator = dot(diff, Q1_u); 
+ double denominator = dot(Q1_u, Q1_u) + dot(diff, Q2_u); 
+ 
+ double improved_u; 
+ if ( denominator > 0. ) { 
+ /* One iteration of NewtonRaphson: 
+ improved_u = u  f(u)/f'(u) */ 
+ improved_u = u  ( numerator / denominator ); 
+ } else { 
+ /* Using NewtonRaphson would move in the wrong direction (towards a local maximum rather 
+ than local minimum), so we move an arbitrary amount in the right direction. */ 
+ if ( numerator > 0. ) { 
+ improved_u = u * .98  .01; 
+ } else if ( numerator < 0. ) { 
+ /* Deliberately asymmetrical, to reduce the chance of cycling. */ 
+ improved_u = .031 + u * .98; 
+ } else { 
+ improved_u = u; 
+ } 
+ } 
+ 
+ if (!is_finite(improved_u)) { 
+ improved_u = u; 
+ } else if ( improved_u < 0.0 ) { 
+ improved_u = 0.0; 
+ } else if ( improved_u > 1.0 ) { 
+ improved_u = 1.0; 
+ } 
+ 
+ /* Ensure that improved_u isn't actually worse. */ 
+ { 
+ double const diff_lensq = lensq(diff); 
+ for (double proportion = .125; ; proportion += .125) { 
+ if ( lensq( bezier_pt(3, Q, improved_u)  P ) > diff_lensq ) { 
+ if ( proportion > 1.0 ) { 
+ //g_warning("found proportion %g", proportion); 
+ improved_u = u; 
+ break; 
+ } 
+ improved_u = ( ( 1  proportion ) * improved_u + 
+ proportion * u ); 
+ } else { 
+ break; 
+ } 
+ } 
+ } 
+ 
+ DOUBLE_ASSERT(improved_u); 
+ return improved_u; 
+} 
+ 
+/** 
+ * Evaluate a Bezier curve at parameter value \a t. 
+ * 
+ * \param degree The degree of the Bezier curve: 3 for cubic, 2 for quadratic etc. Must be less 
+ * than 4. 
+ * \param V The control points for the Bezier curve. Must have (\a degree+1) 
+ * elements. 
+ * \param t The "parameter" value, specifying whereabouts along the curve to 
+ * evaluate. Typically in the range [0.0, 1.0]. 
+ * 
+ * Let s = 1  t. 
+ * BezierII(1, V) gives (s, t) * V, i.e. t of the way 
+ * from V[0] to V[1]. 
+ * BezierII(2, V) gives (s**2, 2*s*t, t**2) * V. 
+ * BezierII(3, V) gives (s**3, 3 s**2 t, 3s t**2, t**3) * V. 
+ * 
+ * The derivative of BezierII(i, V) with respect to t 
+ * is i * BezierII(i1, V'), where for all j, V'[j] = 
+ * V[j + 1]  V[j]. 
+ */ 
+Point 
+bezier_pt(unsigned const degree, Point const V[], double const t) 
+{ 
+ /** Pascal's triangle. */ 
+ static int const pascal[4][4] = {{1}, 
+ {1, 1}, 
+ {1, 2, 1}, 
+ {1, 3, 3, 1}}; 
+ assert( degree < 4); 
+ double const s = 1.0  t; 
+ 
+ /* Calculate powers of t and s. */ 
+ double spow[4]; 
+ double tpow[4]; 
+ spow[0] = 1.0; spow[1] = s; 
+ tpow[0] = 1.0; tpow[1] = t; 
+ for (unsigned i = 1; i < degree; ++i) { 
+ spow[i + 1] = spow[i] * s; 
+ tpow[i + 1] = tpow[i] * t; 
+ } 
+ 
+ Point ret = spow[degree] * V[0]; 
+ for (unsigned i = 1; i <= degree; ++i) { 
+ ret += pascal[degree][i] * spow[degree  i] * tpow[i] * V[i]; 
+ } 
+ return ret; 
+} 
+ 
+/* 
+ * ComputeLeftTangent, ComputeRightTangent, ComputeCenterTangent : 
+ * Approximate unit tangents at endpoints and "center" of digitized curve 
+ */ 
+ 
+/** 
+ * Estimate the (forward) tangent at point d[first + 0.5]. 
+ * 
+ * Unlike the center and right versions, this calculates the tangent in 
+ * the way one might expect, i.e., wrt increasing index into d. 
+ * \pre (2 \<= len) and (d[0] != d[1]). 
+ **/ 
+Point 
+darray_left_tangent(Point const d[], unsigned const len) 
+{ 
+ assert( len >= 2 ); 
+ assert( d[0] != d[1] ); 
+ return unit_vector( d[1]  d[0] ); 
+} 
+ 
+/** 
+ * Estimates the (backward) tangent at d[last  0.5]. 
+ * 
+ * \note The tangent is "backwards", i.e. it is with respect to 
+ * decreasing index rather than increasing index. 
+ * 
+ * \pre 2 \<= len. 
+ * \pre d[len  1] != d[len  2]. 
+ * \pre all[p in d] in_svg_plane(p). 
+ */ 
+static Point 
+darray_right_tangent(Point const d[], unsigned const len) 
+{ 
+ assert( 2 <= len ); 
+ unsigned const last = len  1; 
+ unsigned const prev = last  1; 
+ assert( d[last] != d[prev] ); 
+ return unit_vector( d[prev]  d[last] ); 
+} 
+ 
+/** 
+ * Estimate the (forward) tangent at point d[0]. 
+ * 
+ * Unlike the center and right versions, this calculates the tangent in 
+ * the way one might expect, i.e., wrt increasing index into d. 
+ * 
+ * \pre 2 \<= len. 
+ * \pre d[0] != d[1]. 
+ * \pre all[p in d] in_svg_plane(p). 
+ * \post is_unit_vector(ret). 
+ **/ 
+Point 
+darray_left_tangent(Point const d[], unsigned const len, double const tolerance_sq) 
+{ 
+ assert( 2 <= len ); 
+ assert( 0 <= tolerance_sq ); 
+ for (unsigned i = 1;;) { 
+ Point const pi(d[i]); 
+ Point const t(pi  d[0]); 
+ double const distsq = dot(t, t); 
+ if ( tolerance_sq < distsq ) { 
+ return unit_vector(t); 
+ } 
+ ++i; 
+ if (i == len) { 
+ return ( distsq == 0 
+ ? darray_left_tangent(d, len) 
+ : unit_vector(t) ); 
+ } 
+ } 
+} 
+ 
+/** 
+ * Estimates the (backward) tangent at d[last]. 
+ * 
+ * \note The tangent is "backwards", i.e. it is with respect to 
+ * decreasing index rather than increasing index. 
+ * 
+ * \pre 2 \<= len. 
+ * \pre d[len  1] != d[len  2]. 
+ * \pre all[p in d] in_svg_plane(p). 
+ */ 
+Point 
+darray_right_tangent(Point const d[], unsigned const len, double const tolerance_sq) 
+{ 
+ assert( 2 <= len ); 
+ assert( 0 <= tolerance_sq ); 
+ unsigned const last = len  1; 
+ for (unsigned i = last  1;; i) { 
+ Point const pi(d[i]); 
+ Point const t(pi  d[last]); 
+ double const distsq = dot(t, t); 
+ if ( tolerance_sq < distsq ) { 
+ return unit_vector(t); 
+ } 
+ if (i == 0) { 
+ return ( distsq == 0 
+ ? darray_right_tangent(d, len) 
+ : unit_vector(t) ); 
+ } 
+ } 
+} 
+ 
+/** 
+ * Estimates the (backward) tangent at d[center], by averaging the two 
+ * segments connected to d[center] (and then normalizing the result). 
+ * 
+ * \note The tangent is "backwards", i.e. it is with respect to 
+ * decreasing index rather than increasing index. 
+ * 
+ * \pre (0 \< center \< len  1) and d is uniqued (at least in 
+ * the immediate vicinity of \a center). 
+ */ 
+static Point 
+darray_center_tangent(Point const d[], 
+ unsigned const center, 
+ unsigned const len) 
+{ 
+ assert( center != 0 ); 
+ assert( center < len  1 ); 
+ 
+ Point ret; 
+ if ( d[center + 1] == d[center  1] ) { 
+ /* Rotate 90 degrees in an arbitrary direction. */ 
+ Point const diff = d[center]  d[center  1]; 
+ ret = rot90(diff); 
+ } else { 
+ ret = d[center  1]  d[center + 1]; 
+ } 
+ ret.normalize(); 
+ return ret; 
+} 
+ 
+ 
+/** 
+ * Assign parameter values to digitized points using relative distances between points. 
+ * 
+ * \pre Parameter array u must have space for \a len items. 
+ */ 
+static void 
+chord_length_parameterize(Point const d[], double u[], unsigned const len) 
+{ 
+ if(!( 2 <= len )) 
+ return; 
+ 
+ /* First let u[i] equal the distance travelled along the path from d[0] to d[i]. */ 
+ u[0] = 0.0; 
+ for (unsigned i = 1; i < len; i++) { 
+ double const dist = distance(d[i], d[i1]); 
+ u[i] = u[i1] + dist; 
+ } 
+ 
+ /* Then scale to [0.0 .. 1.0]. */ 
+ double tot_len = u[len  1]; 
+ if(!( tot_len != 0 )) 
+ return; 
+ if (is_finite(tot_len)) { 
+ for (unsigned i = 1; i < len; ++i) { 
+ u[i] /= tot_len; 
+ } 
+ } else { 
+ /* We could do better, but this probably never happens anyway. */ 
+ for (unsigned i = 1; i < len; ++i) { 
+ u[i] = i / (double) ( len  1 ); 
+ } 
+ } 
+ 
+ /** \todo 
+ * It's been reported that u[len  1] can differ from 1.0 on some 
+ * systems (amd64), despite it having been calculated as x / x where x 
+ * is isFinite and nonzero. 
+ */ 
+ if (u[len  1] != 1) { 
+ double const diff = u[len  1]  1; 
+ if (fabs(diff) > 1e13) { 
+ assert(0); // No warnings in 2geom 
+ //g_warning("u[len  1] = %19g (= 1 + %19g), expecting exactly 1", 
+ // u[len  1], diff); 
+ } 
+ u[len  1] = 1; 
+ } 
+ 
+#ifdef BEZIER_DEBUG 
+ assert( u[0] == 0.0 && u[len  1] == 1.0 ); 
+ for (unsigned i = 1; i < len; i++) { 
+ assert( u[i] >= u[i1] ); 
+ } 
+#endif 
+} 
+ 
+ 
+ 
+ 
+/** 
+ * Find the maximum squared distance of digitized points to fitted curve, and (if this maximum 
+ * error is nonzero) set \a *splitPoint to the corresponding index. 
+ * 
+ * \pre 2 \<= len. 
+ * \pre u[0] == 0. 
+ * \pre u[len  1] == 1.0. 
+ * \post ((ret == 0.0) 
+ *  ((*splitPoint \< len  1) 
+ * \&\& (*splitPoint != 0  ret \< 0.0))). 
+ */ 
+static double 
+compute_max_error_ratio(Point const d[], double const u[], unsigned const len, 
+ BezierCurve const bezCurve, double const tolerance, 
+ unsigned *const splitPoint) 
+{ 
+ assert( 2 <= len ); 
+ unsigned const last = len  1; 
+ assert( bezCurve[0] == d[0] ); 
+ assert( bezCurve[3] == d[last] ); 
+ assert( u[0] == 0.0 ); 
+ assert( u[last] == 1.0 ); 
+ /* I.e. assert that the error for the first & last points is zero. 
+ * Otherwise we should include those points in the below loop. 
+ * The assertion is also necessary to ensure 0 < splitPoint < last. 
+ */ 
+ 
+ double maxDistsq = 0.0; /* Maximum error */ 
+ double max_hook_ratio = 0.0; 
+ unsigned snap_end = 0; 
+ Point prev = bezCurve[0]; 
+ for (unsigned i = 1; i <= last; i++) { 
+ Point const curr = bezier_pt(3, bezCurve, u[i]); 
+ double const distsq = lensq( curr  d[i] ); 
+ if ( distsq > maxDistsq ) { 
+ maxDistsq = distsq; 
+ *splitPoint = i; 
+ } 
+ double const hook_ratio = compute_hook(prev, curr, .5 * (u[i  1] + u[i]), bezCurve, tolerance); 
+ if (max_hook_ratio < hook_ratio) { 
+ max_hook_ratio = hook_ratio; 
+ snap_end = i; 
+ } 
+ prev = curr; 
+ } 
+ 
+ double const dist_ratio = sqrt(maxDistsq) / tolerance; 
+ double ret; 
+ if (max_hook_ratio <= dist_ratio) { 
+ ret = dist_ratio; 
+ } else { 
+ assert(0 < snap_end); 
+ ret = max_hook_ratio; 
+ *splitPoint = snap_end  1; 
+ } 
+ assert( ret == 0.0 
+  ( ( *splitPoint < last ) 
+ && ( *splitPoint != 0  ret < 0. ) ) ); 
+ return ret; 
+} 
+ 
+/** 
+ * Whereas compute_max_error_ratio() checks for itself that each data point 
+ * is near some point on the curve, this function checks that each point on 
+ * the curve is near some data point (or near some point on the polyline 
+ * defined by the data points, or something like that: we allow for a 
+ * "reasonable curviness" from such a polyline). "Reasonable curviness" 
+ * means we draw a circle centred at the midpoint of a..b, of radius 
+ * proportional to the length a  b, and require that each point on the 
+ * segment of bezCurve between the parameters of a and b be within that circle. 
+ * If any point P on the bezCurve segment is outside of that allowable 
+ * region (circle), then we return some metric that increases with the 
+ * distance from P to the circle. 
+ * 
+ * Given that this is a fairly arbitrary criterion for finding appropriate 
+ * places for sharp corners, we test only one point on bezCurve, namely 
+ * the point on bezCurve with parameter halfway between our estimated 
+ * parameters for a and b. (Alternatives are taking the farthest of a 
+ * few parameters between those of a and b, or even using a variant of 
+ * NewtonRaphsonFindRoot() for finding the maximum rather than minimum 
+ * distance.) 
+ */ 
+static double 
+compute_hook(Point const &a, Point const &b, double const u, BezierCurve const bezCurve, 
+ double const tolerance) 
+{ 
+ Point const P = bezier_pt(3, bezCurve, u); 
+ double const dist = distance((a+b)*.5, P); 
+ if (dist < tolerance) { 
+ return 0; 
+ } 
+ double const allowed = distance(a, b) + tolerance; 
+ return dist / allowed; 
+ /** \todo 
+ * effic: Hooks are very rare. We could start by comparing 
+ * distsq, only resorting to the more expensive L2 in cases of 
+ * uncertainty. 
+ */ 
+} 
+ 
+} 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/quadtree.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/quadtree.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/quadtree.h (revision 14937) 
@@ 0,0 +1,41 @@ 
+#include <vector> 
+#include <cassert> 
+ 
+class Quad{ 
+public: 
+ Quad* children[4]; 
+ std::vector<int> data; 
+ Quad() { 
+ for(int i = 0; i < 4; i++) 
+ children[i] = 0; 
+ } 
+ typedef std::vector<int>::iterator iterator; 
+}; 
+ 
+class QuadTree{ 
+public: 
+ Quad* root; 
+ double scale; 
+ double bx0, bx1; 
+ 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); 
+}; 
+ 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(substatementopen . 0)) 
+ indenttabsmode:nil 
+ cbraceoffset:0 
+ fillcolumn:99 
+ End: 
+ vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : 
+*/ 
+ 
Index: Scribus/scribus/third_party/lib2geom/sturm.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/sturm.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/sturm.h (revision 14937) 
@@ 0,0 +1,70 @@ 
+#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) { 
+ push_back(X); 
+ push_back(derivative(X)); 
+ Poly Xi = back(); 
+ Poly Xim1 = X; 
+ std::cout << "sturm:\n" << Xim1 << std::endl; 
+ std::cout << Xi << std::endl; 
+ while(Xi.size() > 1) { 
+ Poly r; 
+ divide(Xim1, Xi, r); 
+ std::cout << r << std::endl; 
+ assert(r.size() < Xi.size()); 
+ Xim1 = Xi; 
+ Xi = r; 
+ assert(Xim1.size() > Xi.size()); 
+ push_back(Xi); 
+ } 
+ } 
+ 
+ unsigned count_signs(double t) { 
+ unsigned n_signs = 0;/* Number of signchanges */ 
+ const double big = 1e20; // a number such that practical polys would overflow on evaluation 
+ if(t >= big) { 
+ int old_sign = sgn((*this)[0].back()); 
+ for (unsigned i = 1; i < size(); i++) { 
+ int sign = sgn((*this)[i].back()); 
+ if (sign != old_sign) 
+ n_signs++; 
+ old_sign = sign; 
+ } 
+ } else { 
+ int old_sign = sgn((*this)[0].eval(t)); 
+ for (unsigned i = 1; i < size(); i++) { 
+ int sign = sgn((*this)[i].eval(t)); 
+ if (sign != old_sign) 
+ n_signs++; 
+ old_sign = sign; 
+ } 
+ } 
+ return n_signs; 
+ } 
+ 
+ unsigned n_roots_between(double l, double r) { 
+ return count_signs(l)  count_signs(r); 
+ } 
+}; 
+ 
+} //namespace Geom 
+ 
+#endif 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/piecewise.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/piecewise.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/piecewise.h (revision 14937) 
@@ 0,0 +1,690 @@ 
+/* 
+ * 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 COPYINGLGPL2.1; if not, output to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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 (1t)*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 = ab; 
+ 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.e3); 
+Piecewise<SBasis> 
+divide(SBasis const &a, Piecewise<SBasis> const &b, double tol, unsigned k, double zero=1.e3); 
+Piecewise<SBasis> 
+divide(Piecewise<SBasis> const &a, SBasis const &b, double tol, unsigned k, double zero=1.e3); 
+Piecewise<SBasis> 
+divide(SBasis const &a, SBasis const &b, double tol, unsigned k, double zero=1.e3); 
+ 
+//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, (1t0) / 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, (1t0) / 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]), 
+ (1f.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]+= cresult.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++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/convexcover.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/convexcover.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/convexcover.h (revision 14937) 
@@ 0,0 +1,174 @@ 
+#ifndef GEOM_CONVEX_COVER_H 
+#define GEOM_CONVEX_COVER_H 
+ 
+/* 
+ * convexcover.h 
+ * 
+ * Copyright 2006 Nathan Hurst <njh@mail.csse.monash.edu.au> 
+ * Copyright 2006 Michael G. 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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. 
+ * 
+ */ 
+ 
+/** A convex cover is a sequence of convex polygons that completely cover the path. For now a 
+ * convex hull class is included here (the convexhull header is wrong) 
+ */ 
+ 
+#include "point.h" 
+#include <vector> 
+ 
+namespace Geom{ 
+ 
+/** ConvexHull 
+ * A convexhull is a convex region  every point between two points in the convex hull is also in 
+ * the convex hull. It is defined by a set of points travelling in a clockwise direction. We require the first point to be top most, and of the topmost, leftmost. 
+ 
+ * An empty hull has no points, we allow a single point or two points degenerate cases. 
+ 
+ * We could provide the centroid as a member for efficient direction determination. We can update the 
+ * centroid with all operations with the same time complexity as the operation. 
+ */ 
+ 
+class ConvexHull{ 
+public: // XXX: should be private :) 
+ // extracts the convex hull of boundary. internal use only 
+ void find_pivot(); 
+ void angle_sort(); 
+ void graham_scan(); 
+ void graham(); 
+public: 
+ std::vector<Point> boundary; 
+ //Point centroid; 
+ 
+ void merge(Point p); 
+ bool contains_point(Point p); 
+ 
+ inline Point operator[](int i) const { 
+ int l = boundary.size(); 
+ if(l == 0) return Point(); 
+ return boundary[i >= 0 ? i % l : (i % l) + l]; 
+ } 
+ 
+ /*inline Point &operator[](unsigned i) { 
+ int l = boundary.size(); 
+ if(l == 0) return Point(); 
+ return boundary[i >= 0 ? i % l : i % l + l]; 
+ }*/ 
+ 
+public: 
+ ConvexHull() {} 
+ ConvexHull(std::vector<Point> const & points) { 
+ boundary = points; 
+ graham(); 
+ } 
+ 
+ template <typename T> 
+ ConvexHull(T b, T e) :boundary(b,e) {} 
+ 
+public: 
+ /** Is the convex hull clockwise? We use the definition of clockwise from point.h 
+ **/ 
+ bool is_clockwise() const; 
+ bool no_colinear_points() const; 
+ bool top_point_first() const; 
+ bool meets_invariants() const; 
+ 
+ // contains no points 
+ bool empty() const { return boundary.empty();} 
+ 
+ // contains exactly one point 
+ bool singular() const { return boundary.size() == 1;} 
+ 
+ // all points are on a line 
+ bool linear() const { return boundary.size() == 2;} 
+ bool is_degenerate() const; 
+ 
+ // area of the convex hull 
+ double area() const; 
+ 
+ // furthest point in a direction (lg time) 
+ Point const * furthest(Point direction) const; 
+ 
+ bool is_left(Point p, int n); 
+ int find_left(Point p); 
+}; 
+ 
+// do two convex hulls intersect? 
+bool intersectp(ConvexHull a, ConvexHull b); 
+ 
+std::vector<Point> bridge_points(ConvexHull a, ConvexHull b); 
+ 
+// find the convex hull intersection 
+ConvexHull intersection(ConvexHull a, ConvexHull b); 
+ConvexHull sweepline_intersection(ConvexHull const &a, ConvexHull const &b); 
+ 
+// find the convex hull of a set of convex hulls 
+ConvexHull merge(ConvexHull a, ConvexHull b); 
+ 
+// naive approach 
+ConvexHull graham_merge(ConvexHull a, ConvexHull b); 
+ 
+unsigned find_bottom_right(ConvexHull const &a); 
+ 
+/*** Arbitrary transform operator. 
+ * Take a convex hull and apply an arbitrary convexity preserving transform. 
+ * we should be concerned about singular tranforms here. 
+ */ 
+template <class T> ConvexHull operator*(ConvexHull const &p, T const &m) { 
+ ConvexHull pr; 
+ 
+ pr.boundary.reserve(p.boundary.size()); 
+ 
+ for(unsigned i = 0; i < p.boundary.size(); i++) { 
+ pr.boundary.push_back(p.boundary[i]*m); 
+ } 
+ return pr; 
+} 
+ 
+//TODO: reinstate 
+/*class ConvexCover{ 
+public: 
+ Path const* path; 
+ std::vector<ConvexHull> cc; 
+ 
+ ConvexCover(Path const &sp); 
+};*/ 
+ 
+}; 
+ 
+#endif //2GEOM_CONVEX_COVER_H 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(substatementopen . 0)) 
+ indenttabsmode:nil 
+ cbraceoffset:0 
+ fillcolumn:99 
+ End: 
+ vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : 
+*/ 
+ 
Index: Scribus/scribus/third_party/lib2geom/svgellipticalarc.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/svgellipticalarc.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/svgellipticalarc.h (revision 14937) 
@@ 0,0 +1,393 @@ 
+/* 
+ * SVG Elliptical Path Support Class 
+ * 
+ * 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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 _SVG_ELLIPTICAL_ARC_H_ 
+#define _SVG_ELLIPTICAL_ARC_H_ 
+ 
+ 
+#include "angle.h" 
+#include "matrix.h" 
+#include "sbasis.h" 
+#include "d2.h" 
+ 
+ 
+namespace Geom 
+{ 
+ 
+class EllipticalArc 
+{ 
+ public: 
+ EllipticalArc( Point _initial_point, Point _final_point, 
+ double _rx, double _ry, 
+ bool _large_arc, bool _sweep, 
+ double _rot_angle = 0.0 
+ ) 
+ : 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) 
+ { 
+ assert( (ray(X) >= 0) && (ray(Y) >= 0) ); 
+ if ( are_near(initialPoint(), finalPoint()) ) 
+ { 
+ m_start_angle = m_end_angle = 0; 
+ m_center = initialPoint(); 
+ } 
+ else 
+ { 
+ calculate_center_and_extreme_angles(); 
+ } 
+ 
+ std::cerr << "start_angle: " << decimal_round(rad_to_deg(m_start_angle),2) << " ( " << m_start_angle << " )" << std::endl 
+ << "end_angle: " << decimal_round(rad_to_deg(m_end_angle),2) << " ( " << m_end_angle << " )" << std::endl 
+ << "center: " << m_center << std::endl; 
+ } 
+ 
+ public: 
+ double center(Geom::Dim2 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(Geom::Dim2 i) const 
+ { 
+ return (i == 0) ? m_rx : m_ry; 
+ } 
+ 
+ bool large_arc_flag() const 
+ { 
+ return m_large_arc; 
+ } 
+ 
+// void large_arc_flag(bool v) 
+// { 
+// m_large_arc = v; 
+// } 
+ 
+ bool sweep_flag() const 
+ { 
+ return m_sweep; 
+ } 
+ 
+// void sweep_flag(bool v) 
+// { 
+// m_sweep = v; 
+// } 
+ 
+ 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(initialPoint(), finalPoint()); 
+ } 
+ 
+ double valueAt(Coord t, Dim2 d) const 
+ { 
+ Coord tt = from_01_to_02PI(t); 
+ double sin_rot_angle = std::sin(rotation_angle()); 
+ double cos_rot_angle = std::cos(rotation_angle()); 
+ if ( d == X ) 
+ { 
+ return ray(X) * cos_rot_angle * std::cos(tt) 
+  ray(Y) * sin_rot_angle * std::sin(tt) 
+ + center(X); 
+ } 
+ else 
+ { 
+ return ray(X) * sin_rot_angle * std::cos(tt) 
+ + ray(Y) * cos_rot_angle * std::sin(tt) 
+ + center(X); 
+ } 
+ } 
+ 
+ Point pointAt(Coord t) const 
+ { 
+ Coord tt = from_01_to_02PI(t); 
+ 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(tt), std::sin(tt) ); 
+ return p * m; 
+ } 
+ 
+ D2<SBasis> toSBasis() const 
+ { 
+ // the interval of parametrization has to be [0,1] 
+ Coord et = start_angle() + ( sweep_flag() ? sweep_angle() : sweep_angle() ); 
+ Linear param(start_angle(), et); 
+ // std::cerr << "param : " << param << std::endl; 
+ Coord cos_rot_angle = std::cos(rotation_angle()); 
+ Coord sin_rot_angle = std::sin(rotation_angle()); 
+ // order = 4 seems to be enough to get perfect looking elliptical arc 
+ // should it be choosen in function of the arc length anyway ? 
+ // a user settable parameter: toSBasis(unsigned int order) ? 
+ SBasis arc_x = ray(X) * cos(param,4); 
+ SBasis arc_y = ray(Y) * sin(param,4); 
+ D2<SBasis> arc; 
+ arc[0] = arc_x * cos_rot_angle  arc_y * sin_rot_angle + Linear(center(X),center(X)); 
+ arc[1] = arc_x * sin_rot_angle + arc_y * cos_rot_angle + Linear(center(Y),center(Y)); 
+ return arc; 
+ } 
+ 
+ std::pair<EllipticalArc, EllipticalArc> 
+ subdivide(Coord t) const 
+ { 
+ EllipticalArc* arc1 = portion(0, t); 
+ EllipticalArc* arc2 = portion(t, 1); 
+ assert( arc1 != NULL && arc2 != NULL); 
+ std::pair<EllipticalArc, EllipticalArc> arc_pair(*arc1, *arc2); 
+ delete arc1; 
+ delete arc2; 
+ return arc_pair; 
+ } 
+ 
+ EllipticalArc* portion(double f, double t) const 
+ { 
+ static const double M_2PI = 2*M_PI; 
+ EllipticalArc* arc = new EllipticalArc( *this ); 
+ arc>m_initial_point = pointAt(f); 
+ arc>m_final_point = pointAt(t); 
+ //std::cerr << "initial point: " << arc>m_initial_point << std::endl; 
+ //std::cerr << "final point: " << arc>m_final_point << std::endl; 
+ double sa = sweep_angle(); 
+ //std::cerr << "sa: " << sa << std::endl; 
+ arc>m_start_angle = m_start_angle + sa * f; 
+ if ( arc>m_start_angle > M_2PI  are_near(arc>m_start_angle, M_2PI) ) 
+ arc>m_start_angle = M_2PI; 
+ arc>m_end_angle = m_start_angle + sa * t; 
+ if ( arc>m_end_angle > M_2PI  are_near(arc>m_end_angle, M_2PI) ) 
+ arc>m_end_angle = M_2PI; 
+ //std::cerr << "start angle: " << arc>m_start_angle << std::endl; 
+ //std::cerr << "end angle: " << arc>m_end_angle << std::endl; 
+ //std::cerr << "sweep angle: " << arc>sweep_angle() << std::endl; 
+ if (f > t) arc>m_sweep = !m_sweep; 
+ if ( m_large_arc && (arc>sweep_angle() < M_PI) ) 
+ arc>m_large_arc = false; 
+ return arc; 
+ } 
+ 
+ // the arc is the same but traversed in the opposite direction 
+ EllipticalArc* 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; 
+ } 
+ 
+ private: 
+ 
+ double sweep_angle() const 
+ { 
+ Coord d = end_angle()  start_angle(); 
+ if ( !sweep_flag() ) d = d; 
+ if ( d < 0  are_near(d, 0) ) 
+ d += 2*M_PI; 
+ return d; 
+ } 
+ 
+ Coord from_01_to_02PI(Coord t) const 
+ { 
+ if ( sweep_flag() ) 
+ { 
+ Coord angle = start_angle() + sweep_angle() * t; 
+ if ( (angle > 2*M_PI)  are_near(angle, 2*M_PI) ) 
+ angle = 2*M_PI; 
+ return angle; 
+ } 
+ else 
+ { 
+ Coord angle = start_angle()  sweep_angle() * t; 
+ if ( angle < 0 ) angle += 2*M_PI; 
+ return angle; 
+ } 
+ } 
+ 
+ // NOTE: doesn't work with 360 deg arcs 
+ void calculate_center_and_extreme_angles() 
+ { 
+ const double M_HALF_PI = M_PI/2; 
+ const double M_2PI = 2*M_PI; 
+ 
+ double sin_rot_angle = std::sin(rotation_angle()); 
+ double cos_rot_angle = std::cos(rotation_angle()); 
+ 
+ Point sp = sweep_flag() ? initialPoint() : finalPoint(); 
+ Point ep = sweep_flag() ? finalPoint() : initialPoint(); 
+ 
+ Matrix m( ray(X) * cos_rot_angle, ray(X) * sin_rot_angle, 
+ ray(Y) * sin_rot_angle, ray(Y) * cos_rot_angle, 
+ 0, 0 ); 
+ Matrix im = m.inverse(); 
+ Point sol = (ep  sp) * im; 
+ std::cerr << "sol : " << sol << std::endl; 
+ double half_sum_angle = std::atan2(sol[X], sol[Y]); 
+ double half_diff_angle; 
+ if ( are_near(std::fabs(half_sum_angle), M_HALF_PI) ) 
+ { 
+ double anti_sgn_hsa = (half_sum_angle > 0) ? 1 : 1; 
+ double arg = anti_sgn_hsa * sol[X] / 2; 
+ // if arg is a little bit > 1 acos returns nan 
+ if ( are_near(arg, 1) ) 
+ half_diff_angle = 0; 
+ else if ( are_near(arg, 1) ) 
+ half_diff_angle = M_PI; 
+ else 
+ { 
+ assert( 1 < arg && arg < 1 ); 
+ // if it fails => there is no ellipse that satisfies the given constraints 
+ half_diff_angle = std::acos( arg ); 
+ } 
+ 
+ half_diff_angle = M_HALF_PI  half_diff_angle; 
+ } 
+ else 
+ { 
+ double arg = sol[Y] / ( 2 * std::cos(half_sum_angle) ); 
+ // if arg is a little bit > 1 asin returns nan 
+ if ( are_near(arg, 1) ) 
+ half_diff_angle = M_HALF_PI; 
+ else if ( are_near(arg, 1) ) 
+ half_diff_angle = M_HALF_PI; 
+ else 
+ { 
+ assert( 1 < arg && arg < 1 ); 
+ // if it fails => there is no ellipse that satisfies the given constraints 
+ half_diff_angle = std::asin( arg ); 
+ } 
+ } 
+ std::cerr << "half_sum_angle : " << decimal_round(rad_to_deg(half_sum_angle),2) << " ( " << half_sum_angle << " )" << std::endl; 
+ std::cerr << "half_diff_angle : " << decimal_round(rad_to_deg(half_diff_angle),2) << " ( " << half_diff_angle << " )" << std::endl; 
+ //std::cerr << "cos(half_sum_angle) : " << std::cos(half_sum_angle) << std::endl; 
+ //std::cerr << "sol[Y] / ( 2 * std::cos(half_sum_angle) ) : " << sol[Y] / ( 2 * std::cos(half_sum_angle) ) << std::endl; 
+ 
+ if ( ( m_large_arc && half_diff_angle > 0 ) 
+  (!m_large_arc && half_diff_angle < 0 ) ) 
+ { 
+ half_diff_angle = half_diff_angle; 
+ } 
+ if ( half_sum_angle < 0 ) half_sum_angle += M_2PI; 
+ if ( half_diff_angle < 0 ) half_diff_angle += M_PI; 
+ std::cerr << "half_sum_angle : " << decimal_round(rad_to_deg(half_sum_angle),2) << " ( " << half_sum_angle << " )" << std::endl; 
+ std::cerr << "half_diff_angle : " << decimal_round(rad_to_deg(half_diff_angle),2) << " ( " << half_diff_angle << " )" << std::endl; 
+ 
+ m_start_angle = half_sum_angle  half_diff_angle; 
+ m_end_angle = half_sum_angle + half_diff_angle; 
+ // 0 <= m_start_angle, m_end_angle < 2PI 
+ if ( m_start_angle < 0 ) m_start_angle += M_2PI; 
+ if ( m_end_angle > M_2PI  are_near(m_end_angle, M_2PI) ) m_end_angle = M_2PI; 
+ sol[0] = std::cos(m_start_angle); 
+ sol[1] = std::sin(m_start_angle); 
+ m_center = sp  sol * m; 
+ if ( !sweep_flag() ) 
+ { 
+ double angle = m_start_angle; 
+ m_start_angle = m_end_angle; 
+ m_end_angle = angle; 
+ } 
+ } 
+ 
+ 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; 
+}; 
+ 
+ 
+} 
+ 
+ 
+#endif /*_SVG_ELLIPTICAL_ARC_H_*/ 
+ 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/geom.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/geom.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/geom.cpp (revision 14937) 
@@ 0,0 +1,222 @@ 
+/** 
+ * \file src/geom.cpp 
+ * \brief Various geometrical calculations. 
+ */ 
+ 
+// #ifdef HAVE_CONFIG_H 
+// # include <config.h> 
+// #endif 
+#include "geom.h" 
+#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. 
+ * 
+ * If the two lines intersect, then \a result becomes their point of 
+ * intersection; otherwise, \a result remains unchanged. 
+ * 
+ * This function finds the intersection of the two lines (infinite) 
+ * defined by n0.X = d0 and x1.X = d1. The algorithm is as follows: 
+ * To compute the intersection point use kramer's rule: 
+ * \verbatim 
+ * convert lines to form 
+ * ax + by = c 
+ * dx + ey = f 
+ * 
+ * ( 
+ * e.g. a = (x2  x1), b = (y2  y1), c = (x2  x1)*x1 + (y2  y1)*y1 
+ * ) 
+ * 
+ * In our case we use: 
+ * a = n0.x d = n1.x 
+ * b = n0.y e = n1.y 
+ * c = d0 f = d1 
+ * 
+ * so: 
+ * 
+ * adx + bdy = cd 
+ * adx + aey = af 
+ * 
+ * bdy  aey = cd  af 
+ * (bd  ae)y = cd  af 
+ * 
+ * y = (cd  af)/(bd  ae) 
+ * 
+ * repeat for x and you get: 
+ * 
+ * x = (fb  ce)/(bd  ae) \endverbatim 
+ * 
+ * If the denominator (bdae) is 0 then the lines are parallel, if the 
+ * numerators are then 0 then the lines coincide. 
+ * 
+ * \todo Why not use existing but outcommented code below 
+ * (HAVE_NEW_INTERSECTOR_CODE)? 
+ */ 
+IntersectorKind 
+line_intersection(Geom::Point const &n0, double const d0, 
+ Geom::Point const &n1, double const d1, 
+ Geom::Point &result) 
+{ 
+ double denominator = dot(Geom::rot90(n0), n1); 
+ double X = n1[Geom::Y] * d0  
+ n0[Geom::Y] * d1; 
+ /* X = (d1, d0) dot (n0[Y], n1[Y]) */ 
+ 
+ if (denominator == 0) { 
+ if ( X == 0 ) { 
+ return coincident; 
+ } else { 
+ return parallel; 
+ } 
+ } 
+ 
+ double Y = n0[Geom::X] * d1  
+ n1[Geom::X] * d0; 
+ 
+ result = Geom::Point(X, Y) / denominator; 
+ 
+ return intersects; 
+} 
+ 
+ 
+ 
+ 
+/* ccw exists as a building block */ 
+int 
+intersector_ccw(const Geom::Point& p0, const Geom::Point& p1, 
+ const Geom::Point& p2) 
+/* Determine which way a set of three points winds. */ 
+{ 
+ Geom::Point d1 = p1  p0; 
+ Geom::Point d2 = p2  p0; 
+ /* compare slopes but avoid division operation */ 
+ double c = dot(Geom::rot90(d1), d2); 
+ if(c > 0) 
+ return +1; // ccw  do these match def'n in header? 
+ if(c < 0) 
+ return 1; // cw 
+ 
+ /* Colinear [or NaN]. Decide the order. */ 
+ if ( ( d1[0] * d2[0] < 0 )  
+ ( d1[1] * d2[1] < 0 ) ) { 
+ return 1; // p2 < p0 < p1 
+ } else if ( dot(d1,d1) < dot(d2,d2) ) { 
+ return +1; // p0 <= p1 < p2 
+ } else { 
+ return 0; // p0 <= p2 <= p1 
+ } 
+} 
+ 
+/** Determine whether two line segments intersect. This doesn't find 
+ the point of intersection, use the line_intersect function above, 
+ or the segment_intersection interface below. 
+ 
+ \pre neither segment is zerolength; i.e. p00 != p01 and p10 != p11. 
+*/ 
+static bool 
+segment_intersectp(Geom::Point const &p00, Geom::Point const &p01, 
+ Geom::Point const &p10, Geom::Point const &p11) 
+{ 
+ if(p00 == p01) return false; 
+ if(p10 == p11) return false; 
+ 
+ /* true iff ( (the p1 segment straddles the p0 infinite line) 
+ * and (the p0 segment straddles the p1 infinite line) ). */ 
+ return ((intersector_ccw(p00,p01, p10) 
+ *intersector_ccw(p00, p01, p11)) <=0 ) 
+ && 
+ ((intersector_ccw(p10,p11, p00) 
+ *intersector_ccw(p10, p11, p01)) <=0 ); 
+} 
+ 
+ 
+/** Determine whether \& where two line segments intersect. 
+ 
+If the two segments don't intersect, then \a result remains unchanged. 
+ 
+\pre neither segment is zerolength; i.e. p00 != p01 and p10 != p11. 
+**/ 
+IntersectorKind 
+segment_intersect(Geom::Point const &p00, Geom::Point const &p01, 
+ Geom::Point const &p10, Geom::Point const &p11, 
+ Geom::Point &result) 
+{ 
+ if(segment_intersectp(p00, p01, p10, p11)) { 
+ Geom::Point n0 = (p01  p00).ccw(); 
+ double d0 = dot(n0,p00); 
+ 
+ Geom::Point n1 = (p11  p10).ccw(); 
+ double d1 = dot(n1,p10); 
+ return line_intersection(n0, d0, n1, d1, result); 
+ } else { 
+ return no_intersection; 
+ } 
+} 
+ 
+/** Determine whether \& where two line segments intersect. 
+ 
+If the two segments don't intersect, then \a result remains unchanged. 
+ 
+\pre neither segment is zerolength; i.e. p00 != p01 and p10 != p11. 
+**/ 
+IntersectorKind 
+line_twopoint_intersect(Geom::Point const &p00, Geom::Point const &p01, 
+ Geom::Point const &p10, Geom::Point const &p11, 
+ Geom::Point &result) 
+{ 
+ Geom::Point n0 = (p01  p00).ccw(); 
+ double d0 = dot(n0,p00); 
+ 
+ Geom::Point n1 = (p11  p10).ccw(); 
+ double d1 = dot(n1,p10); 
+ return line_intersection(n0, d0, n1, d1, result); 
+} 
+ 
+/** 
+ * polyCentroid: Calculates the centroid (xCentroid, yCentroid) and area of a polygon, given its 
+ * vertices (x[0], y[0]) ... (x[n1], y[n1]). It is assumed that the contour is closed, i.e., that 
+ * the vertex following (x[n1], y[n1]) is (x[0], y[0]). The algebraic sign of the area is 
+ * positive for counterclockwise ordering of vertices in xy plane; otherwise negative. 
+ 
+ * Returned values: 
+ 0 for normal execution; 
+ 1 if the polygon is degenerate (number of vertices < 3); 
+ 2 if area = 0 (and the centroid is undefined). 
+ 
+ * for now we require the path to be a polyline and assume it is closed. 
+**/ 
+ 
+int centroid(std::vector<Geom::Point> p, Geom::Point& centroid, double &area) { 
+ const unsigned n = p.size(); 
+ if (n < 3) 
+ return 1; 
+ Geom::Point centroid_tmp(0,0); 
+ double atmp = 0; 
+ for (unsigned i = n1, j = 0; j < n; i = j, j++) { 
+ const double ai = cross(p[j], p[i]); 
+ atmp += ai; 
+ centroid_tmp += (p[j] + p[i])*ai; // first moment. 
+ } 
+ area = atmp / 2; 
+ if (atmp != 0) { 
+ centroid = centroid_tmp / (3 * atmp); 
+ return 0; 
+ } 
+ return 2; 
+} 
+ 
+} 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/d2sbasis.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/d2sbasis.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/d2sbasis.cpp (revision 14937) 
@@ 0,0 +1,132 @@ 
+#include "d2.h" 
+/* One would think that we would include d2sbasis.h, however, 
+ * you cannot actually include it in anything  only d2 may import it. 
+ * This is due to the trickinesses of template submatching. */ 
+ 
+namespace Geom { 
+ 
+SBasis L2(D2<SBasis> const & a, unsigned k) { return sqrt(dot(a, a), k); } 
+ 
+D2<SBasis> multiply(Linear const & a, D2<SBasis> const & b) { 
+ return D2<SBasis>(multiply(a, b[X]), multiply(a, b[Y])); 
+} 
+ 
+D2<SBasis> multiply(SBasis const & a, D2<SBasis> const & b) { 
+ return D2<SBasis>(multiply(a, b[X]), multiply(a, b[Y])); 
+} 
+ 
+D2<SBasis> truncate(D2<SBasis> const & a, unsigned terms) { 
+ return D2<SBasis>(truncate(a[X], terms), truncate(a[Y], terms)); 
+} 
+ 
+unsigned sbasis_size(D2<SBasis> const & a) { 
+ return std::max((unsigned) a[0].size(), (unsigned) a[1].size()); 
+} 
+ 
+//TODO: Is this sensical? shouldn't it be like pythagorean or something? 
+double tail_error(D2<SBasis> const & a, unsigned tail) { 
+ return std::max(a[0].tailError(tail), a[1].tailError(tail)); 
+} 
+ 
+Piecewise<D2<SBasis> > sectionize(D2<Piecewise<SBasis> > const &a) { 
+ Piecewise<SBasis> x = partition(a[0], a[1].cuts), y = partition(a[1], a[0].cuts); 
+ assert(x.size() == y.size()); 
+ Piecewise<D2<SBasis> > ret; 
+ for(unsigned i = 0; i < x.size(); i++) 
+ ret.push_seg(D2<SBasis>(x[i], y[i])); 
+ ret.cuts.insert(ret.cuts.end(), x.cuts.begin(), x.cuts.end()); 
+ return ret; 
+} 
+ 
+D2<Piecewise<SBasis> > make_cuts_independant(Piecewise<D2<SBasis> > const &a) { 
+ D2<Piecewise<SBasis> > ret; 
+ for(unsigned d = 0; d < 2; d++) { 
+ for(unsigned i = 0; i < a.size(); i++) 
+ ret[d].push_seg(a[i][d]); 
+ ret[d].cuts.insert(ret[d].cuts.end(), a.cuts.begin(), a.cuts.end()); 
+ } 
+ return ret; 
+} 
+ 
+Piecewise<D2<SBasis> > rot90(Piecewise<D2<SBasis> > const &M){ 
+ Piecewise<D2<SBasis> > result; 
+ if (M.empty()) return M; 
+ result.push_cut(M.cuts[0]); 
+ for (unsigned i=0; i<M.size(); i++){ 
+ result.push(rot90(M[i]),M.cuts[i+1]); 
+ } 
+ return result; 
+} 
+ 
+Piecewise<SBasis> dot(Piecewise<D2<SBasis> > const &a, 
+ Piecewise<D2<SBasis> > const &b){ 
+ Piecewise<SBasis > result; 
+ if (a.empty()  b.empty()) return result; 
+ Piecewise<D2<SBasis> > aa = partition(a,b.cuts); 
+ Piecewise<D2<SBasis> > bb = partition(b,a.cuts); 
+ 
+ result.push_cut(aa.cuts.front()); 
+ for (unsigned i=0; i<aa.size(); i++){ 
+ result.push(dot(aa.segs[i],bb.segs[i]),aa.cuts[i+1]); 
+ } 
+ return result; 
+} 
+ 
+Piecewise<SBasis> cross(Piecewise<D2<SBasis> > const &a, 
+ Piecewise<D2<SBasis> > const &b){ 
+ Piecewise<SBasis > result; 
+ if (a.empty()  b.empty()) return result; 
+ Piecewise<D2<SBasis> > aa = partition(a,b.cuts); 
+ Piecewise<D2<SBasis> > bb = partition(b,a.cuts); 
+ 
+ result.push_cut(aa.cuts.front()); 
+ for (unsigned i=0; i<a.size(); i++){ 
+ result.push(cross(aa.segs[i],bb.segs[i]),aa.cuts[i+1]); 
+ } 
+ return result; 
+} 
+ 
+Piecewise<D2<SBasis> > operator*(Piecewise<D2<SBasis> > const &a, Matrix const &m) { 
+ Piecewise<D2<SBasis> > result; 
+ if(a.empty()) return result; 
+ result.push_cut(a.cuts[0]); 
+ for (unsigned i = 0; i < a.size(); i++) { 
+ result.push(a[i] * m, a.cuts[i+1]); 
+ } 
+ return result; 
+} 
+ 
+//if tol>0, only force continuity where the jump is smaller than tol. 
+Piecewise<D2<SBasis> > force_continuity(Piecewise<D2<SBasis> > const &f, 
+ double tol, 
+ bool closed){ 
+ if (f.size()==0) return f; 
+ Piecewise<D2<SBasis> > result=f; 
+ unsigned cur = (closed)? 0:1; 
+ unsigned prev = (closed)? f.size()1:0; 
+ while(cur<f.size()){ 
+ Point pt0 = f.segs[prev].at1(); 
+ Point pt1 = f.segs[cur ].at0(); 
+ if (tol<=0  L2sq(pt0pt1)<tol*tol){ 
+ pt0 = (pt0+pt1)/2; 
+ for (unsigned dim=0; dim<2; dim++){ 
+ SBasis &prev_sb=result.segs[prev][dim]; 
+ SBasis &cur_sb =result.segs[cur][dim]; 
+ Coord const c=pt0[dim]; 
+ if (prev_sb.empty()) { 
+ prev_sb.push_back(Linear(0.0, c)); 
+ } else { 
+ prev_sb[0][1] = c; 
+ } 
+ if (cur_sb.empty()) { 
+ cur_sb.push_back(Linear(c, 0.0)); 
+ } else { 
+ cur_sb[0][0] = c; 
+ } 
+ } 
+ } 
+ prev = cur++; 
+ } 
+ return result; 
+} 
+} 
Index: Scribus/scribus/third_party/lib2geom/poly.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/poly.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/poly.h (revision 14937) 
@@ 0,0 +1,222 @@ 
+#ifndef SEEN_POLY_H 
+#define SEEN_POLY_H 
+#include <assert.h> 
+#include <vector> 
+#include <iostream> 
+#include <algorithm> 
+#include <complex> 
+#include "utils.h" 
+ 
+class Poly : public std::vector<double>{ 
+public: 
+ // coeff; // sum x^i*coeff[i] 
+ 
+ //unsigned size() const { return coeff.size();} 
+ unsigned degree() const { return size()1;} 
+ 
+ //double operator[](const int i) const { return (*this)[i];} 
+ //double& operator[](const int i) { return (*this)[i];} 
+ 
+ Poly operator+(const Poly& p) const { 
+ Poly result; 
+ const unsigned out_size = std::max(size(), p.size()); 
+ const unsigned min_size = std::min(size(), p.size()); 
+ //result.reserve(out_size); 
+ 
+ for(unsigned i = 0; i < min_size; i++) { 
+ result.push_back((*this)[i] + p[i]); 
+ } 
+ for(unsigned i = min_size; i < size(); i++) 
+ result.push_back((*this)[i]); 
+ for(unsigned i = min_size; i < p.size(); i++) 
+ result.push_back(p[i]); 
+ assert(result.size() == out_size); 
+ return result; 
+ } 
+ Poly operator(const Poly& p) const { 
+ Poly result; 
+ const unsigned out_size = std::max(size(), p.size()); 
+ const unsigned min_size = std::min(size(), p.size()); 
+ result.reserve(out_size); 
+ 
+ for(unsigned i = 0; i < min_size; i++) { 
+ result.push_back((*this)[i]  p[i]); 
+ } 
+ for(unsigned i = min_size; i < size(); i++) 
+ result.push_back((*this)[i]); 
+ for(unsigned i = min_size; i < p.size(); i++) 
+ result.push_back(p[i]); 
+ assert(result.size() == out_size); 
+ return result; 
+ } 
+ Poly operator=(const Poly& p) { 
+ const unsigned out_size = std::max(size(), p.size()); 
+ const unsigned min_size = std::min(size(), p.size()); 
+ resize(out_size); 
+ 
+ for(unsigned i = 0; i < min_size; i++) { 
+ (*this)[i] = p[i]; 
+ } 
+ for(unsigned i = min_size; i < out_size; i++) 
+ (*this)[i] = p[i]; 
+ return *this; 
+ } 
+ Poly operator(const double k) const { 
+ Poly result; 
+ const unsigned out_size = size(); 
+ result.reserve(out_size); 
+ 
+ for(unsigned i = 0; i < out_size; i++) { 
+ result.push_back((*this)[i]); 
+ } 
+ result[0] = k; 
+ return result; 
+ } 
+ Poly operator() const { 
+ Poly result; 
+ result.resize(size()); 
+ 
+ for(unsigned i = 0; i < size(); i++) { 
+ result[i] = (*this)[i]; 
+ } 
+ return result; 
+ } 
+ Poly operator*(const double p) const { 
+ Poly result; 
+ const unsigned out_size = size(); 
+ result.reserve(out_size); 
+ 
+ for(unsigned i = 0; i < out_size; i++) { 
+ result.push_back((*this)[i]*p); 
+ } 
+ assert(result.size() == out_size); 
+ return result; 
+ } 
+// equivalent to multiply by x^terms, discard negative terms 
+ Poly shifted(unsigned terms) const { 
+ Poly result; 
+ // This was a noop and breaks the build on x86_64, as it's trying 
+ // to take maximum of 32bit and 64bit integers 
+ //const unsigned out_size = std::max(unsigned(0), size()+terms); 
+ const size_type out_size = size() + terms; 
+ result.reserve(out_size); 
+ 
+ if(terms < 0) { 
+ for(unsigned i = 0; i < out_size; i++) { 
+ result.push_back((*this)[iterms]); 
+ } 
+ } else { 
+ for(unsigned i = 0; i < terms; i++) { 
+ result.push_back(0.0); 
+ } 
+ for(unsigned i = 0; i < size(); i++) { 
+ result.push_back((*this)[i]); 
+ } 
+ } 
+ 
+ assert(result.size() == out_size); 
+ return result; 
+ } 
+ Poly operator*(const Poly& p) const; 
+ 
+ template <typename T> 
+ T eval(T x) const { 
+ T r = 0; 
+ for(int k = size()1; k >= 0; k) { 
+ r = r*x + T((*this)[k]); 
+ } 
+ return r; 
+ } 
+ 
+ template <typename T> 
+ T operator()(T t) const { return (T)eval(t);} 
+ 
+ void normalize(); 
+ 
+ void monicify(); 
+ Poly() {} 
+ Poly(const Poly& p) : std::vector<double>(p) {} 
+ Poly(const double a) {push_back(a);} 
+ 
+public: 
+ template <class T, class U> 
+ void val_and_deriv(T x, U &pd) const { 
+ pd[0] = back(); 
+ int nc = size()  1; 
+ int nd = pd.size()  1; 
+ for(unsigned j = 1; j < pd.size(); j++) 
+ pd[j] = 0.0; 
+ for(int i = nc 1; i >= 0; i) { 
+ int nnd = std::min(nd, nci); 
+ for(int j = nnd; j >= 1; j) 
+ pd[j] = pd[j]*x + operator[](i); 
+ pd[0] = pd[0]*x + operator[](i); 
+ } 
+ double cnst = 1; 
+ for(int i = 2; i <= nd; i++) { 
+ cnst *= i; 
+ pd[i] *= cnst; 
+ } 
+ } 
+ 
+ static Poly linear(double ax, double b) { 
+ Poly p; 
+ p.push_back(b); 
+ p.push_back(ax); 
+ return p; 
+ } 
+}; 
+ 
+inline Poly operator*(double a, Poly const & b) { return b * a;} 
+ 
+Poly integral(Poly const & p); 
+Poly derivative(Poly const & p); 
+Poly divide_out_root(Poly const & p, double x); 
+Poly compose(Poly const & a, Poly const & b); 
+Poly divide(Poly const &a, Poly const &b, Poly &r); 
+Poly gcd(Poly const &a, Poly const &b, const double tol=1e10); 
+ 
+/*** solve(Poly p) 
+ * find all p.degree() roots of p. 
+ * This function can take a long time with suitably crafted polynomials, but in practice it should be fast. Should we provide special forms for degree() <= 4? 
+ */ 
+std::vector<std::complex<double> > solve(const Poly & p); 
+ 
+/*** solve_reals(Poly p) 
+ * find all real solutions to Poly p. 
+ * currently we just use solve and pick out the suitably real looking values, there may be a better algorithm. 
+ */ 
+std::vector<double> solve_reals(const Poly & p); 
+double polish_root(Poly const & p, double guess, double tol); 
+ 
+inline std::ostream &operator<< (std::ostream &out_file, const Poly &in_poly) { 
+ if(in_poly.size() == 0) 
+ out_file << "0"; 
+ else { 
+ for(int i = (int)in_poly.size()1; i >= 0; i) { 
+ if(i == 1) { 
+ out_file << "" << in_poly[i] << "*x"; 
+ out_file << " + "; 
+ } else if(i) { 
+ out_file << "" << in_poly[i] << "*x^" << i; 
+ out_file << " + "; 
+ } else 
+ out_file << in_poly[i]; 
+ 
+ } 
+ } 
+ return out_file; 
+} 
+ 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
+#endif 
Index: Scribus/scribus/third_party/lib2geom/region.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/region.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/region.h (revision 14937) 
@@ 0,0 +1,85 @@ 
+#ifndef __2GEOM_REGION_H 
+#define __2GEOM_REGION_H 
+ 
+#include "path.h" 
+#include "pathintersection.h" 
+ 
+namespace Geom { 
+ 
+class Shape; 
+ 
+class Region { 
+ friend Crossings crossings(Region const &a, Region const &b); 
+ friend class Shape; 
+ friend Shape shape_boolean(bool rev, Shape const & a, Shape const & b, CrossingSet const & crs); 
+ 
+ Path boundary; 
+ mutable boost::optional<Rect> box; 
+ bool fill; 
+ public: 
+ Region() : fill(true) {} 
+ explicit Region(Path const &p) : boundary(p) { fill = path_direction(p); } 
+ Region(Path const &p, bool dir) : boundary(p), fill(dir) {} 
+ Region(Path const &p, boost::optional<Rect> const &b) : boundary(p), box(b) { fill = path_direction(p); } 
+ Region(Path const &p, boost::optional<Rect> const &b, bool dir) : boundary(p), box(b), fill(dir) {} 
+ 
+ unsigned size() const { return boundary.size(); } 
+ 
+ bool isFill() const { return fill; } 
+ Region asFill() const { if(fill) return Region(*this); else return inverse(); } 
+ Region asHole() const { if(fill) return inverse(); else return Region(*this); } 
+ 
+ operator Path() const { return boundary; } 
+ Rect boundsFast() const { 
+ if(!box) box = boost::optional<Rect>(boundary.boundsFast()); 
+ return *box; 
+ } 
+ 
+ bool contains(Point const &p) const { 
+ if(box && !box>contains(p)) return false; 
+ return Geom::contains(boundary, p); 
+ } 
+ bool contains(Region const &other) const { return contains(other.boundary.initialPoint()); } 
+ 
+ bool includes(Point const &p) const { 
+ return logical_xor(!fill, contains(p)); 
+ } 
+ 
+ Region inverse() const { return Region(boundary.reverse(), box, !fill); } 
+ 
+ Region operator*(Matrix const &m) const; 
+ 
+ bool invariants() const; 
+}; 
+ 
+typedef std::vector<Region> Regions; 
+ 
+unsigned outer_index(Regions const &ps); 
+ 
+//assumes they're already sanitized somewhat 
+inline Regions regions_from_paths(std::vector<Path> const &ps) { 
+ Regions res; 
+ for(unsigned i = 0; i < ps.size(); i++) 
+ res.push_back(Region(ps[i])); 
+ return res; 
+} 
+ 
+inline std::vector<Path> paths_from_regions(Regions const &rs) { 
+ std::vector<Path> res; 
+ for(unsigned i = 0; i < rs.size(); i++) 
+ res.push_back(rs[i]); 
+ return res; 
+} 
+ 
+Regions sanitize_path(Path const &p); 
+ 
+Regions region_boolean(bool rev, Region const & a, Region const & b, Crossings const &cr); 
+Regions region_boolean(bool rev, Region const & a, Region const & b, Crossings const & cr_a, Crossings const & cr_b); 
+ 
+inline Regions region_boolean(bool rev, Region const & a, Region const & b) { 
+ return region_boolean(rev, a, b, crossings(a, b)); 
+} 
+ 
+} 
+ 
+#endif 
Index: Scribus/scribus/third_party/lib2geom/svgpath.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/svgpath.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/svgpath.cpp (revision 14937) 
@@ 0,0 +1,97 @@ 
+/* 
+ * callback interface for SVG path data 
+ * 
+ * Copyright 2007 MenTaLguY <mental@rydia.net> 
+ * 
+ * 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 COPYINGLGPL2.1; if not, output to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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 "sbasistobezier.h" 
+#include "svgpath.h" 
+ 
+namespace Geom { 
+ 
+void output(Curve const &curve, SVGPathSink &sink) { 
+ std::vector<Point> pts = sbasis_to_bezier(curve.toSBasis(), 2); //TODO: use something better! 
+ sink.curveTo(pts[0], pts[1], pts[2]); 
+} 
+ 
+void output(LineSegment const &curve, SVGPathSink &sink) { 
+ sink.lineTo(curve[1]); 
+} 
+ 
+void output(CubicBezier const &curve, SVGPathSink &sink) { 
+ sink.curveTo(curve[1], curve[2], curve[3]); 
+} 
+ 
+void output(QuadraticBezier const &curve, SVGPathSink &sink) { 
+ sink.quadTo(curve[1], curve[2]); 
+} 
+ 
+void output(SVGEllipticalArc const &curve, SVGPathSink &sink) { 
+ // FIXME 
+} 
+ 
+template <typename T> 
+bool output_as(Curve const &curve, SVGPathSink &sink) { 
+ T const *t = dynamic_cast<T const *>(&curve); 
+ if (t) { 
+ output(*t, sink); 
+ return true; 
+ } else { 
+ return false; 
+ } 
+} 
+ 
+void output_svg_path(Path &path, SVGPathSink &sink) { 
+ sink.moveTo(path.front().initialPoint()); 
+ 
+ Path::iterator iter; 
+ for ( iter = path.begin() ; iter != path.end() ; ++iter ) { 
+ output_as<LineSegment>(*iter, sink)  
+ output_as<CubicBezier>(*iter, sink)  
+ output_as<QuadraticBezier>(*iter, sink)  
+ output_as<SVGEllipticalArc>(*iter, sink)  
+ output_as<Curve>(*iter, sink); 
+ } 
+ 
+ if (path.closed()) { 
+ sink.closePath(); 
+ } 
+ sink.finish(); 
+} 
+ 
+} 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/ord.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/ord.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/ord.h (revision 14937) 
@@ 0,0 +1,37 @@ 
+ 
+#ifndef __2GEOM_ORD__ 
+#define __2GEOM_ORD__ 
+ 
+namespace { 
+ 
+enum Cmp { 
+ LESS_THAN=1, 
+ GREATER_THAN=1, 
+ EQUAL_TO=0 
+}; 
+ 
+inline Cmp operator(Cmp x) { 
+ switch(x) { 
+ case LESS_THAN: 
+ return GREATER_THAN; 
+ case GREATER_THAN: 
+ return LESS_THAN; 
+ case EQUAL_TO: 
+ return EQUAL_TO; 
+ } 
+} 
+ 
+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; 
+ } 
+} 
+ 
+} 
+ 
+#endif 
Index: Scribus/scribus/third_party/lib2geom/crossing.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/crossing.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/crossing.h (revision 14937) 
@@ 0,0 +1,146 @@ 
+#ifndef __GEOM_CROSSING_H 
+#define __GEOM_CROSSING_H 
+ 
+#include <vector> 
+#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 
+ unsigned a, b; //storage of indices 
+ Crossing() : dir(false), ta(0), tb(1), a(0), b(1) {} 
+ Crossing(double t_a, double t_b, bool direction) : dir(direction), ta(t_a), tb(t_b), a(0), b(1) {} 
+ 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; } 
+ bool onIx(unsigned ix) const { return a == ix  b == ix; } 
+}; 
+ 
+ 
+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 are_near(a, b); } }; 
+*/ 
+ 
+struct CrossingOrder { 
+ unsigned ix; 
+ CrossingOrder(unsigned i) : ix(i) {} 
+ bool operator()(Crossing a, Crossing b) { 
+ return (ix == a.a ? a.ta : a.tb) < 
+ (ix == b.a ? b.ta : b.tb); 
+ } 
+}; 
+ 
+ 
+typedef std::vector<Crossings> CrossingSet; 
+ 
+template<typename C> 
+std::vector<Rect> bounds(C const &a) { 
+ std::vector<Rect> rs; 
+ for(unsigned i = 0; i < a.size(); i++) rs.push_back(a[i].boundsFast()); 
+ return rs; 
+} 
+ 
+inline void sort_crossings(Crossings &cr, unsigned ix) { std::sort(cr.begin(), cr.end(), CrossingOrder(ix)); } 
+ 
+template<typename T> 
+struct Crosser { 
+ virtual ~Crosser() {} 
+ virtual Crossings crossings(T const &a, T const &b) { return crossings(std::vector<T>(1,a), std::vector<T>(1,b))[0]; } 
+ virtual CrossingSet crossings(std::vector<T> const &a, std::vector<T> const &b) { 
+ CrossingSet results(a.size() + b.size(), Crossings()); 
+ 
+ std::vector<std::vector<unsigned> > cull = sweep_bounds(bounds(a), bounds(b)); 
+ for(unsigned i = 0; i < cull.size(); i++) { 
+ for(unsigned jx = 0; jx < cull[i].size(); jx++) { 
+ unsigned j = cull[i][jx]; 
+ unsigned jc = j + a.size(); 
+ Crossings cr = crossings(a[i], b[j]); 
+ for(unsigned k = 0; k < cr.size(); k++) { cr[k].a = i; cr[k].b = jc; } 
+ 
+ //Sort & add Asorted crossings 
+ sort_crossings(cr, i); 
+ Crossings n(results[i].size() + cr.size()); 
+ std::merge(results[i].begin(), results[i].end(), cr.begin(), cr.end(), n.begin(), CrossingOrder(i)); 
+ results[i] = n; 
+ 
+ //Sort & add Bsorted crossings 
+ sort_crossings(cr, jc); 
+ n.resize(results[jc].size() + cr.size()); 
+ std::merge(results[jc].begin(), results[jc].end(), cr.begin(), cr.end(), n.begin(), CrossingOrder(jc)); 
+ results[jc] = n; 
+ } 
+ } 
+ return results; 
+ } 
+}; 
+void merge_crossings(Crossings &a, Crossings &b, unsigned i); 
+void offset_crossings(Crossings &cr, double a, double b); 
+ 
+Crossings reverse_ta(Crossings const &cr, std::vector<double> max); 
+Crossings reverse_tb(Crossings const &cr, unsigned split, std::vector<double> max); 
+CrossingSet reverse_ta(CrossingSet const &cr, unsigned split, std::vector<double> max); 
+CrossingSet reverse_tb(CrossingSet const &cr, unsigned split, std::vector<double> max); 
+ 
+void clean(Crossings &cr_a, Crossings &cr_b); 
+ 
+} 
+ 
+#endif 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/conjugate_gradient.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/conjugate_gradient.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/conjugate_gradient.h (revision 14937) 
@@ 0,0 +1,46 @@ 
+/* 
+ * conjugate_gradient.h 
+ * 
+ * Copyright 2006 Nathan Hurst <njh@mail.csse.monash.edu.au> 
+ * 
+ * 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 COPYINGLGPL2.1; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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 _CONJUGATE_GRADIENT_H 
+#define _CONJUGATE_GRADIENT_H 
+ 
+#include <valarray> 
+ 
+double 
+inner(std::valarray<double> const &x, 
+ std::valarray<double> const &y); 
+ 
+void 
+conjugate_gradient(std::valarray<double> const &A, 
+ std::valarray<double> &x, 
+ std::valarray<double> const &b, 
+ unsigned n, double tol, 
+ unsigned max_iterations, bool ortho1); 
+#endif // _CONJUGATE_GRADIENT_H 
Index: Scribus/scribus/third_party/lib2geom/rect.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/rect.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/rect.h (revision 14937) 
@@ 0,0 +1,169 @@ 
+/* 
+ * rect.h  D2<Interval> specialization to Rect 
+ * 
+ * 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 COPYINGLGPL2.1; if not, output to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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. 
+ * 
+ */ 
+ 
+/* Authors of original rect class: 
+ * Lauris Kaplinski <lauris@kaplinski.com> 
+ * Nathan Hurst <njh@mail.csse.monash.edu.au> 
+ * bulia byak <buliabyak@users.sf.net> 
+ * MenTaLguY <mental@rydia.net> 
+ */ 
+ 
+#ifdef _2GEOM_D2 /*This is intentional: we don't actually want anyone to 
+ include this, other than D2.h. If somone else tries, D2 
+ won't be defined. If it is, this will already be included. */ 
+#ifndef _2GEOM_RECT 
+#define _2GEOM_RECT 
+ 
+#include "matrix.h" 
+#include <boost/optional/optional.hpp> 
+ 
+namespace Geom { 
+ 
+typedef D2<Interval> Rect; 
+ 
+Rect unify(const Rect &, const Rect &); 
+ 
+template<> 
+class D2<Interval> { 
+ private: 
+ Interval f[2]; 
+ public: 
+ D2<Interval>() { f[X] = f[Y] = Interval(0, 0); } 
+ 
+ D2<Interval>(Interval const &a, Interval const &b) { 
+ f[X] = a; 
+ f[Y] = b; 
+ } 
+ 
+ D2<Interval>(Point const & a, Point const & b) { 
+ f[X] = Interval(a[X], b[X]); 
+ f[Y] = Interval(a[Y], b[Y]); 
+ } 
+ 
+ inline Interval& operator[](unsigned i) { return f[i]; } 
+ inline Interval const & operator[](unsigned i) const { return f[i]; } 
+ 
+ inline Point min() const { return Point(f[X].min(), f[Y].min()); } 
+ inline Point max() const { return Point(f[X].max(), f[Y].max()); } 
+ 
+ /** returns the four corners of the rectangle in positive order 
+ * (clockwise if +Y is up, anticlockwise if +Y is down) */ 
+ Point corner(unsigned i) const { 
+ switch(i % 4) { 
+ case 0: return Point(f[X].min(), f[Y].min()); 
+ case 1: return Point(f[X].max(), f[Y].min()); 
+ case 2: return Point(f[X].max(), f[Y].max()); 
+ default: return Point(f[X].min(), f[Y].max()); 
+ } 
+ } 
+ 
+ //We should probably remove these  they're coord sys gnostic 
+ inline double top() const { return f[Y].min(); } 
+ inline double bottom() const { return f[Y].max(); } 
+ inline double left() const { return f[X].min(); } 
+ inline double right() const { return f[X].max(); } 
+ 
+ inline double width() const { return f[X].extent(); } 
+ inline double height() const { return f[Y].extent(); } 
+ 
+ /** returns a vector from min to max. */ 
+ inline Point dimensions() const { return Point(f[X].extent(), f[Y].extent()); } 
+ inline Point midpoint() const { return Point(f[X].middle(), f[Y].middle()); } 
+ 
+ inline double area() const { return f[X].extent() * f[Y].extent(); } 
+ inline double maxExtent() const { return std::max(f[X].extent(), f[Y].extent()); } 
+ 
+ inline bool isEmpty() const { 
+ return f[X].isEmpty() && f[Y].isEmpty(); 
+ } 
+ inline bool intersects(Rect const &r) const { 
+ return f[X].intersects(r[X]) && f[Y].intersects(r[Y]); 
+ } 
+ inline bool contains(Rect const &r) const { 
+ return f[X].contains(r[X]) && f[Y].contains(r[Y]); 
+ } 
+ inline bool contains(Point const &p) const { 
+ return f[X].contains(p[X]) && f[Y].contains(p[Y]); 
+ } 
+ 
+ inline void expandTo(Point p) { 
+ f[X].extendTo(p[X]); f[Y].extendTo(p[Y]); 
+ } 
+ inline void unionWith(Rect const &b) { 
+ f[X].unionWith(b[X]); f[Y].unionWith(b[Y]); 
+ } 
+ 
+ inline void expandBy(double amnt) { 
+ f[X].expandBy(amnt); f[Y].expandBy(amnt); 
+ } 
+ inline void expandBy(Point const p) { 
+ f[X].expandBy(p[X]); f[Y].expandBy(p[Y]); 
+ } 
+ 
+ /** Transforms the rect by m. Note that it gives correct results only for scales and translates, 
+ in the case of rotations, the area of the rect will grow as it cannot rotate. */ 
+ inline Rect operator*(Matrix const m) const { 
+ return unify(Rect(corner(0) * m, corner(2) * m), 
+ Rect(corner(1) * m, corner(3) * m)); 
+ } 
+}; 
+ 
+inline Rect unify(Rect const & a, Rect const & b) { 
+ return Rect(unify(a[X], b[X]), unify(a[Y], b[Y])); 
+} 
+ 
+inline Rect union_list(std::vector<Rect> const &r) { 
+ if(r.empty()) return Rect(Interval(0,0), Interval(0,0)); 
+ Rect ret = r[0]; 
+ for(unsigned i = 1; i < r.size(); i++) 
+ ret.unionWith(r[i]); 
+ return ret; 
+} 
+ 
+inline boost::optional<Rect> intersect(Rect const & a, Rect const & b) { 
+ boost::optional<Interval> x = intersect(a[X], b[X]); 
+ boost::optional<Interval> y = intersect(a[Y], b[Y]); 
+ return x && y ? boost::optional<Rect>(Rect(*x, *y)) : boost::optional<Rect>(); 
+} 
+ 
+} 
+ 
+#endif //_2GEOM_RECT 
+#endif //_2GEOM_D2 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/sbasisgeometric.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/sbasisgeometric.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/sbasisgeometric.h (revision 14937) 
@@ 0,0 +1,83 @@ 
+#ifndef _SBASIS_GEOMETRIC 
+#define _SBASIS_GEOMETRIC 
+#include "d2.h" 
+#include "piecewise.h" 
+#include <vector> 
+ 
+/** twodimensional geometric operators. 
+ * Copyright 2007, JFBarraud 
+ * Copyright 2007, njh 
+ * 
+ * These operators are built on a more 'polynomially robust' 
+ * transformation to map a function that takes a [0,1] parameter to a 
+ * 2d vector into a function that takes the same [0,1] parameter to a 
+ * unit vector with the same direction. 
+ * 
+ * Rather that using (X/sqrt(X))(t) which involves two unstable 
+ * operations, sqrt and divide, this approach forms a curve directly 
+ * from the various tangent directions at each end (angular jet). As 
+ * a result, the final path has a convergence behaviour derived from 
+ * that of the sin and cos series.  njh 
+ */ 
+ 
+namespace Geom{ 
+ 
+Piecewise<D2<SBasis> > 
+cutAtRoots(Piecewise<D2<SBasis> > const &M, double tol=1e4); 
+ 
+Piecewise<SBasis> 
+atan2(D2<SBasis> const &vect, 
+ double tol=.01, unsigned order=3); 
+ 
+Piecewise<SBasis> 
+atan2(Piecewise<D2<SBasis> >const &vect, 
+ double tol=.01, unsigned order=3); 
+ 
+Piecewise<D2<SBasis> > 
+unitVector(D2<SBasis> const &vect, 
+ double tol=.01, unsigned order=3); 
+Piecewise<D2<SBasis> > 
+unitVector(Piecewise<D2<SBasis> > const &vect, 
+ double tol=.01, unsigned order=3); 
+ 
+// Piecewise<D2<SBasis> > 
+// uniform_speed(D2<SBasis> const M, 
+// double tol=.1); 
+ 
+Piecewise<SBasis> curvature( D2<SBasis> const &M, double tol=.01); 
+Piecewise<SBasis> curvature(Piecewise<D2<SBasis> > const &M, double tol=.01); 
+ 
+Piecewise<SBasis> arcLengthSb( D2<SBasis> const &M, double tol=.01); 
+Piecewise<SBasis> arcLengthSb(Piecewise<D2<SBasis> > const &M, double tol=.01); 
+ 
+double length( D2<SBasis> const &M, double tol=.01); 
+double length(Piecewise<D2<SBasis> > const &M, double tol=.01); 
+ 
+Piecewise<D2<SBasis> > 
+arc_length_parametrization(D2<SBasis> const &M, 
+ unsigned order=3, 
+ double tol=.01); 
+Piecewise<D2<SBasis> > 
+arc_length_parametrization(Piecewise<D2<SBasis> > const &M, 
+ unsigned order=3, 
+ double tol=.01); 
+ 
+ 
+unsigned centroid(Piecewise<D2<SBasis> > const &p, Point& centroid, double &area); 
+ 
+}; 
+ 
+#endif 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
+ 
+ 
Index: Scribus/scribus/third_party/lib2geom/shape.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/shape.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/shape.h (revision 14937) 
@@ 0,0 +1,102 @@ 
+#ifndef __2GEOM_SHAPE_H 
+#define __2GEOM_SHAPE_H 
+ 
+#include <vector> 
+#include <set> 
+ 
+#include "region.h" 
+ 
+//TODO: BBOX optimizations 
+ 
+namespace Geom { 
+ 
+enum { 
+ BOOLOP_JUST_A = 1, 
+ BOOLOP_JUST_B = 2, 
+ BOOLOP_BOTH = 4, 
+ BOOLOP_NEITHER = 8 
+}; 
+ 
+enum { 
+ BOOLOP_NULL = 0, 
+ BOOLOP_INTERSECT = BOOLOP_BOTH, 
+ BOOLOP_SUBTRACT_A_B = BOOLOP_JUST_B, 
+ BOOLOP_IDENTITY_A = BOOLOP_JUST_A  BOOLOP_BOTH, 
+ BOOLOP_SUBTRACT_B_A = BOOLOP_JUST_A, 
+ BOOLOP_IDENTITY_B = BOOLOP_JUST_B  BOOLOP_BOTH, 
+ BOOLOP_EXCLUSION = BOOLOP_JUST_A  BOOLOP_JUST_B, 
+ BOOLOP_UNION = BOOLOP_JUST_A  BOOLOP_JUST_B  BOOLOP_BOTH 
+}; 
+ 
+class Shape { 
+ Regions content; 
+ mutable bool fill; 
+ //friend Shape shape_region_boolean(bool rev, Shape const & a, Region const & b); 
+ friend CrossingSet crossings_between(Shape const &a, Shape const &b); 
+ friend Shape shape_boolean(bool rev, Shape const &, Shape const &, CrossingSet const &); 
+ friend Shape boolop(Shape const &a, Shape const &b, unsigned); 
+ friend Shape boolop(Shape const &a, Shape const &b, unsigned, CrossingSet const &); 
+ friend void add_to_shape(Shape &s, Path const &p, bool); 
+ public: 
+ Shape() : fill(true) {} 
+ explicit Shape(Region const & r) { 
+ content = Regions(1, r); 
+ fill = r.fill; 
+ } 
+ explicit Shape(Regions const & r) : content(r) { update_fill(); } 
+ explicit Shape(bool f) : fill(f) {} 
+ Shape(Regions const & r, bool f) : content(r), fill(f) {} 
+ 
+ Regions getContent() const { return content; } 
+ bool isFill() const { return fill; } 
+ 
+ unsigned size() const { return content.size(); } 
+ const Region &operator[](unsigned ix) const { return content[ix]; } 
+ 
+ Shape inverse() const; 
+ Shape operator*(Matrix const &m) const; 
+ 
+ bool contains(Point const &p) const; 
+ 
+ bool inside_invariants() const; //semislow & easy to violate : checks that the insides are inside, the outsides are outside 
+ bool region_invariants() const; //semislow : checks for self crossing 
+ bool cross_invariants() const; //slow : checks that everything is disjoint 
+ bool invariants() const; //vera slow (combo, checks the above) 
+ 
+ private: 
+ std::vector<unsigned> containment_list(Point p) const; 
+ void update_fill() const { 
+ unsigned ix = outer_index(content); 
+ if(ix < size()) 
+ fill = content[ix].fill; 
+ else if(size() > 0) 
+ fill = content.front().fill; 
+ else 
+ fill = true; 
+ } 
+}; 
+ 
+inline CrossingSet crossings_between(Shape const &a, Shape const &b) { return crossings(paths_from_regions(a.content), paths_from_regions(b.content)); } 
+ 
+Shape shape_boolean(bool rev, Shape const &, Shape const &, CrossingSet const &); 
+Shape shape_boolean(bool rev, Shape const &, Shape const &); 
+ 
+//unsigned pick_coincident(unsigned ix, unsigned jx, bool &rev, std::vector<Path> const &ps, CrossingSet const &crs); 
+//void outer_crossing(unsigned &ix, unsigned &jx, bool & dir, std::vector<Path> const & ps, CrossingSet const & crs); 
+void crossing_dual(unsigned &i, unsigned &j, CrossingSet const & crs); 
+unsigned crossing_along(double t, unsigned ix, unsigned jx, bool dir, Crossings const & crs); 
+ 
+Shape boolop(Shape const &, Shape const &, unsigned flags); 
+Shape boolop(Shape const &, Shape const &, unsigned flags, CrossingSet &); 
+ 
+Shape sanitize(std::vector<Path> const &ps); 
+ 
+Shape stopgap_cleaner(std::vector<Path> const &ps); 
+ 
+inline std::vector<Path> desanitize(Shape const & s) { 
+ return paths_from_regions(s.getContent()); 
+} 
+ 
+} 
+ 
+#endif 
Index: Scribus/scribus/third_party/lib2geom/sbasispoly.cpp 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/sbasispoly.cpp (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/sbasispoly.cpp (revision 14937) 
@@ 0,0 +1,47 @@ 
+#include "sbasispoly.h" 
+ 
+namespace Geom{ 
+ 
+SBasis poly_to_sbasis(Poly const & p) { 
+ SBasis x = Linear(0, 1); 
+ SBasis r; 
+ 
+ for(int i = p.size()1; i >= 0; i) { 
+ r = SBasis(Linear(p[i], p[i])) + multiply(x, r); 
+ } 
+ r.normalize(); 
+ return r; 
+ 
+} 
+ 
+Poly sbasis_to_poly(SBasis const & sb) { 
+ if(sb.isZero()) 
+ return Poly(); 
+ Poly S; // (1x)x = 1*x^2 + 1*x + 0 
+ Poly A, B; 
+ B.push_back(0); 
+ B.push_back(1); 
+ A.push_back(1); 
+ A.push_back(1); 
+ S = A*B; 
+ Poly r; 
+ 
+ for(int i = sb.size()1; i >= 0; i) { 
+ r = S*r + sb[i][0]*A + sb[i][1]*B; 
+ } 
+ r.normalize(); 
+ return r; 
+} 
+ 
+}; 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/matrix.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/matrix.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/matrix.h (revision 14937) 
@@ 0,0 +1,161 @@ 
+#ifndef __Geom_MATRIX_H__ 
+#define __Geom_MATRIX_H__ 
+ 
+/** \file 
+ * Definition of Geom::Matrix types. 
+ * 
+ * Main authors: 
+ * Lauris Kaplinski <lauris@kaplinski.com>: 
+ * Original NRMatrix definition and related macros. 
+ * 
+ * Nathan Hurst <njh@mail.csse.monash.edu.au>: 
+ * Geom::Matrix class version of the above. 
+ * 
+ * Michael G. Sloan <mgsloan@gmail.com>: 
+ * Reorganization and additions. 
+ * 
+ * This code is in public domain. 
+ */ 
+ 
+//#include <glib/gmessages.h> 
+ 
+#include "point.h" 
+ 
+namespace Geom { 
+ 
+/** 
+ * The Matrix class. 
+ * 
+ * For purposes of multiplication, points should be thought of as row vectors 
+ * 
+ * \f$(p_X p_Y 1)\f$ 
+ * 
+ * to be rightmultiplied by transformation matrices of the form 
+ * \f[ 
+ \left[ 
+ \begin{array}{ccc} 
+ c_0&c_1&0 \\ 
+ c_2&c_3&0 \\ 
+ c_4&c_5&1 
+ \end{array} 
+ \right] 
+ \f] 
+ * (so the columns of the matrix correspond to the columns (elements) of the result, 
+ * and the rows of the matrix correspond to columns (elements) of the "input"). 
+ */ 
+class Matrix { 
+ private: 
+ Coord _c[6]; 
+ public: 
+ Matrix() {} 
+ 
+ Matrix(Matrix const &m) { 
+ for(int i = 0; i < 6; i++) { 
+ _c[i] = m[i]; 
+ } 
+ } 
+ 
+ Matrix(Coord c0, Coord c1, Coord c2, Coord c3, Coord c4, Coord c5) { 
+ _c[0] = c0; _c[1] = c1; 
+ _c[2] = c2; _c[3] = c3; 
+ _c[4] = c4; _c[5] = c5; 
+ } 
+ 
+ Matrix &operator=(Matrix const &m) { 
+ for(int i = 0; i < 6; i++) 
+ _c[i] = m._c[i]; 
+ return *this; 
+ } 
+ 
+ inline Coord operator[](unsigned const i) const { return _c[i]; } 
+ inline Coord &operator[](unsigned const i) { return _c[i]; } 
+ 
+ 
+ Point xAxis() const; 
+ Point yAxis() const; 
+ Point translation() const; 
+ void setXAxis(Point const &vec); 
+ void setYAxis(Point const &vec); 
+ void setTranslation(Point const &loc); 
+ 
+ double expansionX() const; 
+ double expansionY() const; 
+ void setExpansionX(double val); 
+ void setExpansionY(double val); 
+ 
+ void setIdentity(); 
+ 
+ bool isIdentity(Coord eps = EPSILON) const; 
+ bool isTranslation(Coord eps = EPSILON) const; 
+ bool isRotation(double eps = EPSILON) const; 
+ bool isScale(double eps = EPSILON) const; 
+ bool isUniformScale(double eps = EPSILON) const; 
+ bool onlyScaleAndTranslation(double eps = EPSILON) const; 
+ 
+ bool flips() const; 
+ 
+ Matrix without_translation() const; 
+ 
+ Matrix inverse() const; 
+ 
+ Coord det() const; 
+ Coord descrim2() const; 
+ Coord descrim() const; 
+}; 
+ 
+Matrix operator*(Matrix const &a, Matrix const &b); 
+ 
+/** A function to print out the Matrix (for debugging) */ 
+inline std::ostream &operator<< (std::ostream &out_file, const Geom::Matrix &m) { 
+ out_file << "A: " << m[0] << " C: " << m[2] << " E: " << m[4] << "\n"; 
+ out_file << "B: " << m[1] << " D: " << m[3] << " F: " << m[5] << "\n"; 
+ return out_file; 
+} 
+ 
+/** Given a matrix m such that unit_circle = m*x, this returns the 
+ * quadratic form x*A*x = 1. */ 
+Matrix elliptic_quadratic_form(Matrix const &m); 
+ 
+/** Given a matrix (ignoring the translation) this returns the eigen 
+ * values and vectors. */ 
+class Eigen{ 
+public: 
+ Point vectors[2]; 
+ double values[2]; 
+ Eigen(Matrix const &m); 
+}; 
+ 
+// Matrix factories 
+Matrix from_basis(const Point x_basis, const Point y_basis, const Point offset=Point(0,0)); 
+ 
+/** Returns the Identity Matrix. */ 
+inline Matrix identity() { 
+ return Matrix(1.0, 0.0, 
+ 0.0, 1.0, 
+ 0.0, 0.0); 
+} 
+ 
+inline bool operator==(Matrix const &a, Matrix const &b) { 
+ for(unsigned i = 0; i < 6; ++i) { 
+ if ( a[i] != b[i] ) return false; 
+ } 
+ return true; 
+} 
+inline bool operator!=(Matrix const &a, Matrix const &b) { return !( a == b ); } 
+ 
+ 
+ 
+} /* namespace Geom */ 
+ 
+#endif /* !__Geom_MATRIX_H__ */ 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
Index: Scribus/scribus/third_party/lib2geom/d2.h 
=================================================================== 
 Scribus/scribus/third_party/lib2geom/d2.h (nonexistent) 
+++ Scribus/scribus/third_party/lib2geom/d2.h (revision 14937) 
@@ 0,0 +1,409 @@ 
+/* 
+ * d2.h  Lifts one dimensional objects into 2d 
+ * 
+ * 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 COPYINGLGPL2.1; if not, output to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021111307 USA 
+ * You should have received a copy of the MPL along with this library 
+ * in the file COPYINGMPL1.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_D2 //If this is change, change the guard in rect.h as well. 
+#define _2GEOM_D2 
+ 
+#include "point.h" 
+#include "interval.h" 
+#include "matrix.h" 
+ 
+#include <boost/concept_check.hpp> 
+#include "concepts.h" 
+ 
+namespace Geom{ 
+ 
+template <class T> 
+class D2{ 
+ //BOOST_CLASS_REQUIRE(T, boost, AssignableConcept); 
+ private: 
+ T f[2]; 
+ 
+ public: 
+ D2() {f[X] = f[Y] = T();} 
+ explicit D2(Point const &a) { 
+ f[X] = T(a[X]); f[Y] = T(a[Y]); 
+ } 
+ 
+ D2(T const &a, T const &b) { 
+ f[X] = a; 
+ f[Y] = b; 
+ } 
+ 
+ //TODO: ask mental about operator= as seen in Point 
+ 
+ T& operator[](unsigned i) { return f[i]; } 
+ T const & operator[](unsigned i) const { return f[i]; } 
+ 
+ //IMPL: FragmentConcept 
+ typedef Point output_type; 
+ bool isZero() const { 
+ boost::function_requires<FragmentConcept<T> >(); 
+ return f[X].isZero() && f[Y].isZero(); 
+ } 
+ bool isConstant() const { 
+ boost::function_requires<FragmentConcept<T> >(); 
+ return f[X].isConstant() && f[Y].isConstant(); 
+ } 
+ bool isFinite() const { 
+ boost::function_requires<FragmentConcept<T> >(); 
+ return f[X].isFinite() && f[Y].isFinite(); 
+ } 
+ Point at0() const { 
+ boost::function_requires<FragmentConcept<T> >(); 
+ return Point(f[X].at0(), f[Y].at0()); 
+ } 
+ Point at1() const { 
+ boost::function_requires<FragmentConcept<T> >(); 
+ return Point(f[X].at1(), f[Y].at1()); 
+ } 
+ Point valueAt(double t) const { 
+ boost::function_requires<FragmentConcept<T> >(); 
+ return (*this)(t); 
+ } 
+ std::vector<Point > valueAndDerivatives(double t, unsigned count) const { 
+ std::vector<Coord> x = f[X].valueAndDerivatives(t, count), 
+ y = f[Y].valueAndDerivatives(t, count); 
+ std::vector<Point> res; 
+ for(unsigned i = 0; i < count; i++) { 
+ res.push_back(Point(x[i], y[i])); 
+ } 
+ return res; 
+ } 
+ D2<SBasis> toSBasis() const { 
+ boost::function_requires<FragmentConcept<T> >(); 
+ return D2<SBasis>(f[X].toSBasis(), f[Y].toSBasis()); 
+ } 
+ 
+ Point operator()(double t) const; 
+ Point operator()(double x, double y) const; 
+}; 
+template <typename T> 
+inline D2<T> reverse(const D2<T> &a) { 
+ boost::function_requires<FragmentConcept<T> >(); 
+ return D2<T>(reverse(a[X]), reverse(a[Y])); 
+} 
+ 
+template <typename T> 
+inline D2<T> portion(const D2<T> &a, Coord f, Coord t) { 
+ boost::function_requires<FragmentConcept<T> >(); 
+ return D2<T>(portion(a[X], f, t), portion(a[Y], f, t)); 
+} 
+ 
+//IMPL: boost::EqualityComparableConcept 
+template <typename T> 
+inline bool 
+operator==(D2<T> const &a, D2<T> const &b) { 
+ boost::function_requires<boost::EqualityComparableConcept<T> >(); 
+ return a[0]==b[0] && a[1]==b[1]; 
+} 
+template <typename T> 
+inline bool 
+operator!=(D2<T> const &a, D2<T> const &b) { 
+ boost::function_requires<boost::EqualityComparableConcept<T> >(); 
+ return a[0]!=b[0]  a[1]!=b[1]; 
+} 
+ 
+//IMPL: NearConcept 
+template <typename T> 
+inline bool 
+are_near(D2<T> const &a, D2<T> const &b, double tol) { 
+ boost::function_requires<NearConcept<T> >(); 
+ return are_near(a[0], b[0]) && are_near(a[1], b[1]); 
+} 
+ 
+//IMPL: AddableConcept 
+template <typename T> 
+inline D2<T> 
+operator+(D2<T> const &a, D2<T> const &b) { 
+ boost::function_requires<AddableConcept<T> >(); 
+ 
+ D2<T> r; 
+ for(unsigned i = 0; i < 2; i++) 
+ r[i] = a[i] + b[i]; 
+ return r; 
+} 
+template <typename T> 
+inline D2<T> 
+operator(D2<T> const &a, D2<T> const &b) { 
+ boost::function_requires<AddableConcept<T> >(); 
+ 
+ D2<T> r; 
+ for(unsigned i = 0; i < 2; i++) 
+ r[i] = a[i]  b[i]; 
+ return r; 
+} 
+template <typename T> 
+inline D2<T> 
+operator+=(D2<T> &a, D2<T> const &b) { 
+ boost::function_requires<AddableConcept<T> >(); 
+ 
+ for(unsigned i = 0; i < 2; i++) 
+ a[i] += b[i]; 
+ return a; 
+} 
+template <typename T> 
+inline D2<T> 
+operator=(D2<T> &a, D2<T> const & b) { 
+ boost::function_requires<AddableConcept<T> >(); 
+ 
+ for(unsigned i = 0; i < 2; i++) 
+ a[i] = b[i]; 
+ return a; 
+} 
+ 
+//IMPL: ScalableConcept 
+template <typename T> 
+inline D2<T> 
+operator(D2<T> const & a) { 
+ boost::function_requires<ScalableConcept<T> >(); 
+ D2<T> r; 
+ for(unsigned i = 0; i < 2; i++) 
+ r[i] = a[i]; 
+ return r; 
+} 
+template <typename T> 
+inline D2<T> 
+operator*(D2<T> const & a, Point const & b) { 
+ boost::function_requires<ScalableConcept<T> >(); 
+ 
+ D2<T> r; 
+ for(unsigned i = 0; i < 2; i++) 
+ r[i] = a[i] * b[i]; 
+ return r; 
+} 
+template <typename T> 
+inline D2<T> 
+operator/(D2<T> const & a, Point const & b) { 
+ boost::function_requires<ScalableConcept<T> >(); 
+ //TODO: b==0? 
+ D2<T> r; 
+ for(unsigned i = 0; i < 2; i++) 
+ r[i] = a[i] / b[i]; 
+ return r; 
+} 
+template <typename T> 
+inline D2<T> 
+operator*=(D2<T> &a, Point const & b) { 
+ boost::function_requires<ScalableConcept<T> >(); 
+ 
+ for(unsigned i = 0; i < 2; i++) 
+ a[i] *= b[i]; 
+ return a; 
+} 
+template <typename T> 
+inline D2<T> 
+operator/=(D2<T> &a, Point const & b) { 
+ boost::function_requires<ScalableConcept<T> >(); 
+ //TODO: b==0? 
+ for(unsigned i = 0; i < 2; i++) 
+ a[i] /= b[i]; 
+ return a; 
+} 
+ 
+template <typename T> 
+inline D2<T> operator*(D2<T> const & a, double b) { return D2<T>(a[0]*b, a[1]*b); } 
+template <typename T> 
+inline D2<T> operator*=(D2<T> & a, double b) { a[0] *= b; a[1] *= b; return a; } 
+template <typename T> 
+inline D2<T> operator/(D2<T> const & a, double b) { return D2<T>(a[0]/b, a[1]/b); } 
+template <typename T> 
+inline D2<T> operator/=(D2<T> & a, double b) { a[0] /= b; a[1] /= b; return a; } 
+ 
+template<typename T> 
+D2<T> operator*(D2<T> const &v, Matrix const &m) { 
+ boost::function_requires<AddableConcept<T> >(); 
+ boost::function_requires<ScalableConcept<T> >(); 
+ D2<T> ret; 
+ for(unsigned i = 0; i < 2; i++) 
+ ret[i] = v[X] * m[i] + v[Y] * m[i + 2] + m[i + 4]; 
+ return ret; 
+} 
+ 
+//IMPL: OffsetableConcept 
+template <typename T> 
+inline D2<T> 
+operator+(D2<T> const & a, Point b) { 
+ boost::function_requires<OffsetableConcept<T> >(); 
+ D2<T> r; 
+ for(unsigned i = 0; i < 2; i++) 
+ r[i] = a[i] + b[i]; 
+ return r; 
+} 
+template <typename T> 
+inline D2<T> 
+operator(D2<T> const & a, Point b) { 
+ boost::function_requires<OffsetableConcept<T> >(); 
+ D2<T> r; 
+ for(unsigned i = 0; i < 2; i++) 
+ r[i] = a[i]  b[i]; 
+ return r; 
+} 
+template <typename T> 
+inline D2<T> 
+operator+=(D2<T> & a, Point b) { 
+ boost::function_requires<OffsetableConcept<T> >(); 
+ for(unsigned i = 0; i < 2; i++) 
+ a[i] += b[i]; 
+ return a; 
+} 
+template <typename T> 
+inline D2<T> 
+operator=(D2<T> & a, Point b) { 
+ boost::function_requires<OffsetableConcept<T> >(); 
+ for(unsigned i = 0; i < 2; i++) 
+ a[i] = b[i]; 
+ return a; 
+} 
+ 
+template <typename T> 
+inline T 
+dot(D2<T> const & a, D2<T> const & b) { 
+ boost::function_requires<AddableConcept<T> >(); 
+ boost::function_requires<MultiplicableConcept<T> >(); 
+ 
+ T r; 
+ for(unsigned i = 0; i < 2; i++) 
+ r += a[i] * b[i]; 
+ return r; 
+} 
+ 
+template <typename T> 
+inline T 
+cross(D2<T> const & a, D2<T> const & b) { 
+ boost::function_requires<ScalableConcept<T> >(); 
+ boost::function_requires<MultiplicableConcept<T> >(); 
+ 
+ return a[1] * b[0]  a[0] * b[1]; 
+} 
+ 
+ 
+//equivalent to cw/ccw, for use in situations where rotation direction doesn't matter. 
+template <typename T> 
+inline D2<T> 
+rot90(D2<T> const & a) { 
+ boost::function_requires<ScalableConcept<T> >(); 
+ return D2<T>(a[Y], a[X]); 
+} 
+ 
+//TODO: concepterize the following functions 
+template <typename T> 
+inline D2<T> 
+compose(D2<T> const & a, T const & b) { 
+ D2<T> r; 
+ for(unsigned i = 0; i < 2; i++) 
+ r[i] = compose(a[i],b); 
+ return r; 
+} 
+ 
+template <typename T> 
+inline D2<T> 
+compose_each(D2<T> const & a, D2<T> const & b) { 
+ D2<T> r; 
+ for(unsigned i = 0; i < 2; i++) 
+ r[i] = compose(a[i],b[i]); 
+ return r; 
+} 
+ 
+template <typename T> 
+inline D2<T> 
+compose_each(T const & a, D2<T> const & b) { 
+ D2<T> r; 
+ for(unsigned i = 0; i < 2; i++) 
+ r[i] = compose(a,b[i]); 
+ return r; 
+} 
+ 
+ 
+template<typename T> 
+inline Point 
+D2<T>::operator()(double t) const { 
+ Point p; 
+ for(unsigned i = 0; i < 2; i++) 
+ p[i] = (*this)[i](t); 
+ return p; 
+} 
+ 
+//TODO: we might want to have this take a Point as the parameter. 
+template<typename T> 
+inline Point 
+D2<T>::operator()(double x, double y) const { 
+ Point p; 
+ for(unsigned i = 0; i < 2; i++) 
+ p[i] = (*this)[i](x, y); 
+ return p; 
+} 
+ 
+ 
+template<typename T> 
+D2<T> derivative(D2<T> const & a) { 
+ return D2<T>(derivative(a[X]), derivative(a[Y])); 
+} 
+template<typename T> 
+D2<T> integral(D2<T> const & a) { 
+ return D2<T>(integral(a[X]), integral(a[Y])); 
+} 
+ 
+} //end namespace Geom 
+ 
+#include "rect.h" 
+#include "d2sbasis.h" 
+ 
+namespace Geom{ 
+ 
+//Some D2 Fragment implementation which requires rect: 
+template <typename T> 
+Rect bounds_fast(const D2<T> &a) { 
+ boost::function_requires<FragmentConcept<T> >(); 
+ return Rect(bounds_fast(a[X]), bounds_fast(a[Y])); 
+} 
+template <typename T> 
+Rect bounds_exact(const D2<T> &a) { 
+ boost::function_requires<FragmentConcept<T> >(); 
+ return Rect(bounds_exact(a[X]), bounds_exact(a[Y])); 
+} 
+template <typename T> 
+Rect bounds_local(const D2<T> &a, const Interval &t) { 
+ boost::function_requires<FragmentConcept<T> >(); 
+ return Rect(bounds_local(a[X], t), bounds_local(a[Y], t)); 
+} 
+}; 
+ 
+/* 
+ Local Variables: 
+ mode:c++ 
+ cfilestyle:"stroustrup" 
+ cfileoffsets:((innamespace . 0)(inlineopen . 0)(caselabel . +)) 
+ indenttabsmode:nil 
+ fillcolumn:99 
+ End: 
+*/ 
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf8:textwidth=99 : 
+#endif 
Index: Scribus/scribus/third_party/lib2geom/polydksolve.h 
=================================================================== 
 Scribus/scribus/th 
