Subversion Repositories Scribus

Compare Revisions

Ignore whitespace Rev 15346 → Rev 15347

/trunk/Scribus/scribus/third_party/lib2geom/doxygen.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/conic_section_clipper_cr.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/line.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/nearest-point.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/conicsec.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/curve.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/curves.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/conic_section_clipper_impl.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/conic_section_clipper.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/ellipse.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/toposweep.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/bezier-curve.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/intersection-by-smashing.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/nearest-point.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/affine.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/line.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/conic_section_clipper_impl.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/arc-length.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/conicsec.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/ellipse.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/rtree.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/nearestpoint.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/redblacktree.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/chebyshev.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/pathvector.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/hvlinesegment.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/toposweep.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/pathvector.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/chebyshev.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/redblacktree.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/numeric/linear_system.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/numeric/matrix.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/numeric/fitting-tool.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/numeric/symmetric-matrix-fs-trace.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/numeric/symmetric-matrix-fs-operation.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/numeric/fitting-model.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/numeric/vector.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/numeric/symmetric-matrix-fs.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/numeric/matrix.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/intersection-by-smashing.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/svg-elliptical-arc.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/math-utils.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/recursive-bezier-intersection.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/linear-of.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/intersection-by-bezier-clipping.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/affine.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/bezier-clipping.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/sbasis-of.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/circle.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/arc-length.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/bezier-curve.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/sbasis-curve.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/conic_section_clipper.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/svg-path-parser.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/circle.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/elliptical-arc.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/rtree.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/ray.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/forward.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/utils.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/elliptical-arc.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/svg-path-parser.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/curve.cpp
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/linearN.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/sbasisN.h
File deleted
/trunk/Scribus/scribus/third_party/lib2geom/path.h
1,12 → 1,7
/**
* \file
* \brief Path - Series of continuous curves
/*
* Path - Series of continuous curves
*
* Authors:
* MenTaLguY <mental@rydia.net>
* Marco Cecchetti <mrcekets at gmail.com>
*
* Copyright 2007-2008 authors
* 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
32,317 → 27,513
* 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 {
 
#ifndef SEEN_GEOM_PATH_H
#define SEEN_GEOM_PATH_H
class Curve;
 
struct CurveHelpers {
protected:
static int root_winding(Curve const &c, Point p);
};
 
#include <boost/shared_ptr.hpp>
#include "curve.h"
#include "bezier-curve.h"
class Curve : private CurveHelpers {
public:
virtual ~Curve() {}
 
#include <iterator>
#include <algorithm>
virtual Point initialPoint() const = 0;
virtual Point finalPoint() const = 0;
 
virtual bool isDegenerate() const = 0;
 
namespace Geom
{
virtual Curve *duplicate() const = 0;
 
class Path;
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); }
 
namespace PathInternal {
virtual std::vector<double> roots(double v, Dim2 d) const = 0;
 
typedef std::vector<boost::shared_ptr<Curve const> > Sequence;
virtual int winding(Point p) const { return root_winding(*this, p); }
 
template <typename C, typename P>
class BaseIterator {
protected:
BaseIterator() : path(NULL), index(0) {}
BaseIterator(P *p, unsigned i) : path(p), index(i) {}
// default copy, default assign
//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:
bool operator==(BaseIterator const &other) {
return path == other.path && index == other.index;
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);
}
bool operator!=(BaseIterator const &other) {
return path != other.path || index != other.index;
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 const &operator*() const { return (*path)[index]; }
Curve const *operator->() const { return &(*path)[index]; }
boost::shared_ptr<Curve const> get_ref() const {
return path->get_ref_at_index(index);
Curve *transformed(Matrix const &m) const {
return new SBasisCurve(inner * m);
}
 
C &operator++() {
++index;
return static_cast<C &>(*this);
Curve *derivative() const {
return new SBasisCurve(Geom::derivative(inner));
}
C operator++(int) {
C old(static_cast<C &>(*this));
++(*this);
return old;
 
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)) {
}
 
C &operator--() {
--index;
return static_cast<C &>(*this);
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]);
}
C operator--(int) {
C old(static_cast<C &>(*this));
--(*this);
return old;
 
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]);
}
 
private:
P *path;
unsigned index;
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]);
}
 
friend class ::Geom::Path;
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<order-1>(Geom::derivative(inner[X]), Geom::derivative(inner[Y]));
else if (order == 1) {
double dx = inner[X][1] - inner[X][0], dy = inner[Y][1] - inner[Y][0];
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);
}
};
 
class ConstIterator : public BaseIterator<ConstIterator, Path const> {
// 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:
typedef BaseIterator<ConstIterator, Path const> Base;
SVGEllipticalArc() {}
 
ConstIterator() : Base() {}
// default copy, default assign
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:
ConstIterator(Path const &p, unsigned i) : Base(&p, i) {}
friend class ::Geom::Path;
Point initial_;
double rx_;
double ry_;
double x_axis_rotation_;
bool large_arc_;
bool sweep_;
Point final_;
};
 
class Iterator : public BaseIterator<Iterator, Path> {
template <typename IteratorImpl>
class BaseIterator
: public std::iterator<std::forward_iterator_tag, Curve const>
{
public:
typedef BaseIterator<Iterator, Path> Base;
BaseIterator() {}
 
Iterator() : Base() {}
// default copy, default assign
// default construct
// default copy
 
operator ConstIterator const &() const {
return reinterpret_cast<ConstIterator const &>(*this);
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:
Iterator(Path &p, unsigned i) : Base(&p, i) {}
friend class ::Geom::Path;
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) {}
 
/*
* Open and closed paths: all paths, whether open or closed, store a final
* segment which connects the initial and final endpoints of the "real"
* path data. While similar to the "z" in an SVG path, it exists for
* both open and closed paths, and is not considered part of the "normal"
* path data, which is always covered by the range [begin(), end_open()).
* Conversely, the range [begin(), end_closed()) always contains the "extra"
* closing segment.
*
* The only difference between a closed and an open path is whether
* end_default() returns end_closed() or end_open(). The idea behind this
* is to let any path be stroked using [begin(), end_default()), and filled
* using [begin(), end_closed()), without requiring a separate "filled" version
* of the path to use for filling.
*
* \invariant : curves_ always contains at least one segment. The last segment
* is always of type ClosingSegment. All constructors take care of this.
(curves_.size() > 0) && dynamic_cast<ClosingSegment>(curves_.back())
*/
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 PathInternal::Sequence Sequence;
typedef PathInternal::Iterator iterator;
typedef PathInternal::ConstIterator const_iterator;
typedef BaseIterator<Sequence::iterator> iterator;
typedef BaseIterator<Sequence::const_iterator> const_iterator;
typedef Sequence::size_type size_type;
typedef Sequence::difference_type difference_type;
 
class ClosingSegment : public LineSegment {
public:
ClosingSegment() : LineSegment() {}
ClosingSegment(Point const &p1, Point const &p2) : LineSegment(p1, p2) {}
virtual Curve *duplicate() const { return new ClosingSegment(*this); }
virtual Curve *reverse() const { return new ClosingSegment((*this)[1], (*this)[0]); }
};
Path()
: final_(new LineSegment()), closed_(false)
{
curves_.push_back(final_);
}
 
enum Stitching {
NO_STITCHING=0,
STITCH_DISCONTINUOUS
};
 
class StitchSegment : public LineSegment {
public:
StitchSegment() : LineSegment() {}
StitchSegment(Point const &p1, Point const &p2) : LineSegment(p1, p2) {}
virtual Curve *duplicate() const { return new StitchSegment(*this); }
virtual Curve *reverse() const { return new StitchSegment((*this)[1], (*this)[0]); }
};
 
// Path(Path const &other) - use default copy constructor
 
explicit Path(Point p=Point())
: curves_(boost::shared_ptr<Sequence>(new Sequence(1, boost::shared_ptr<Curve>()))),
final_(new ClosingSegment(p, p)),
closed_(false)
Path(Path const &other)
: final_(new LineSegment()), closed_(other.closed_)
{
get_curves().back() = boost::shared_ptr<Curve>(final_);
curves_.push_back(final_);
insert(begin(), other.begin(), other.end());
}
 
Path(const_iterator const &first,
const_iterator const &last,
bool closed=false)
: curves_(boost::shared_ptr<Sequence>(new Sequence(seq_iter(first),
seq_iter(last)))),
closed_(closed)
explicit Path(Point p)
: final_(new LineSegment(p, p)), closed_(false)
{
if (!get_curves().empty()) {
final_ = new ClosingSegment(get_curves().back()->finalPoint(),
get_curves().front()->initialPoint());
} else {
final_ = new ClosingSegment();
}
get_curves().push_back(boost::shared_ptr<Curve>(final_));
curves_.push_back(final_);
}
 
virtual ~Path() {}
// Path &operator=(Path const &other) - use default assignment operator
 
void swap(Path &other) {
std::swap(other.curves_, curves_);
std::swap(other.final_, final_);
std::swap(other.closed_, closed_);
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);
}
 
Curve const &operator[](unsigned i) const { return *get_curves()[i]; }
Curve const &at_index(unsigned i) const { return *get_curves()[i]; }
boost::shared_ptr<Curve const> get_ref_at_index(unsigned i) {
return get_curves()[i];
virtual ~Path() {
delete_range(curves_.begin(), curves_.end()-1);
delete final_;
}
 
Curve const &front() const { return *get_curves()[0]; }
Curve const &back() const { return back_open(); }
Curve const &back_open() const {
if (empty()) { THROW_RANGEERROR("Path contains not enough segments"); }
return *get_curves()[get_curves().size()-2];
Path &operator=(Path const &other) {
clear();
insert(begin(), other.begin(), other.end());
close(other.closed_);
return *this;
}
Curve const &back_closed() const { return *get_curves()[get_curves().size()-1]; }
Curve const &back_default() const {
return ( closed_ ? back_closed() : back_open() );
}
 
const_iterator begin() const { return const_iterator(*this, 0); }
const_iterator end() const { return const_iterator(*this, size()); }
iterator begin() { return iterator(*this, 0); }
iterator end() { return iterator(*this, size()); }
void swap(Path &other);
 
const_iterator end_open() const { return const_iterator(*this, size()); }
const_iterator end_closed() const { return const_iterator(*this, size()+1); }
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_open() const { return get_curves().size()-1; }
size_type size_closed() const { return get_curves().size(); }
size_type size_default() const {
return ( closed_ ? size_closed() : size_open() );
}
size_type size() const { return size_open(); }
size_type size() const { return curves_.size()-1; }
size_type max_size() const { return curves_.max_size()-1; }
 
size_type max_size() const { return get_curves().max_size()-1; }
 
bool empty() const { return (get_curves().size() == 1); }
bool empty() const { return curves_.size() == 1; }
bool closed() const { return closed_; }
void close(bool closed=true) { closed_ = closed; }
 
OptRect boundsFast() const;
OptRect boundsExact() const;
Rect boundsFast() const;
Rect boundsExact() const;
 
Piecewise<D2<SBasis> > toPwSb() const {
Piecewise<D2<SBasis> > ret;
ret.push_cut(0);
unsigned i = 1;
bool degenerate = true;
// pw<d2<>> is always open. so if path is closed, add closing segment as well to pwd2.
for(const_iterator it = begin(); it != end_default(); ++it) {
// 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++);
degenerate = false;
}
}
if (degenerate) {
// if path only contains degenerate curves, no second cut is added
// so we need to create at least one segment manually
ret = Piecewise<D2<SBasis> >(initialPoint());
}
return ret;
}
 
bool operator==(Path const &other) const {
if (this == &other) return true;
if (closed_ != other.closed_) return false;
return get_curves() == other.get_curves();
}
bool operator!=(Path const &other) const {
return !( *this == other );
}
 
Path operator*(Affine const &m) const {
Path ret(*this);
ret *= m;
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;
}
 
Path &operator*=(Affine const &m);
Point pointAt(double t) const
{
unsigned int sz = size();
if ( closed() ) ++sz;
if ( t < 0 || t > sz )
{
THROW_RANGEERROR("parameter t out of bounds");
}
if ( empty() ) return initialPoint(); // naked moveto
double k, lt = modf(t, &k);
unsigned int i = static_cast<unsigned int>(k);
if ( i == sz )
{
--i;
lt = 1;
}
return (*this)[i].pointAt(lt);
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
{
unsigned int sz = size();
if ( closed() ) ++sz;
if ( t < 0 || t > sz )
{
THROW_RANGEERROR("parameter t out of bounds");
}
if ( empty() ) return initialPoint()[d]; // naked moveto
double k, lt = modf(t, &k);
unsigned int i = static_cast<unsigned int>(k);
if ( i == sz )
{
--i;
lt = 1;
}
return (*this)[i].valueAt(lt, d);
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);
}
 
Point operator() (double t) const
{
return pointAt(t);
}
std::vector<double> roots(double v, Dim2 d) const {
std::vector<double> res;
for(unsigned i = 0; i <= size(); i++) {
352,30 → 543,7
}
return res;
}
std::vector<double>
allNearestPoints(Point const& _point, double from, double to) const;
std::vector<double>
allNearestPoints(Point const& _point) const
{
unsigned int sz = size();
if ( closed() ) ++sz;
return allNearestPoints(_point, 0, sz);
}
std::vector<double>
nearestPointPerCurve(Point const& _point) const;
double nearestPoint(Point const& _point, double from, double to, double *distance_squared = NULL) const;
double nearestPoint(Point const& _point, double *distance_squared = NULL) const
{
unsigned int sz = size();
if ( closed() ) ++sz;
return nearestPoint(_point, 0, sz, distance_squared);
}
 
void appendPortionTo(Path &p, double f, double t) const;
 
Path portion(double f, double t) const {
387,132 → 555,104
Path portion(Interval i) const { return portion(i.min(), i.max()); }
 
Path reverse() const {
Path ret(*this);
ret.unshare();
for ( Sequence::iterator iter = ret.get_curves().begin() ;
iter != ret.get_curves().end()-1 ; ++iter )
{
*iter = boost::shared_ptr<Curve>((*iter)->reverse());
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;
}
std::reverse(ret.get_curves().begin(), ret.get_curves().end()-1);
ret.final_ = static_cast<ClosingSegment *>(ret.final_->reverse());
ret.get_curves().back() = boost::shared_ptr<Curve>(ret.final_);
return ret;
}
 
void insert(iterator const &pos,
Curve const &curve, Stitching stitching=NO_STITCHING)
{
unshare();
Sequence::iterator seq_pos(seq_iter(pos));
Sequence source(1, boost::shared_ptr<Curve>(curve.duplicate()));
if (stitching) stitch(seq_pos, seq_pos, source);
do_update(seq_pos, seq_pos, source.begin(), source.end());
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;
}
}
 
void insert(iterator const &pos,
const_iterator const &first,
const_iterator const &last,
Stitching stitching=NO_STITCHING)
template <typename Impl>
void insert(iterator pos, BaseIterator<Impl> first, BaseIterator<Impl> last)
{
unshare();
Sequence::iterator seq_pos(seq_iter(pos));
Sequence source(seq_iter(first), seq_iter(last));
if (stitching) stitch(seq_pos, seq_pos, source);
do_update(seq_pos, seq_pos, source.begin(), source.end());
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() {
unshare();
do_update(get_curves().begin(), get_curves().end()-1,
get_curves().begin(), get_curves().begin());
do_update(curves_.begin(), curves_.end()-1,
curves_.begin(), curves_.begin());
}
 
void erase(iterator const &pos, Stitching stitching=NO_STITCHING) {
unshare();
Sequence::iterator seq_pos(seq_iter(pos));
if (stitching) {
Sequence stitched;
stitch(seq_pos, seq_pos+1, stitched);
do_update(seq_pos, seq_pos+1, stitched.begin(), stitched.end());
} else {
do_update(seq_pos, seq_pos+1, get_curves().begin(), get_curves().begin());
}
void erase(iterator pos) {
do_update(pos.impl_, pos.impl_+1, curves_.begin(), curves_.begin());
}
 
void erase(iterator const &first,
iterator const &last,
Stitching stitching=NO_STITCHING)
{
unshare();
Sequence::iterator seq_first=seq_iter(first);
Sequence::iterator seq_last=seq_iter(last);
if (stitching) {
Sequence stitched;
stitch(seq_first, seq_last, stitched);
do_update(seq_first, seq_last, stitched.begin(), stitched.end());
} else {
do_update(seq_first, seq_last,
get_curves().begin(), get_curves().begin());
}
void erase(iterator first, iterator last) {
do_update(first.impl_, last.impl_, curves_.begin(), curves_.begin());
}
 
// erase last segment of path
void erase_last() {
erase(iterator(*this, size()-1));
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 const &replaced,
Curve const &curve,
Stitching stitching=NO_STITCHING)
void replace(iterator first_replaced, iterator last_replaced,
Curve const &curve)
{
unshare();
Sequence::iterator seq_replaced(seq_iter(replaced));
Sequence source(1, boost::shared_ptr<Curve>(curve.duplicate()));
if (stitching) stitch(seq_replaced, seq_replaced+1, source);
do_update(seq_replaced, seq_replaced+1, source.begin(), source.end());
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;
}
}
 
void replace(iterator const &first_replaced,
iterator const &last_replaced,
Curve const &curve, Stitching stitching=NO_STITCHING)
template <typename Impl>
void replace(iterator replaced,
BaseIterator<Impl> first, BaseIterator<Impl> last)
{
unshare();
Sequence::iterator seq_first_replaced(seq_iter(first_replaced));
Sequence::iterator seq_last_replaced(seq_iter(last_replaced));
Sequence source(1, boost::shared_ptr<Curve>(curve.duplicate()));
if (stitching) stitch(seq_first_replaced, seq_last_replaced, source);
do_update(seq_first_replaced, seq_last_replaced,
source.begin(), source.end());
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;
}
}
 
void replace(iterator const &replaced,
const_iterator const &first,
const_iterator const &last,
Stitching stitching=NO_STITCHING)
template <typename Impl>
void replace(iterator first_replaced, iterator last_replaced,
BaseIterator<Impl> first, BaseIterator<Impl> last)
{
unshare();
Sequence::iterator seq_replaced(seq_iter(replaced));
Sequence source(seq_iter(first), seq_iter(last));
if (stitching) stitch(seq_replaced, seq_replaced+1, source);
do_update(seq_replaced, seq_replaced+1, source.begin(), source.end());
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 replace(iterator const &first_replaced,
iterator const &last_replaced,
const_iterator const &first,
const_iterator const &last,
Stitching stitching=NO_STITCHING)
{
unshare();
Sequence::iterator seq_first_replaced(seq_iter(first_replaced));
Sequence::iterator seq_last_replaced(seq_iter(last_replaced));
Sequence source(seq_iter(first), seq_iter(last));
if (stitching) stitch(seq_first_replaced, seq_last_replaced, source);
do_update(seq_first_replaced, seq_last_replaced,
source.begin(), source.end());
}
 
void start(Point p) {
clear();
final_->setPoint(0, p);
522,92 → 662,40
Point initialPoint() const { return (*final_)[1]; }
Point finalPoint() const { return (*final_)[0]; }
 
void setInitial(Point const& p)
{
if ( empty() ) return;
unshare();
boost::shared_ptr<Curve> head(front().duplicate());
head->setInitial(p);
Sequence::iterator replaced = get_curves().begin();
Sequence source(1, head);
do_update(replaced, replaced + 1, source.begin(), source.end());
}
void append(Curve const &curve);
void append(D2<SBasis> const &curve);
 
void setFinal(Point const& p)
{
if ( empty() ) return;
unshare();
boost::shared_ptr<Curve> tail(back().duplicate());
tail->setFinal(p);
Sequence::iterator replaced = get_curves().end() - 2;
Sequence source(1, tail);
do_update(replaced, replaced + 1, source.begin(), source.end());
}
 
void append(Curve const &curve, Stitching stitching=NO_STITCHING) {
unshare();
if (stitching) stitchTo(curve.initialPoint());
do_append(curve.duplicate());
}
void append(D2<SBasis> const &curve, Stitching stitching=NO_STITCHING) {
unshare();
if (stitching) stitchTo(Point(curve[X][0][0], curve[Y][0][0]));
do_append(new SBasisCurve(curve));
}
void append(Path const &other, Stitching stitching=NO_STITCHING) {
insert(end(), other.begin(), other.end(), stitching);
}
 
void stitchTo(Point const &p) {
if (!empty() && finalPoint() != p) {
unshare();
do_append(new StitchSegment(finalPoint(), p));
}
}
 
 
/**
* It is important to note that the coordinates passed to appendNew should be finite!
* If one of the coordinates is infinite, 2geom will throw a ContinuityError exception.
*/
 
template <typename CurveType, typename A>
void appendNew(A a) {
unshare();
do_append(new CurveType(finalPoint(), a));
do_append(new CurveType((*final_)[0], a));
}
 
template <typename CurveType, typename A, typename B>
void appendNew(A a, B b) {
unshare();
do_append(new CurveType(finalPoint(), a, 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) {
unshare();
do_append(new CurveType(finalPoint(), a, b, 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) {
unshare();
do_append(new CurveType(finalPoint(), a, b, c, 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) {
unshare();
do_append(new CurveType(finalPoint(), a, b, c, d, 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) {
unshare();
do_append(new CurveType(finalPoint(), a, b, c, d, e, f));
do_append(new CurveType((*final_)[0], a, b, c, d, e, f));
}
 
template <typename CurveType, typename A, typename B, typename C,
614,8 → 702,7
typename D, typename E, typename F,
typename G>
void appendNew(A a, B b, C c, D d, E e, F f, G g) {
unshare();
do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g));
do_append(new CurveType((*final_)[0], a, b, c, d, e, f, g));
}
 
template <typename CurveType, typename A, typename B, typename C,
622,8 → 709,7
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) {
unshare();
do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g, h));
do_append(new CurveType((*final_)[0], a, b, c, d, e, f, g, h));
}
 
template <typename CurveType, typename A, typename B, typename C,
630,52 → 716,28
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) {
unshare();
do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g, h, i));
do_append(new CurveType((*final_)[0], a, b, c, d, e, f, g, h, i));
}
 
private:
static Sequence::iterator seq_iter(iterator const &iter) {
return iter.path->get_curves().begin() + iter.index;
}
static Sequence::const_iterator seq_iter(const_iterator const &iter) {
return iter.path->get_curves().begin() + iter.index;
}
 
Sequence &get_curves() { return *curves_; }
Sequence const &get_curves() const { return *curves_; }
 
void unshare() {
if (!curves_.unique()) {
curves_ = boost::shared_ptr<Sequence>(new Sequence(*curves_));
}
if (!get_curves().back().unique()) {
final_ = static_cast<ClosingSegment *>(final_->duplicate());
get_curves().back() = boost::shared_ptr<Curve>(final_);
}
}
 
void stitch(Sequence::iterator first_replaced,
Sequence::iterator last_replaced,
Sequence &sequence);
 
void do_update(Sequence::iterator first_replaced,
Sequence::iterator last_replaced,
Sequence::iterator first,
Sequence::iterator last);
 
// n.b. takes ownership of curve object
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);
 
boost::shared_ptr<Sequence> curves_;
ClosingSegment *final_;
Sequence curves_;
LineSegment *final_;
bool closed_;
}; // end class Path
};
 
inline static Piecewise<D2<SBasis> > paths_to_pw(std::vector<Path> paths) {
Piecewise<D2<SBasis> > ret = paths[0].toPwSb();
685,14 → 747,55
return ret;
}
 
inline
Coord nearest_point(Point const& p, Path const& c)
{
return c.nearestPoint(p);
/*
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;
 
};
*/
 
}
 
} // end namespace Geom
 
namespace std {
 
template <>
701,20 → 804,18
a.swap(b);
}
 
} // end namespace std
}
 
#endif // SEEN_GEOM_PATH_H
 
 
 
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
c-file-offsets:((innamespace . 0)(substatement-open . 0))
indent-tabs-mode:nil
c-brace-offset:0
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
// vim: filetype=cpp:expandtab:shiftwidth=2:tabstop=8:softtabstop=2 :
/trunk/Scribus/scribus/third_party/lib2geom/utils.h
1,9 → 1,7
#ifndef LIB2GEOM_UTILS_HEADER
#define LIB2GEOM_UTILS_HEADER
 
/**
* \file
* \brief Various utility functions.
/** Various utility functions.
*
* Copyright 2007 Johan Engelen <goejendaagh@zonnet.nl>
* Copyright 2006 Michael G. Sloan <mgsloan@gmail.com>
33,8 → 31,7
*
*/
 
#include "math-utils.h"
#include <vector>
#include <cmath>
 
namespace Geom {
 
41,19 → 38,44
// proper logical xor
inline bool logical_xor (bool a, bool b) { return (a || b) && !(a && b); }
 
void binomial_coefficients(std::vector<size_t>& bc, size_t n);
/** 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
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/path-intersection.h
1,37 → 1,3
/**
* \file
* \brief \todo brief description
*
* Authors:
* ? <?@?.?>
*
* Copyright ?-? authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
*/
 
#ifndef __GEOM_PATH_INTERSECTION_H
#define __GEOM_PATH_INTERSECTION_H
 
66,11 → 32,6
return ret;
}
 
Crossings pair_intersect(Curve const & A, Interval const &Ad,
Curve const & B, Interval const &Bd);
Crossings mono_intersect(Curve const & A, Interval const &Ad,
Curve const & B, Interval const &Bd);
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); }
89,11 → 50,6
CrossingSet crossings_among(std::vector<Path> const & p);
Crossings self_crossings(Path const & a);
 
inline Crossings crossings(Curve const & a, Curve const & b) {
DefaultCrosser c = DefaultCrosser();
return c.crossings(a, b);
}
 
inline Crossings crossings(Path const & a, Path const & b) {
DefaultCrosser c = DefaultCrosser();
return c.crossings(a, b);
107,14 → 63,3
}
 
#endif
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/poly-dk-solve.cpp
0,0 → 1,64
#include "poly-dk-solve.h"
#include <iterator>
 
/*** implementation of the Durand-Kerner method. seems buggy*/
 
std::complex<double> evalu(Poly const & p, std::complex<double> x) {
std::complex<double> result = 0;
std::complex<double> xx = 1;
 
for(unsigned i = 0; i < p.size(); i++) {
result += p[i]*xx;
xx *= x;
}
return result;
}
 
std::vector<std::complex<double> > DK(Poly const & ply, const double tol) {
std::vector<std::complex<double> > roots;
const int N = ply.degree();
 
std::complex<double> b(0.4, 0.9);
std::complex<double> p = 1;
for(int i = 0; i < N; i++) {
roots.push_back(p);
p *= b;
}
assert(roots.size() == ply.degree());
 
double error = 0;
int i;
for( i = 0; i < 30; i++) {
error = 0;
for(int r_i = 0; r_i < N; r_i++) {
std::complex<double> denom = 1;
std::complex<double> R = roots[r_i];
for(int d_i = 0; d_i < N; d_i++) {
if(r_i != d_i)
denom *= R-roots[d_i];
}
assert(norm(denom) != 0);
std::complex<double> dr = evalu(ply, R)/denom;
error += norm(dr);
roots[r_i] = R - dr;
}
/*std::copy(roots.begin(), roots.end(), std::ostream_iterator<std::complex<double> >(std::cout, ",\t"));
std::cout << std::endl;*/
if(error < tol)
break;
}
//std::cout << error << ", " << i<< std::endl;
return roots;
}
 
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/poly-laguerre-solve.cpp
0,0 → 1,151
#include "poly-laguerre-solve.h"
#include <iterator>
 
typedef std::complex<double> cdouble;
 
cdouble laguerre_internal_complex(Poly const & p,
double x0,
double tol,
bool & quad_root) {
cdouble a = 2*tol;
cdouble xk = x0;
double n = p.degree();
quad_root = false;
const unsigned shuffle_rate = 10;
// static double shuffle[] = {0, 0.5, 0.25, 0.75, 0.125, 0.375, 0.625, 0.875, 1.0};
unsigned shuffle_counter = 0;
while(std::norm(a) > (tol*tol)) {
//std::cout << "xk = " << xk << std::endl;
cdouble b = p.back();
cdouble d = 0, f = 0;
double err = abs(b);
double abx = abs(xk);
for(int j = p.size()-2; j >= 0; j--) {
f = xk*f + d;
d = xk*d + b;
b = xk*b + p[j];
err = abs(b) + abx*err;
}
 
err *= 1e-7; // magic epsilon for convergence, should be computed from tol
 
cdouble px = b;
if(abs(b) < err)
return xk;
//if(std::norm(px) < tol*tol)
// return xk;
cdouble G = d / px;
cdouble H = G*G - f / px;
 
//std::cout << "G = " << G << "H = " << H;
cdouble radicand = (n - 1)*(n*H-G*G);
//assert(radicand.real() > 0);
if(radicand.real() < 0)
quad_root = true;
//std::cout << "radicand = " << radicand << std::endl;
if(G.real() < 0) // here we try to maximise the denominator avoiding cancellation
a = - sqrt(radicand);
else
a = sqrt(radicand);
//std::cout << "a = " << a << std::endl;
a = n / (a + G);
//std::cout << "a = " << a << std::endl;
if(shuffle_counter % shuffle_rate == 0)
{
//a *= shuffle[shuffle_counter / shuffle_rate];
}
xk -= a;
shuffle_counter++;
if(shuffle_counter >= 90)
break;
}
//std::cout << "xk = " << xk << std::endl;
return xk;
}
 
double laguerre_internal(Poly const & p,
Poly const & pp,
Poly const & ppp,
double x0,
double tol,
bool & quad_root) {
double a = 2*tol;
double xk = x0;
double n = p.degree();
quad_root = false;
while(a*a > (tol*tol)) {
//std::cout << "xk = " << xk << std::endl;
double px = p(xk);
if(px*px < tol*tol)
return xk;
double G = pp(xk) / px;
double H = G*G - ppp(xk) / px;
 
//std::cout << "G = " << G << "H = " << H;
double radicand = (n - 1)*(n*H-G*G);
assert(radicand > 0);
//std::cout << "radicand = " << radicand << std::endl;
if(G < 0) // here we try to maximise the denominator avoiding cancellation
a = - sqrt(radicand);
else
a = sqrt(radicand);
//std::cout << "a = " << a << std::endl;
a = n / (a + G);
//std::cout << "a = " << a << std::endl;
xk -= a;
}
//std::cout << "xk = " << xk << std::endl;
return xk;
}
 
 
std::vector<cdouble >
laguerre(Poly p, const double tol) {
std::vector<cdouble > solutions;
//std::cout << "p = " << p << " = ";
while(p.size() > 1)
{
double x0 = 0;
bool quad_root = false;
cdouble sol = laguerre_internal_complex(p, x0, tol, quad_root);
//if(abs(sol) > 1) break;
Poly dvs;
if(quad_root) {
dvs.push_back((sol*conj(sol)).real());
dvs.push_back(-(sol + conj(sol)).real());
dvs.push_back(1.0);
//std::cout << "(" << dvs << ")";
//solutions.push_back(sol);
//solutions.push_back(conj(sol));
} else {
//std::cout << sol << std::endl;
dvs.push_back(-sol.real());
dvs.push_back(1.0);
solutions.push_back(sol);
//std::cout << "(" << dvs << ")";
}
Poly r;
p = divide(p, dvs, r);
//std::cout << r << std::endl;
}
return solutions;
}
 
std::vector<double>
laguerre_real_interval(Poly const & ply,
const double lo, const double hi,
const double tol) {
std::vector<double > solutions;
return solutions;
}
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/sbasis-math.h
1,6 → 1,5
/**
* \file
* \brief some std functions to work with (pw)s-basis
/*
* sbasis-math.h - some std functions to work with (pw)s-basis
*
* Authors:
* Jean-Francois Barraud
42,7 → 41,6
 
#include "sbasis.h"
#include "piecewise.h"
#include "d2.h"
 
namespace Geom{
//-|x|---------------------------------------------------------------
82,12 → 80,9
Piecewise<SBasis> reciprocal( SBasis const &f, double tol=1e-3, int order=3);
Piecewise<SBasis> reciprocal(Piecewise<SBasis>const &f, double tol=1e-3, int order=3);
 
//--interpolate------------------------------------------------------------
Piecewise<SBasis> interpolate( std::vector<double> times, std::vector<double> values, unsigned smoothness = 1);
}
 
#endif //SEEN_GEOM_PW_SB_CALCULUS_H
 
/*
Local Variables:
mode:c++
97,4 → 92,4
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
// vim: filetype = cpp:expandtab:shiftwidth = 4:tabstop = 8:softtabstop = 4:encoding = utf-8:textwidth = 99 :
/trunk/Scribus/scribus/third_party/lib2geom/sweep.cpp
1,139 → 1,105
#include <sweep.h>
 
#include <algorithm>
 
namespace Geom {
 
/**
* \brief Make a list of pairs of self intersections in a list of Rects.
*
* \param rs: vector of Rect.
* \param d: dimension to sweep along
*
* [(A = rs[i], B = rs[j]) for i,J in enumerate(pairs) for j in J]
* then A.left <= B.left
*/
 
std::vector<std::vector<unsigned> > sweep_bounds(std::vector<Rect> rs, Dim2 d) {
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][d][0], i, false));
events.push_back(Event(rs[i][d][1], 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][1-d].intersects(rs[ix][1-d])) {
pairs[jx].push_back(ix);
}
}
open.push_back(ix);
}
}
return pairs;
}
 
/**
* \brief Make a list of pairs of red-blue intersections between two lists of Rects.
*
* \param a: vector of Rect.
* \param b: vector of Rect.
* \param d: dimension to scan along
*
* [(A = rs[i], B = rs[j]) for i,J in enumerate(pairs) for j in J]
* then A.left <= B.left, A in a, B in b
*/
std::vector<std::vector<unsigned> > sweep_bounds(std::vector<Rect> a, std::vector<Rect> b, Dim2 d) {
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++) {
Rect r = n ? b[i] : a[i];
events[n].push_back(Event(r[d][0], i, false));
events[n].push_back(Event(r[d][1], i, true));
}
std::sort(events[n].begin(), events[n].end());
}
 
std::vector<unsigned> open[2];
bool n = events[1].front() < events[0].front();
{// As elegant as putting the initialiser in the for was, it upsets some legacy compilers (MS VS C++)
unsigned i[] = {0,0};
for(; 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][1-d].intersects(b[ix][1-d])) {
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][1-d].intersects(a[ix][1-d])) {
pairs[ix].push_back(jx);
}
}
}
open[n].push_back(ix);
}
i[n]++;
if(i[n]>=events[n].size()) {break;}
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;
}
 
}
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
#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;
}
 
}
/trunk/Scribus/scribus/third_party/lib2geom/sbasis.cpp
33,22 → 33,35
 
#include <cmath>
 
#include <sbasis.h>
#include <isnan.h>
#include "sbasis.h"
#include "isnan.h"
#include "angle.h"
 
 
namespace Geom{
 
/** bound the error from term truncation
\param tail first term to chop
\returns the largest possible error this truncation could give
/*** 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);
Interval bs = bounds_fast(*this, tail);
return std::max(fabs(bs.min()),fabs(bs.max()));
}
 
/** test all coefficients are finite
*/
bool SBasis::isFinite() const {
for(unsigned i = 0; i < size(); i++) {
if(!(*this)[i].isFinite())
57,124 → 70,78
return true;
}
 
/** Compute the value and the first n derivatives
\param t position to evaluate
\param n number of derivatives (not counting value)
\returns a vector with the value and the n derivative evaluations
 
There is an elegant way to compute the value and n derivatives for a polynomial using a variant of horner's rule. Someone will someday work out how for sbasis.
*/
std::vector<double> SBasis::valueAndDerivatives(double t, unsigned n) const {
std::vector<double> ret(n+1);
ret[0] = valueAt(t);
SBasis tmp = *this;
for(unsigned i = 1; i < n+1; i++) {
tmp.derive();
ret[i] = tmp.valueAt(t);
}
return ret;
}
 
 
/** Compute the pointwise sum of a and b (Exact)
\param a,b sbasis functions
\returns sbasis equal to a+b
 
*/
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());
SBasis result(out_size, Linear());
result.reserve(out_size);
 
for(unsigned i = 0; i < min_size; i++) {
result[i] = a[i] + b[i];
result.push_back(a[i] + b[i]);
}
for(unsigned i = min_size; i < a.size(); i++)
result[i] = a[i];
result.push_back(a[i]);
for(unsigned i = min_size; i < b.size(); i++)
result[i] = b[i];
result.push_back(b[i]);
 
assert(result.size() == out_size);
return result;
}
 
/** Compute the pointwise difference of a and b (Exact)
\param a,b sbasis functions
\returns sbasis equal to a-b
 
*/
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());
SBasis result(out_size, Linear());
result.reserve(out_size);
 
for(unsigned i = 0; i < min_size; i++) {
result[i] = a[i] - b[i];
result.push_back(a[i] - b[i]);
}
for(unsigned i = min_size; i < a.size(); i++)
result[i] = a[i];
result.push_back(a[i]);
for(unsigned i = min_size; i < b.size(); i++)
result[i] = -b[i];
result.push_back(-b[i]);
 
assert(result.size() == out_size);
return result;
}
 
/** Compute the pointwise sum of a and b and store in a (Exact)
\param a,b sbasis functions
\returns sbasis equal to a+b
 
*/
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.resize(out_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[i] = b[i];
a.push_back(b[i]);
 
assert(a.size() == out_size);
return a;
}
 
/** Compute the pointwise difference of a and b and store in a (Exact)
\param a,b sbasis functions
\returns sbasis equal to a-b
 
*/
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.resize(out_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[i] = -b[i];
a.push_back(-b[i]);
 
assert(a.size() == out_size);
return a;
}
 
/** Compute the pointwise product of a and b (Exact)
\param a,b sbasis functions
\returns sbasis equal to a*b
 
*/
SBasis operator*(SBasis const &a, double k) {
SBasis c(a.size(), Linear());
SBasis c;
c.reserve(a.size());
for(unsigned i = 0; i < a.size(); i++)
c[i] = a[i] * k;
c.push_back(a[i] * k);
return c;
}
 
/** Compute the pointwise product of a and b and store the value in a (Exact)
\param a,b sbasis functions
\returns sbasis equal to a*b
 
*/
SBasis& operator*=(SBasis& a, double b) {
if (a.isZero()) return a;
if (b == 0)
185,42 → 152,25
return a;
}
 
/** multiply a by x^sh in place (Exact)
\param a sbasis function
\param sh power
\returns a
 
*/
SBasis shift(SBasis const &a, int sh) {
size_t n = a.size()+sh;
SBasis c(n, Linear());
size_t m = std::max(0, sh);
for(int i = 0; i < sh; i++)
c[i] = Linear(0,0);
for(size_t i = m, j = std::max(0,-sh); i < n; i++, j++)
c[i] = a[j];
SBasis c = a;
if(sh > 0) {
c.insert(c.begin(), sh, Linear(0,0));
} else {
//TODO: truncate
}
return c;
}
 
/** multiply a by x^sh (Exact)
\param a linear function
\param sh power
\returns a* x^sh
 
*/
SBasis shift(Linear const &a, int sh) {
size_t n = 1+sh;
SBasis c(n, Linear());
for(int i = 0; i < sh; i++)
c[i] = Linear(0,0);
if(sh >= 0)
c[sh] = a;
SBasis c;
if(sh > 0) {
c.insert(c.begin(), sh, Linear(0,0));
c.push_back(a);
}
return c;
}
 
#if 0
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)}
 
229,10 → 179,11
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 = b[j].tri()*a[i-j].tri();
c[i+1/*shift*/] += Linear(-tri);
double tri = Tri(b[j])*Tri(a[i-j]);
c[i+1/*shift*/] += Linear(Hat(-tri));
}
}
for(unsigned j = 0; j < b.size(); j++) {
245,52 → 196,7
//assert(!(0 == c.back()[0] && 0 == c.back()[1]));
return c;
}
#else
 
/** Compute the pointwise product of a and b adding c (Exact)
\param a,b,c sbasis functions
\returns sbasis equal to a*b+c
 
The added term is almost free
*/
SBasis multiply_add(SBasis const &a, SBasis const &b, SBasis c) {
if(a.isZero() || b.isZero())
return c;
c.resize(a.size() + b.size(), Linear(0,0));
for(unsigned j = 0; j < b.size(); j++) {
for(unsigned i = j; i < a.size()+j; i++) {
double tri = b[j].tri()*a[i-j].tri();
c[i+1/*shift*/] += Linear(-tri);
}
}
for(unsigned j = 0; j < b.size(); j++) {
for(unsigned i = j; i < a.size()+j; i++) {
for(unsigned dim = 0; dim < 2; dim++)
c[i][dim] += b[j][dim]*a[i-j][dim];
}
}
c.normalize();
//assert(!(0 == c.back()[0] && 0 == c.back()[1]));
return c;
}
 
/** Compute the pointwise product of a and b (Exact)
\param a,b sbasis functions
\returns sbasis equal to a*b
 
*/
SBasis multiply(SBasis const &a, SBasis const &b) {
SBasis c;
if(a.isZero() || b.isZero())
return c;
return multiply_add(a, b, c);
}
#endif
/** Compute the integral of a (Exact)
\param a sbasis functions
\returns sbasis integral(a)
 
*/
SBasis integral(SBasis const &c) {
SBasis a;
a.resize(c.size() + 1, Linear(0,0));
297,12 → 203,12
a[0] = Linear(0,0);
 
for(unsigned k = 1; k < c.size() + 1; k++) {
double ahat = -c[k-1].tri()/(2*k);
a[k][0] = a[k][1] = ahat;
double ahat = -Tri(c[k-1])/(2*k);
a[k] = Hat(ahat);
}
double aTri = 0;
for(int k = c.size()-1; k >= 0; k--) {
aTri = (c[k].hat() + (k+1)*aTri/2)/(2*k+1);
aTri = (Hat(c[k]).d + (k+1)*aTri/2)/(2*k+1);
a[k][0] -= aTri/2;
a[k][1] += aTri/2;
}
310,63 → 216,28
return a;
}
 
/** Compute the derivative of a (Exact)
\param a sbasis functions
\returns sbasis da/dt
 
*/
SBasis derivative(SBasis const &a) {
SBasis c;
c.resize(a.size(), Linear(0,0));
if(a.isZero())
return c;
 
for(unsigned k = 0; k < a.size()-1; k++) {
double d = (2*k+1)*(a[k][1] - a[k][0]);
c[k][0] = d + (k+1)*a[k+1][0];
c[k][1] = d - (k+1)*a[k+1][1];
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];
}
}
}
int k = a.size()-1;
double d = (2*k+1)*(a[k][1] - a[k][0]);
if(d == 0)
c.pop_back();
else {
c[k][0] = d;
c[k][1] = d;
}
 
return c;
}
 
/** Compute the derivative of this inplace (Exact)
 
*/
void SBasis::derive() { // in place version
if(isZero()) return;
for(unsigned k = 0; k < size()-1; k++) {
double d = (2*k+1)*((*this)[k][1] - (*this)[k][0]);
(*this)[k][0] = d + (k+1)*(*this)[k+1][0];
(*this)[k][1] = d - (k+1)*(*this)[k+1][1];
}
int k = size()-1;
double d = (2*k+1)*((*this)[k][1] - (*this)[k][0]);
if(d == 0)
pop_back();
else {
(*this)[k][0] = d;
(*this)[k][1] = d;
}
}
 
/** Compute the sqrt of a
\param a sbasis functions
\returns sbasis \f[ \sqrt{a} \f]
 
It is recommended to use the piecewise version unless you have good reason.
TODO: convert int k to unsigned k, and remove cast
*/
//TODO: convert int k to unsigned k, and remove cast
SBasis sqrt(SBasis const &a, int k) {
SBasis c;
if(a.isZero() || k == 0)
388,17 → 259,12
return c;
}
 
/** Compute the recpirocal of a
\param a sbasis functions
\returns sbasis 1/a
 
It is recommended to use the piecewise version unless you have good reason.
*/
// 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 = (a.tri()*a.tri())/(-a[0]*a[1]);
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]);
407,12 → 273,6
return c;
}
 
/** Compute a / b to k terms
\param a,b sbasis functions
\returns sbasis a/b
 
It is recommended to use the piecewise version unless you have good reason.
*/
SBasis divide(SBasis const &a, SBasis const &b, int k) {
SBasis c;
assert(!a.isZero());
434,34 → 294,26
return c;
}
 
/** Compute a composed with b
\param a,b sbasis functions
\returns sbasis a(b(t))
 
return a0 + s(a1 + s(a2 +... where s = (1-u)u; ak =(1 - u)a^0_k + ua^1_k
*/
// a(b)
// return a0 + s(a1 + s(a2 +... where s = (1-u)u; ak =(1 - u)a^0_k + ua^1_k
SBasis compose(SBasis const &a, SBasis const &b) {
SBasis s = multiply((SBasis(Linear(1,1))-b), b);
SBasis r;
 
for(int i = a.size()-1; i >= 0; i--) {
r = multiply_add(r, s, SBasis(Linear(a[i][0])) - b*a[i][0] + b*a[i][1]);
r = SBasis(Linear(Hat(a[i][0]))) - b*a[i][0] + b*a[i][1] + multiply(r,s);
}
return r;
}
 
/** Compute a composed with b to k terms
\param a,b sbasis functions
\returns sbasis a(b(t))
 
return a0 + s(a1 + s(a2 +... where s = (1-u)u; ak =(1 - u)a^0_k + ua^1_k
*/
// a(b)
// return a0 + s(a1 + s(a2 +... where s = (1-u)u; ak =(1 - u)a^0_k + ua^1_k
SBasis compose(SBasis const &a, SBasis const &b, unsigned k) {
SBasis s = multiply((SBasis(Linear(1,1))-b), b);
SBasis r;
 
for(int i = a.size()-1; i >= 0; i--) {
r = multiply_add(r, s, SBasis(Linear(a[i][0])) - b*a[i][0] + b*a[i][1]);
r = SBasis(Linear(Hat(a[i][0]))) - b*a[i][0] + b*a[i][1] + multiply(r,s);
}
r.truncate(k);
return r;
482,14 → 334,9
 
//#define DEBUG_INVERSION 1
 
/** find the function a^-1 such that a^-1 composed with a to k terms is the identity function
\param a sbasis function
\returns sbasis a^-1 s.t. a^-1(a(t)) = 1
 
The function must have 'unit range'("a00 = 0 and a01 = 1") and be monotonic.
*/
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;
500,11 → 347,11
if(a1 != 1) {
a /= a1;
}
SBasis c(k, Linear()); // c(v) := 0
SBasis c; // c(v) := 0
if(a.size() >= 2 && k == 2) {
c[0] = Linear(0,1);
c.push_back(Linear(0,1));
Linear t1(1+a[1][0], 1-a[1][1]); // t_1
c[1] = Linear(-a[1][0]/t1[0], -a[1][1]/t1[1]);
c.push_back(Linear(-a[1][0]/t1[0], -a[1][1]/t1[1]));
} else if(a.size() >= 2) { // non linear
SBasis r = Linear(0,1); // r(u) := r_0(u) := u
Linear t1(1./(1+a[1][0]), 1./(1-a[1][1])); // 1./t_1
520,7 → 367,7
//assert(t1 == t[1]);
#endif
 
//c.resize(k+1, Linear(0,0));
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;
560,18 → 407,11
return c;
}
 
/** Compute the sine of a to k terms
\param b linear function
\returns sbasis sin(a)
 
It is recommended to use the piecewise version unless you have good reason.
*/
SBasis sin(Linear b, int k) {
SBasis s(k+2, Linear());
s[0] = Linear(std::sin(b[0]), std::sin(b[1]));
double tr = s[0].tri();
double t2 = b.tri();
s[1] = Linear(std::cos(b[0])*t2 - tr, -std::cos(b[1])*t2 + tr);
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++) {
580,34 → 420,23
bo -= s[i]*(t2/(i+1));
 
 
s[i+2] = bo/double(i+2);
s.push_back(bo/double(i+2));
}
 
return s;
}
 
/** Compute the cosine of a
\param b linear function
\returns sbasis cos(a)
 
It is recommended to use the piecewise version unless you have good reason.
*/
SBasis cos(Linear bo, int k) {
return sin(Linear(bo[0] + M_PI/2,
bo[1] + M_PI/2),
return sin(Linear(bo[0] + M_PI_2,
bo[1] + M_PI_2),
k);
}
 
/** compute fog^-1.
\param f,g sbasis functions
\returns sbasis f(g^-1(t)).
 
("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!
*/
//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(order, Linear()); //result
SBasis result; //result
SBasis r=f; //remainder
SBasis Pk=Linear(1)-g,Qk=g,sg=Pk*Qk;
Pk.truncate(order);
636,7 → 465,7
a=( q01*r10-q10*r01)/det;
b=(-p01*r10+p10*r01)/det;
}
result[k] = Linear(a,b);
result.push_back(Linear(a,b));
r=r-Pk*a-Qk*b;
 
Pk=Pk*sg;
/trunk/Scribus/scribus/third_party/lib2geom/point-l.h
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++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/bezier-to-sbasis.h
1,6 → 1,5
/**
* \file bezier-to-sbasis.h
* \brief \todo brief description
/*
* bezier-to-sbasis.h
*
* Copyright 2006 Nathan Hurst <njh@mail.csse.monash.edu.au>
*
33,14 → 32,12
#define _BEZIER_TO_SBASIS
 
#include "coord.h"
 
#include "d2.h"
#include "point.h"
#include "d2.h"
#include "sbasis-to-bezier.h"
 
namespace Geom
{
namespace Geom{
 
#if 0
inline SBasis bezier_to_sbasis(Coord const *handles, unsigned order) {
if(order == 0)
return Linear(handles[0]);
53,8 → 50,7
 
 
template <typename T>
inline D2<SBasis> handles_to_sbasis(T const &handles, unsigned order)
{
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++)
62,29 → 58,8
return D2<SBasis>(bezier_to_sbasis(v[0], order),
bezier_to_sbasis(v[1], order));
}
#endif
 
 
template <typename T>
inline
D2<SBasis> handles_to_sbasis(T const& handles, unsigned order)
{
D2<SBasis> sbc;
size_t sz = order + 1;
std::vector<Point> v;
v.reserve(sz);
for (size_t i = 0; i < sz; ++i)
v.push_back(handles[i]);
bezier_to_sbasis(sbc, v);
return sbc;
}
 
 
} // end namespace Geom
 
 
 
 
};
#endif
/*
Local Variables:
/trunk/Scribus/scribus/third_party/lib2geom/sbasis-to-bezier.h
1,37 → 1,3
/**
* \file
* \brief \todo brief description
*
* Authors:
* ? <?@?.?>
*
* Copyright ?-? authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
*/
 
#ifndef _SBASIS_TO_BEZIER
#define _SBASIS_TO_BEZIER
 
38,17 → 4,7
#include "d2.h"
#include "path.h"
 
#include <vector>
 
namespace Geom {
 
void sbasis_to_bezier (Bezier & bz, SBasis const& sb, size_t sz = 0);
void sbasis_to_bezier (std::vector<Point> & bz, D2<SBasis> const& sb, size_t sz = 0);
void bezier_to_sbasis (SBasis & sb, Bezier const& bz);
void bezier_to_sbasis (D2<SBasis> & sb, std::vector<Point> const& bz);
 
 
#if 0
namespace Geom{
// this produces a degree k bezier from a degree k sbasis
Bezier
sbasis_to_bezier(SBasis const &B, unsigned q = 0);
59,28 → 15,10
 
std::vector<Geom::Point>
sbasis_to_bezier(D2<SBasis> const &B, unsigned q = 0);
#endif
 
std::vector<Path> path_from_piecewise(Piecewise<D2<SBasis> > const &B, double tol);
 
std::vector<Path> path_from_piecewise(Piecewise<D2<SBasis> > const &B, double tol, bool only_cubicbeziers = false);
Path path_from_sbasis(D2<SBasis> const &B, double tol);
 
Path path_from_sbasis(D2<SBasis> const &B, double tol, bool only_cubicbeziers = false);
inline Path cubicbezierpath_from_sbasis(D2<SBasis> const &B, double tol)
{ return path_from_sbasis(B, tol, true); }
 
} // end namespace Geom
 
 
 
};
#endif
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/solve-bezier-parametric.cpp
1,5 → 1,5
#include <solver.h>
#include <point.h>
#include "solver.h"
#include "point.h"
#include <algorithm>
 
namespace Geom{
30,7 → 30,7
 
const unsigned MAXDEPTH = 64; /* Maximum depth for recursion */
 
const double BEPSILON = ldexp(1.0,-MAXDEPTH-1); /*Flatness control value */
const double BEPSILON = ldexp(1.0,((signed)-1)-MAXDEPTH); /*Flatness control value */
 
unsigned total_steps, total_subs;
 
69,12 → 69,12
}
 
/* Otherwise, solve recursively after subdividing control polygon */
Geom::Point Left[degree+1], /* New left and right */
Right[degree+1]; /* control polygons */
Bezier(w, degree, 0.5, Left, Right);
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, degree, solutions, depth+1);
find_parametric_bezier_roots(Right, degree, solutions, depth+1);
find_parametric_bezier_roots(&Left[0], degree, solutions, depth+1);
find_parametric_bezier_roots(&Right[0], degree, solutions, depth+1);
}
 
 
123,7 → 123,7
 
const double abSquared = (a * a) + (b * b);
 
double distance[degree]; /* Distances from pts to line */
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[i-1]);
191,24 → 191,28
Geom::Point *Left, /* RETURN left half ctl pts */
Geom::Point *Right) /* RETURN right half ctl pts */
{
Geom::Point Vtemp[degree+1][degree+1];
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 */
std::copy(V, V+degree+1, Vtemp[0]);
Left[0] = vtemp[0];
Right[degree]= vtemp[degree];
 
/* Triangle computation */
for (unsigned i = 1; i <= degree; i++) {
for (unsigned j = 0; j <= degree - i; j++) {
Vtemp[i][j] = lerp(t, Vtemp[i-1][j], Vtemp[i-1][j+1]);
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[degree-i]=vtemp[degree-i];
}
for (unsigned j = 0; j <= degree; j++)
Left[j] = Vtemp[j][0];
for (unsigned j = 0; j <= degree; j++)
Right[j] = Vtemp[degree-j][j];
 
return (Vtemp[degree][0]);
return (vtemp[0]);
}
 
};
217,9 → 221,12
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
c-file-offsets:((innamespace . 0)(substatement-open . 0))
indent-tabs-mode:nil
c-brace-offset:0
fill-column:99
End:
vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
 
 
/trunk/Scribus/scribus/third_party/lib2geom/angle.h
1,326 → 1,53
/**
* \file
* \brief Various trigoniometric helper functions
*//*
* Authors:
* Johan Engelen <goejendaagh@zonnet.nl>
* Marco Cecchetti <mrcekets at gmail.com>
* Krzysztof Kosiński <tweenk.pl@gmail.com>
*
* Copyright (C) 2007-2010 Authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
*/
 
#ifndef LIB2GEOM_SEEN_ANGLE_H
#define LIB2GEOM_SEEN_ANGLE_H
 
#include <cmath>
#include <boost/operators.hpp>
#include "exception.h"
#include "coord.h"
#include "point.h"
 
namespace Geom {
 
#ifndef M_PI
# define M_PI 3.14159265358979323846
#endif
 
/** @brief Wrapper for angular values.
*
* This class is a convenience wrapper that implements the behavior generally expected of angles,
* like addition modulo \f$2\pi\f$. The value returned from the default conversion
* to <tt>double</tt> is in the range \f$[-\pi, \pi)\f$ - the convention used by C's
* math library.
*
* @ingroup Primitives
*/
class Angle
: boost::additive< Angle
, boost::equality_comparable< Angle
> >
{
public:
Angle(Coord v) : _angle(v + M_PI) { normalize(); } // this can be called implicitly
explicit Angle(Point p) : _angle(atan2(p) + M_PI) {}
Angle(Point a, Point b) : _angle(angle_between(a, b) + M_PI) {}
operator Coord() const { return radians(); }
Angle &operator+=(Angle const &o) {
_angle += o._angle;
normalize();
return *this;
}
Angle &operator-=(Angle const &o) {
_angle -= o._angle;
normalize();
return *this;
}
bool operator==(Angle const &o) const {
return _angle == o._angle;
}
 
/** @brief Get the angle as radians.
* @return Number in range \f$[-\pi, \pi)\f$. */
Coord radians() const {
return _angle - M_PI;
}
/** @brief Get the angle as radians starting from zero.
* @return Number in range \f$[0, 2\pi)\f$. 0 corresponds to \f$-\pi\f$ for radians(). */
Coord radians0() const {
return _angle;
}
/** @brief Get the angle as degrees in math convention.
* @return Number in range [-180, 180) obtained by scaling the result of radians()
* by \f$180/\pi\f$. */
Coord degrees() const { return radians() / M_PI * 180.0; }
/** @brief Get the angle as degrees in clock convention.
* This method converts the angle to the "clock convention": angles start from the +Y axis
* and grow clockwise. This means that 0 corresponds to \f$\pi/2\f$ radians,
* 90 to 0 radians, 180 to \f$-\pi/2\f$ radians, and 270 to \f$\pi\f$ radians.
* @return A number in the range [0, 360).
*/
Coord degreesClock() const {
Coord ret = 90.0 - _angle / M_PI * 180.0;
if (ret < 0) ret += 360;
return ret;
}
/** @brief Convert the angle to canonical internal representation.
* Use this periodically to avoid loss of precision when adding lots of angles together. */
void normalize() {
if (_angle >= 2*M_PI || _angle < 0) {
_angle = std::fmod(_angle, 2*M_PI);
if (_angle < 0) _angle += 2*M_PI;
}
}
static Angle from_radians0(Coord r) {
Angle a;
a._angle = std::fmod(r, 2*M_PI);
return a;
}
static Angle from_degrees(Coord d) {
Angle a(d * M_PI / 180);
return a;
}
static Angle from_degrees_clock(Coord d) {
// first make sure d is in [0, 360)
d = std::fmod(d, 360.0);
if (d < 0) d += 360.0;
Coord rad = M_PI/2 - d * M_PI / 180.0;
if (rad < 0) rad += 2*M_PI;
Angle a;
a._angle = rad;
return a;
}
private:
Angle() {}
Coord _angle; // this is always in [0, 2pi), so offset by pi from math library convention
friend class AngleInterval;
};
 
inline Angle distance_ccw(Angle const &as, Angle const &ae) {
Coord s = as.radians0();
Coord e = ae.radians0();
Coord dist;
if (s <= e) dist = s - e;
else dist = 2*M_PI + s - e;
return Angle::from_radians0(dist);
}
inline Angle distance_cw(Angle const &as, Angle const &ae) {
return distance_ccw(ae, as);
}
 
inline Angle distance_abs(Angle const &as, Angle const &ae) {
Angle ret = distance_ccw(as, ae);
if (ret.radians0() > M_PI) {
return Angle::from_radians0(2*M_PI - ret.radians0());
} else {
return ret;
}
}
 
/** @brief Directed angular interval.
*
* Wrapper for directed angles with defined start and end values. Useful e.g. for representing
* the portion of an ellipse in an elliptical arc. Both extreme angles are contained
* in the interval (it is a closed interval). Angular intervals can also be interptered
* as functions \f$f: [0, 1] \to [-\pi, \pi)\f$, which return the start angle for 0,
* the end angle for 1, and interpolate linearly for other values. Note that such functions
* are not continuous if the interval contains the zero angle.
*
* This class is immutable - you cannot change the values of start and end angles
* without creating a new instance of this class.
*
* @ingroup Primitives
*/
class AngleInterval {
public:
AngleInterval(Angle const &s, Angle const &e, bool cw = false)
: _start_angle(cw ? e : s), _end_angle(cw ? s : e)
{}
AngleInterval(double s, double e, bool cw = false)
: _start_angle(cw ? e : s), _end_angle(cw ? s : e)
{}
/** @brief Get the angular coordinate of the interval's initial point
* @return Angle in range \f$[0,2\pi)\f$ corresponding to the start of arc */
Angle const &initialAngle() const { return _start_angle; }
/** @brief Get the angular coordinate of the interval's final point
* @return Angle in range \f$[0,2\pi)\f$ corresponding to the end of arc */
Angle const &finalAngle() const { return _end_angle; }
bool isDegenerate() const { return initialAngle() == finalAngle(); }
/** @brief Get an angle corresponding to the specified time value. */
Angle angleAt(Coord t) const {
Coord span = distance_ccw(_start_angle, _end_angle).radians0();
Angle ret;
ret._angle = std::fmod(_start_angle.radians0() + span * t, 2*M_PI);
return ret;
}
Angle operator()(Coord t) const { return angleAt(t); }
/** @brief Find an angle nearest to the specified time value.
* @param a Query angle
* @return If the interval contains the query angle, a number from the range [0, 1]
* such that a = angleAt(t); otherwise, 0 or 1, depending on which extreme
* angle is nearer. */
Coord nearestAngle(Angle const &a) const {
Coord dist = distance_ccw(_start_angle, a).radians0();
Coord span = distance_ccw(_start_angle, _end_angle).radians0();
if (dist <= span) return dist / span;
else return distance_abs(_start_angle, a).radians0() > distance_abs(_end_angle, a) ? 1.0 : 0.0;
}
/** @brief Check whether the interval includes the given angle. */
bool contains(Angle const &a) const {
Coord s = _start_angle.radians0();
Coord e = _end_angle.radians0();
Coord x = a.radians0();
// If s <= e, then the +X axis (the angular origin) is contained in the interval.
if (s <= e) return x >= s && x <= e;
else return x >= e || x <= s;
}
protected:
AngleInterval() {}
Angle _start_angle;
Angle _end_angle;
};
 
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;}
 
/*
* start_angle and angle must belong to [0, 2PI[
* and angle must belong to the cirsular arc defined by
* start_angle, end_angle and with rotation direction cw
*/
inline
double map_circular_arc_on_unit_interval( double angle, double start_angle, double end_angle, bool cw = true )
{
double d = end_angle - start_angle;
double t = angle - start_angle;
if ( !cw )
{
d = -d;
t = -t;
}
d = std::fmod(d, 2*M_PI);
t = std::fmod(t, 2*M_PI);
if ( d < 0 ) d += 2*M_PI;
if ( t < 0 ) t += 2*M_PI;
return t / d;
}
 
inline
Coord map_unit_interval_on_circular_arc(Coord t, double start_angle, double end_angle, bool cw = true)
{
double sweep_angle = end_angle - start_angle;
if ( !cw ) sweep_angle = -sweep_angle;
sweep_angle = std::fmod(sweep_angle, 2*M_PI);
if ( sweep_angle < 0 ) sweep_angle += 2*M_PI;
 
Coord angle = start_angle;
if ( cw )
{
angle += sweep_angle * t;
}
else
{
angle -= sweep_angle * t;
}
angle = std::fmod(angle, 2*M_PI);
if (angle < 0) angle += 2*M_PI;
return angle;
}
 
/*
* Return true if the given angle is contained in the circular arc determined
* by the passed angles.
*
* a: the angle to be tested
* sa: the angle the arc start from
* ia: an angle strictly inner to the arc
* ea: the angle the arc end to
*
* prerequisite: the inner angle has to be not equal (mod 2PI) to the start
* or the end angle, except when they are equal each other, too.
* warning: when sa == ea (mod 2PI) they define a whole circle
* if ia != sa (mod 2PI), on the contrary if ia == sa == ea (mod 2PI)
* they define a single point.
*/
inline
bool arc_contains (double a, double sa, double ia, double ea)
{
a -= sa;
a = std::fmod(a, 2*M_PI);
if (a < 0) a += 2*M_PI;
ia -= sa;
ia = std::fmod(ia, 2*M_PI);
if (ia < 0) ia += 2*M_PI;
ea -= sa;
ea = std::fmod(ea, 2*M_PI);
if (ea < 0) ea += 2*M_PI;
 
if (ia == 0 && ea == 0) return (a == 0);
if (ia == 0 || ia == ea)
{
THROW_RANGEERROR ("arc_contains: passed angles do not define an arc");
}
return (ia < ea && a <= ea) || (ia > ea && (a >= ea || a == 0));
}
 
} // end namespace Geom
 
#endif
 
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/**
* \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 COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
*/
#ifndef 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
/trunk/Scribus/scribus/third_party/lib2geom/sbasis-2d.h
1,38 → 1,3
/**
* \file
* \brief \todo brief description
*
* Authors:
* Nathan Hurst <?@?.?>
* JFBarraud <?@?.?>
*
* Copyright 2006-2008 authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
*/
 
#ifndef SEEN_SBASIS_2D_H
#define SEEN_SBASIS_2D_H
#include <vector>
51,12 → 16,7
v 0,2
*/
double a[4];
Linear2d() {
a[0] = 0;
a[1] = 0;
a[2] = 0;
a[3] = 0;
}
Linear2d() {}
Linear2d(double aa) {
for(unsigned i = 0 ; i < 4; i ++)
a[i] = aa;
313,7 → 273,7
 
SBasis2d integral(SBasis2d const &c);
 
SBasis2d partial_derivative(SBasis2d const &a, int dim);
SBasis2d derivative(SBasis2d const &a);
 
SBasis2d sqrt(SBasis2d const &a, int k);
 
350,12 → 310,6
return out_file;
}
 
D2<SBasis>
sb2dsolve(SBasis2d const &f, Geom::Point const &A, Geom::Point const &B, unsigned degmax=2);
 
D2<SBasis>
sb2d_cubic_solve(SBasis2d const &f, Geom::Point const &A, Geom::Point const &B);
 
};
 
/*
/trunk/Scribus/scribus/third_party/lib2geom/point.h
1,81 → 1,38
/**
* \file
* \brief Cartesian point / 2D vector and related operations
*//*
* Authors:
* Michael G. Sloan <mgsloan@gmail.com>
* Nathan Hurst <njh@njhurst.com>
* Krzysztof Kosiński <tweenk.pl@gmail.com>
*
* Copyright (C) 2006-2009 Authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*/
 
#ifndef SEEN_Geom_POINT_H
#define SEEN_Geom_POINT_H
 
#include "scconfig.h"
/** \file
* Cartesian point class.
*/
 
#include <iostream>
#include <iterator>
#include <boost/operators.hpp>
#include "forward.h"
 
#include "coord.h"
#include "isnan.h" //temporary fix for isnan()
#include "math-utils.h"
#include "utils.h"
 
namespace Geom {
 
enum Dim2 { X=0, Y=1 };
 
class Point
: boost::additive< Point
, boost::totally_ordered< Point
, boost::multiplicative< Point, Coord
, boost::multiplicative< Point, Affine
, boost::multiplicative< Point, Translate
, boost::multiplicative< Point, Rotate
, boost::multiplicative< Point, Scale
, boost::multiplicative< Point, HShear
, boost::multiplicative< Point, VShear
> > > > > > > > > // this uses chaining so it looks weird, but works
{
class Matrix;
 
/// Cartesian point.
class Point {
Coord _pt[2];
 
public:
/** Construct a point on the origin. */
public:
inline Point()
{ _pt[X] = _pt[Y] = 0; }
 
/** Construct a point from its coordinates. */
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];
82,48 → 39,59
return *this;
}
 
/// @name Access the coordinates of a point
/// @{
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]; }
/// @}
 
/// @name Vector operations
/// @{
/** @brief Compute the distance from origin.
* @return Length of the vector from origin to this point */
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]); }
void normalize();
 
/** @brief 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 counter-clockwise. */
/** 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 counter-clockwise.)
**/
Point ccw() const {
return Point(_pt[Y], -_pt[X]);
}
 
/** @brief 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. */
/** 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]);
}
/// @}
 
/// @name Vector-like arithmetic operations
/// @{
inline Point operator-() const {
return Point(-_pt[X], -_pt[Y]);
/**
\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];
130,240 → 98,123
}
return *this;
}
inline Point &operator*=(double s) {
 
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 s) {
inline Point &operator/=(double const s) {
//TODO: s == 0?
for ( unsigned i = 0 ; i < 2 ; ++i ) _pt[i] /= s;
return *this;
}
/// @}
 
/// @name Affine transformations
/// @{
Point &operator*=(Affine const &m);
// implemented in transforms.cpp
Point &operator*=(Translate const &t);
Point &operator*=(Scale const &s);
Point &operator*=(Rotate const &r);
Point &operator*=(HShear const &s);
Point &operator*=(VShear const &s);
/** @brief Transform the point by the inverse of the specified matrix. */
template <typename T>
Point &operator/=(T const &m) {
*this *= m.inverse();
return *this;
}
/// @}
Point &operator*=(Matrix const &m);
 
/// @name Various utilities
/// @{
/** @brief Lower the precision of the point.
* This will round both coordinates to multiples of \f$10^p\f$. */
inline void round (int p = 0) {
_pt[X] = (Coord)(decimal_round((double)_pt[X], p));
_pt[Y] = (Coord)(decimal_round((double)_pt[Y], p));
return;
}
 
/** @brief Check whether both coordinates are finite.
* @return True if neither coordinate is infinite. */
inline bool isFinite() const {
for ( unsigned i = 0 ; i < 2 ; ++i ) {
if(!IS_FINITE(_pt[i])) return false;
}
return true;
}
/** @brief Equality operator.
* This tests for exact identity (as opposed to are_near()). Note that due to numerical
* errors, this test might return false even if the points should be identical. */
inline bool operator==(const Point &in_pnt) const {
inline int operator == (const Point &in_pnt) {
return ((_pt[X] == in_pnt[X]) && (_pt[Y] == in_pnt[Y]));
}
/** @brief Lexicographical ordering for points.
* Y coordinate is regarded as more significant. When sorting according to this
* ordering, the points will be sorted according to the Y coordinate, and within
* points with the same Y coordinate according to the X coordinate. */
inline bool operator<(const Point &p) const {
return ( ( _pt[Y] < p[Y] ) ||
(( _pt[Y] == p[Y] ) && ( _pt[X] < p[X] )));
}
/// @}
 
/// @name Point factories
/// @{
/** @brief Construct a point from its polar coordinates.
* The angle is specified in radians, in the mathematical convention (increasing
* counter-clockwise from +X). */
static inline Point polar(Coord angle, Coord radius) {
Point ret(polar(angle));
ret *= radius;
return ret;
}
/** @brief Construct an unit vector from its angle.
* The angle is specified in radians, in the mathematical convention (increasing
* counter-clockwise from +X). */
static inline Point polar(Coord angle) {
Point ret;
sincos(angle, ret[Y], ret[X]);
return ret;
}
/// @}
 
/** @brief Lexicographical ordering functor. */
template <Dim2 d> struct LexOrder;
/** @brief Lexicographical ordering functor with runtime dimension. */
class LexOrderRt {
public:
LexOrderRt(Dim2 d) : dim(d) {}
inline bool operator()(Point const &a, Point const &b);
private:
Dim2 dim;
};
 
friend inline std::ostream &operator<< (std::ostream &out_file, const Geom::Point &in_pnt);
};
 
/** @brief Output operator for points.
* Prints out the coordinates.
* @relates Point */
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;
}
 
template<> struct Point::LexOrder<X> {
bool operator()(Point const &a, Point const &b) {
return a[X] < b[X] || (a[X] == b[X] && a[Y] < b[Y]);
}
};
template<> struct Point::LexOrder<Y> {
bool operator()(Point const &a, Point const &b) {
return a[Y] < b[Y] || (a[Y] == b[Y] && a[X] < b[X]);
}
};
inline bool Point::LexOrderRt::operator()(Point const &a, Point const &b) {
return dim ? Point::LexOrder<Y>()(a, b) : Point::LexOrder<X>()(a, b);
/** 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;
}
 
/** @brief Compute the second (Euclidean) norm of @a p.
* This corresponds to the length of @a p. The result will not overflow even if
* \f$p_X^2 + p_Y^2\f$ is larger that the maximum value that can be stored
* in a <code>double</code>.
* @return \f$\sqrt{p_X^2 + p_Y^2}\f$
* @relates Point */
inline Coord L2(Point const &p)
{
return p.length();
//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]);
}
 
/** @brief Compute the square of the Euclidean norm of @a p.
* Warning: this can overflow where L2 won't.
* @return \f$p_X^2 + p_Y^2\f$
* @relates Point */
inline Coord L2sq(Point const &p)
{
return p[0]*p[0] + p[1]*p[1];
/** 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
/** @brief Nearness predicate for points.
* True if neither coordinate of @a a is further than @a eps from the corresponding
* coordinate of @a b.
* @relates Point */
inline bool are_near(Point const &a, Point const &b, double const eps=EPSILON)
{
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) );
}
 
/** @brief Return a point halfway between the specified ones.
* @relates Point */
inline Point middle_point(Point const& P1, Point const& P2)
{
return (P1 + P2) / 2;
}
 
/** @brief Returns p * Geom::rotate_degrees(90), but more efficient.
/** Returns p * Geom::rotate_degrees(90), but more efficient.
*
* Angle direction in 2Geom: If you use the traditional mathematics convention that y
* 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 non-mathematical convention that y increases downwards, then positive angles
* are clockwise, as is common outside of mathematics.
*
* There is no function to rotate by -90 degrees: use -rot90(p) instead.
* @relates Point */
inline Point rot90(Point const &p)
{
return Point(-p[Y], p[X]);
}
* There is no rot_neg90 function: use -rot90(p) instead.
*/
inline Point rot90(Point const &p) { return Point(-p[Y], p[X]); }
 
/** @brief Linear interpolation between two points.
* @param t Time value
* @param a First point
* @param b Second point
* @return Point on a line between a and b. The ratio of its distance from a
* and the distance between a and b will be equal to t.
* @relates Point */
inline Point lerp(double const t, Point const &a, Point const &b)
{
return (a * (1 - t) + b * t);
}
/** 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); }
 
/** @brief Compute the dot product of a and b.
* Dot product can be interpreted as a measure of how parallel the vectors are.
* For perpendicular vectors, it is zero. For parallel ones, its absolute value is highest,
* and the sign depends on whether they point in the same direction (+) or opposite ones (-).
* @return \f$a \cdot b = a_X b_X + a_Y b_Y\f$.
* @relates Point*/
inline Coord dot(Point const &a, Point const &b)
{
return a[0] * b[0] + a[1] * b[1];
}
Point unit_vector(Point const &a);
 
/** @brief Compute the 2D cross product.
* Defined as dot(a, b.cw()). This means it will be zero for parallel vectors,
* and its absolute value highest for perpendicular vectors.
* @relates Point*/
inline Coord cross(Point const &a, Point const &b)
{
return dot(a, b.cw());
}
/** 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()); }
 
/** @brief Compute the (Euclidean) distance between points.
* @relates Point */
inline Coord distance (Point const &a, Point const &b)
{
return L2(a - b);
}
/** 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); }
 
/** @brief Compute the square of the distance between points.
* @relates Point */
inline Coord distanceSq (Point const &a, Point const &b)
{
return L2sq(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 unit_vector(Point const &a);
Coord L1(Point const &p);
Coord LInfty(Point const &p);
bool is_zero(Point const &p);
bool is_unit_vector(Point const &p);
extern double atan2(Point const &p);
extern double angle_between(Point const &a, Point const &b);
Point abs(Point const &b);
Point constrain_angle(Point const &A, Point const &B, unsigned int n = 4, Geom::Point const &dir = Geom::Point(1,0));
 
Point operator*(Point const &v, Matrix const &m);
 
Point operator/(Point const &p, Matrix const &m);
 
} /* namespace Geom */
 
// This is required to fix a bug in GCC 4.3.3 (and probably others) that causes the compiler
// to try to instantiate the iterator_traits template and fail. Probably it thinks that Point
// is an iterator and tries to use std::distance instead of Geom::distance.
namespace std {
template <> class iterator_traits<Geom::Point> {};
}
 
#endif /* !SEEN_Geom_POINT_H */
 
/*
/trunk/Scribus/scribus/third_party/lib2geom/solve-bezier-one-d.cpp
1,12 → 1,6
 
#include <solver.h>
#include <choose.h>
#include <bezier.h>
#include <point.h>
 
#include <cmath>
#include "solver.h"
#include "point.h"
#include <algorithm>
//#include <valarray>
 
/*** 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
16,107 → 10,66
namespace Geom{
 
template<class t>
static int SGN(t x) { return (x > 0 ? 1 : (x < 0 ? -1 : 0)); }
static int SGN(t x) { return (x > 0 ? 1 : (x < 0 ? -1 : 0)); }
 
//const unsigned MAXDEPTH = 23; // Maximum depth for recursion. Using floats means 23 bits precision max
/*
* Forward declarations
*/
static void
Bernstein(double const *V,
unsigned degree,
double t,
double *Left,
double *Right);
 
//const double BEPSILON = ldexp(1.0,(-MAXDEPTH-1)); /*Flatness control value */
//const double SECANT_EPSILON = 1e-13; // secant method converges much faster, get a bit more precision
/**
* This function is called _a lot_. We have included various manual memory management stuff to reduce the amount of mallocing that goes on. In the future it is possible that this will hurt performance.
**/
class Bernsteins{
public:
static const size_t MAX_DEPTH = 22;
size_t degree, N;
std::vector<double> &solutions;
//std::vector<double> bc;
BinomialCoefficient<double> bc;
static unsigned
control_poly_flat_enough(double const *V, unsigned degree,
double left_t, double right_t);
 
Bernsteins(size_t _degree, std::vector<double> & sol)
: degree(_degree), N(degree+1), solutions(sol), bc(degree)
{
}
const unsigned MAXDEPTH = 64; /* Maximum depth for recursion */
 
void subdivide(double const *V,
double t,
double *Left,
double *Right);
const double BEPSILON = ldexp(1.0,((signed)-1)-MAXDEPTH); /*Flatness control value */
 
unsigned
control_poly_flat_enough(double const *V);
 
double horner(const double *b, double t);
 
 
void
find_bernstein_roots(double const *w, /* The control points */
unsigned depth, /* The depth of the recursion */
double left_t, double right_t);
};
/*
* find_bernstein_roots : Given an equation in Bernstein-Bernstein form, find all
* find_bernstein_roots : Given an equation in Bernstein-Bernstein 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 */
unsigned degree, /* The degree of the polynomial */
std::vector<double> &solutions, /* RETURN candidate t-values */
unsigned depth, /* The depth of the recursion */
double left_t, double right_t, bool /*use_secant*/)
{
Bernsteins B(degree, solutions);
B.find_bernstein_roots(w, depth, left_t, right_t);
}
 
void
find_bernstein_roots(std::vector<double> &solutions, /* RETURN candidate t-values */
Geom::Bezier const& bz, /* The control points */
unsigned depth, /* The depth of the recursion */
double left_t, double right_t)
{
Bernsteins B(bz.degree(), solutions);
Geom::Bezier& bzl = const_cast<Geom::Bezier&>(bz);
double* w = &(bzl[0]);
B.find_bernstein_roots(w, 0, left_t, right_t);
}
 
 
 
void Bernsteins::find_bernstein_roots(double const *w, /* The control points */
unsigned depth, /* The depth of the recursion */
double left_t,
double right_t)
{
 
size_t n_crossings = 0;
 
{
unsigned n_crossings = 0; /* Number of zero-crossings */
int old_sign = SGN(w[0]);
//std::cout << "w[0] = " << w[0] << std::endl;
int sign;
for (size_t i = 1; i < N; i++)
{
//std::cout << "w[" << i << "] = " << w[i] << std::endl;
sign = SGN(w[i]);
if (sign != 0)
{
if (sign != old_sign && old_sign != 0)
{
++n_crossings;
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;
}
}
//std::cout << "n_crossings = " << n_crossings << std::endl;
if (n_crossings == 0) return; // no solutions here
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 (n_crossings == 1) /* Unique solution */
{
//std::cout << "depth = " << depth << std::endl;
/* Stop recursion when the tree is deep enough */
/* if deep enough, return 1 solution at midpoint */
if (depth > MAX_DEPTH)
{
//printf("bottom out %d\n", depth);
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];
 
123,94 → 76,26
solutions.push_back(left_t - Ax*w[0] / Ay);
return;
}
 
 
double s = 0, t = 1;
double e = 1e-10;
int side = 0;
double r, fr, fs = w[0], ft = w[degree];
 
for (size_t n = 0; n < 100; ++n)
{
r = (fs*t - ft*s) / (fs - ft);
if (fabs(t-s) < e * fabs(t+s)) break;
 
fr = horner(w, r);
 
if (fr * ft > 0)
{
t = r; ft = fr;
if (side == -1) fs /= 2;
side = -1;
}
else if (fs * fr > 0)
{
s = r; fs = fr;
if (side == +1) ft /= 2;
side = +1;
}
else break;
}
solutions.push_back(r*right_t + (1-r)*left_t);
return;
 
break;
}
 
/* Otherwise, solve recursively after subdividing control polygon */
// double Left[N], /* New left and right */
// Right[N]; /* control polygons */
//const double t = 0.5;
double* LR = new double[2*N];
double* Left = LR;
double* Right = LR + N;
 
std::copy(w, w + N, Right);
 
Left[0] = Right[0];
for (size_t i = 1; i < N; ++i)
{
for (size_t j = 0; j < N-i; ++j)
{
Right[j] = (Right[j] + Right[j+1]) * 0.5;
}
Left[i] = Right[0];
}
 
double mid_t = (left_t + right_t) * 0.5;
 
 
find_bernstein_roots(Left, depth+1, left_t, mid_t);
 
 
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*(1-split) + 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, depth+1, mid_t, right_t);
delete[] LR;
find_bernstein_roots(&Right[0], degree, solutions, depth+1, mid_t, right_t);
}
 
 
// suggested by Sederberg.
double Bernsteins::horner(const double *b, double t)
{
double u, tn, tmp;
u = 1.0 - t;
tn = 1.0;
tmp = b[0] * u;
for(size_t i = 1; i < degree; ++i)
{
tn *= t;
tmp = (tmp + tn*bc[i]*b[i]) * u;
}
return (tmp + tn*t*b[degree]);
}
 
 
 
#if 0
/*
* control_poly_flat_enough :
* Check if the control polygon of a Bernstein curve is flat enough
217,8 → 102,10
* for recursive subdivision to bottom out.
*
*/
unsigned
Bernsteins::control_poly_flat_enough(double const *V)
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] */
226,6 → 113,8
/* 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;
233,7 → 122,7
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 - a;
const double d = (a + V[i]) * ii*b + c;
double dist = d*d;
// Find the largest distance
if (d < 0.0)
241,23 → 130,57
else
max_distance_above = std::max(max_distance_above, dist);
}
const double abSquared = (a * a) + (b * b);
 
const double abSquared = 1./((a * a) + 1);
const double intercept_1 = -(c + max_distance_above / abSquared);
const double intercept_2 = -(c + max_distance_below / abSquared);
 
const double intercept_1 = (a - max_distance_above * abSquared);
const double intercept_2 = (a - 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);
//printf("error %g %g %g\n", error, a, BEPSILON * a);
return error < BEPSILON * a;
if (error < BEPSILON * a)
return 1;
return 0;
}
#endif
 
 
 
/*
* Bernstein :
* Evaluate a Bernstein function at a particular parameter value
* Fill in control points for resulting sub-curves.
*
*/
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 = (1-t);
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[degree-i]=vtemp[degree-i];
}
}
 
};
 
/*
264,9 → 187,12
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
c-file-offsets:((innamespace . 0)(substatement-open . 0))
indent-tabs-mode:nil
c-brace-offset:0
fill-column:99
End:
vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
 
 
/trunk/Scribus/scribus/third_party/lib2geom/quadtree.cpp
1,17 → 1,5
#include <quadtree.h>
#include "quadtree.h"
 
namespace Geom{
Quad* QuadTree::search(Rect const &r) {
return search(r[0].min(), r[1].min(),
r[0].max(), r[1].max());
}
 
void QuadTree::insert(Rect const &r, int shape) {
insert(r[0].min(), r[1].min(),
r[0].max(), r[1].max(), shape);
}
 
 
Quad* QuadTree::search(double x0, double y0, double x1, double y1) {
Quad *q = root;
43,94 → 31,9
}
return q;
}
 
 
/*
Comments by Vangelis (use with caution :P )
 
Insert Rect (x0, y0), (x1, y1) in the QuadTree Q.
 
===================================================================================
* QuadTree Q has: Quadtree's Quad root R, QuadTree's bounding box B.
 
* Each Quad has a Quad::data where we store the id of the Rect that belong to
this Quad. (In reality we'll store a pointer to the shape).
 
* Each Quad has 4 Quad children: 0, 1, 2, 3. Each child Quad represents one of the following quarters
of the bounding box B:
 
+---------------------+
| | |
| NW=0 | NE=1 |
| | |
| | |
+---------------------+
| | |
| SW=2 | SE=3 |
| | |
| | |
+---------------------+
 
Each Quad can further be divided in 4 Quads as above and so on. Below there is an example
Root
/ || \
/ / \ \
0 1 2 3
/\
/ | | \
0 1 2 3
 
+---------------------+
| | 1-0 | 1-1|
| 0 | | |
| |-----|----|
| | 1-2 | 1-3|
| | | |
+---------------------+
| | |
| | |
| 2 | 3 |
| | |
+---------------------+
 
 
 
===================================================================================
Insert Rect (x0, y0), (x1, y1) in the QuadTree Q. Algorithm:
1) check if Rect is bigger than QuadTree's bounding box
2) find in which Quad we should add the Rect:
 
 
 
-----------------------------------------------------------------------------------
How we find in which Quad we should add the Rect R:
 
Q = Quadtree's Quad root
B = QuadTree's bounding box B
WHILE (Q) {
IF ( Rect cannot fit in one unique quarter of B ){
Q = current Quad ;
BREAK;
}
IF ( Rect can fit in the quarter I ) {
IF (Q.children[I] doesn't exist) {
create the Quad Q.children[I];
}
B = bounding box of the Quad Q.children[I] ;
Q = Q.children[I] ;
CHECK(R, B) ;
}
}
add Rect R to Q ;
 
 
*/
void QuadTree::insert(double x0, double y0, double x1, double y1, int shape) {
// loop until a quad would break the box.
 
// empty root => empty QuadTree. Create initial bounding box (0,0), (1,1)
if(root == 0) {
root = new Quad;
140,18 → 43,14
by1 = 1;
}
Quad *q = root;
 
//A temp bounding box. Same as root's bounting box (ie of the whole QuadTree)
double bxx0 = bx0, bxx1 = bx1;
double byy0 = by0, byy1 = by1;
 
while((bxx0 > x0) ||
(bxx1 < x1) ||
(byy0 > y0) ||
(byy1 < y1)) {
// QuadTree has small size, can't accomodate new rect. Double the size:
(byy1 < y1)) { // too small initial size - double
unsigned i = 0;
 
if(bxx0 > x0) {
bxx0 = 2*bxx0 - bxx1;
i += 1;
165,22 → 64,15
byy1 = 2*byy1 - byy0;
}
q = new Quad;
//check if root is empty (no rects, no quad children)
if( clean_root() ){
root = q;
}
else{
q->children[i] = root;
root = q;
}
q->children[i] = root;
root = q;
bx0 = bxx0;
bx1 = bxx1;
by0 = byy0;
by1 = byy1;
}
 
while(q) {
// Find the center of the temp bounding box
double cx = (bxx0 + bxx1)/2;
double cy = (byy0 + byy1)/2;
unsigned i = 0;
188,41 → 80,21
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{
// rect does not fit in one unique quarter (in X axis) of the temp bounding box
} else
break;
}
if(y0 >= cy) {
i += 2;
byy0 = cy;
} else if(y1 <= cy) {
byy1 = cy;
} else{
// rect does not fit in one unique quarter (in Y axis) of the temp bounding box
} else
break;
}
 
// check if rect's bounding box has size 1x1. This means that rect is defined by 2 points
// that are in the same place.
if( ( fabs(bxx0 - bxx1) < 1.0 ) && ( fabs(byy0 - byy1) < 1.0 )){
bxx0 = floor(bxx0);
bxx1 = floor(bxx1);
byy0 = floor(byy0);
byy1 = floor(byy1);
break;
}
 
/*
1 rect does fit in one unique quarter of the temp bounding box. And we have found which.
2 temp bounding box = bounding box of this quarter.
3 "Go in" this quarter (create if doesn't exist)
*/
assert(i < 4);
Quad *qq = q->children[i];
if(qq == 0) {
246,43 → 118,14
}
 
/*
Returns:
false: if root isn't empty
true: if root is empty it cleans root
*/
bool QuadTree::clean_root() {
assert(root);
 
// false if root *has* rects assigned to it.
bool all_clean = root->data.empty();
 
// if root has children we get false
for(unsigned i = 0; i < 4; i++)
{
if(root->children[i])
{
all_clean = false;
}
}
 
if(all_clean)
{
delete root;
root=0;
return true;
}
return false;
}
 
};
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
c-file-offsets:((innamespace . 0)(substatement-open . 0))
indent-tabs-mode:nil
c-brace-offset:0
fill-column:99
End:
vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
 
/trunk/Scribus/scribus/third_party/lib2geom/sbasis-math.cpp
34,27 → 34,19
//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 <sbasis-math.h>
 
#include <d2-sbasis.h>
#include <stdio.h>
#include <math.h>
#include "sbasis-math.h"
//#define ZERO 1e-3
 
#include <cstdio>
#include <cmath>
#include "angle.h"
 
namespace Geom {
 
 
//-|x|-----------------------------------------------------------------------
/** Return the absolute value of a function pointwise.
\param f function
*/
Piecewise<SBasis> abs(SBasis const &f){
return abs(Piecewise<SBasis>(f));
}
/** Return the absolute value of a function pointwise.
\param f function
*/
Piecewise<SBasis> abs(Piecewise<SBasis> const &f){
Piecewise<SBasis> absf=partition(f,roots(f));
for (unsigned i=0; i<absf.size(); i++){
64,27 → 56,15
}
 
//-max(x,y), min(x,y)--------------------------------------------------------
/** Return the greater of the two functions pointwise.
\param f, g two functions
*/
Piecewise<SBasis> max( SBasis const &f, SBasis const &g){
return max(Piecewise<SBasis>(f),Piecewise<SBasis>(g));
}
/** Return the greater of the two functions pointwise.
\param f, g two functions
*/
Piecewise<SBasis> max(Piecewise<SBasis> const &f, SBasis const &g){
return max(f,Piecewise<SBasis>(g));
}
/** Return the greater of the two functions pointwise.
\param f, g two functions
*/
Piecewise<SBasis> max( SBasis const &f, Piecewise<SBasis> const &g){
return max(Piecewise<SBasis>(f),g);
}
/** Return the greater of the two functions pointwise.
\param f, g two functions
*/
Piecewise<SBasis> max(Piecewise<SBasis> const &f, Piecewise<SBasis> const &g){
Piecewise<SBasis> max=partition(f,roots(f-g));
Piecewise<SBasis> gg =partition(g,max.cuts);
95,38 → 75,20
return max;
}
 
/** Return the more negative of the two functions pointwise.
\param f, g two functions
*/
Piecewise<SBasis>
min( SBasis const &f, SBasis const &g){ return -max(-f,-g); }
/** Return the more negative of the two functions pointwise.
\param f, g two functions
*/
Piecewise<SBasis>
min(Piecewise<SBasis> const &f, SBasis const &g){ return -max(-f,-g); }
/** Return the more negative of the two functions pointwise.
\param f, g two functions
*/
Piecewise<SBasis>
min( SBasis const &f, Piecewise<SBasis> const &g){ return -max(-f,-g); }
/** Return the more negative of the two functions pointwise.
\param f, g two functions
*/
Piecewise<SBasis>
min(Piecewise<SBasis> const &f, Piecewise<SBasis> const &g){ return -max(-f,-g); }
 
 
//-sign(x)---------------------------------------------------------------
/** Return the sign of the two functions pointwise.
\param f function
*/
Piecewise<SBasis> signSb(SBasis const &f){
return signSb(Piecewise<SBasis>(f));
}
/** Return the sign of the two functions pointwise.
\param f function
*/
Piecewise<SBasis> signSb(Piecewise<SBasis> const &f){
Piecewise<SBasis> sign=partition(f,roots(f));
for (unsigned i=0; i<sign.size(); i++){
149,7 → 111,7
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++) {
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));
176,16 → 138,10
return sqrtf0;
}
 
/** Compute the sqrt of a function.
\param f function
*/
Piecewise<SBasis> sqrt(SBasis const &f, double tol, int order){
return sqrt(max(f,Linear(tol*tol)),tol,order);
}
 
/** Compute the sqrt of a function.
\param f function
*/
Piecewise<SBasis> sqrt(Piecewise<SBasis> const &f, double tol, int order){
Piecewise<SBasis> result;
Piecewise<SBasis> zero = Piecewise<SBasis>(Linear(tol*tol));
202,24 → 158,9
 
//-Yet another sin/cos--------------------------------------------------------------
 
/** Compute the sine of a function.
\param f function
\param tol maximum error
\param order maximum degree polynomial to use
*/
Piecewise<SBasis> sin( SBasis const &f, double tol, int order){return(cos(-f+M_PI/2,tol,order));}
/** Compute the sine of a function.
\param f function
\param tol maximum error
\param order maximum degree polynomial to use
*/
Piecewise<SBasis> sin(Piecewise<SBasis> const &f, double tol, int order){return(cos(-f+M_PI/2,tol,order));}
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);}
 
/** Compute the cosine of a function.
\param f function
\param tol maximum error
\param order maximum degree polynomial to use
*/
Piecewise<SBasis> cos(Piecewise<SBasis> const &f, double tol, int order){
Piecewise<SBasis> result;
for (unsigned i=0; i<f.size(); i++){
230,11 → 171,6
return result;
}
 
/** Compute the cosine of a function.
\param f function
\param tol maximum error
\param order maximum degree polynomial to use
*/
Piecewise<SBasis> cos( SBasis const &f, double tol, int order){
double alpha = (f.at0()+f.at1())/2.;
SBasis x = f-alpha;
269,6 → 205,7
return c0;
}
 
 
//--1/x------------------------------------------------------------
//TODO: this implementation is just wrong. Remove or redo!
 
328,46 → 265,20
}
 
Piecewise<SBasis> reciprocal(SBasis const &f, double tol, int order){
Piecewise<SBasis> reciprocal_fn=reciprocalOnDomain(*bounds_fast(f), tol);
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> reciprocal_fn=reciprocalOnDomain(bounds_fast(f), tol);
Piecewise<SBasis> result=compose(reciprocal_fn,f);
truncateResult(result,order);
return(result);
}
 
/**
* \brief Retruns a Piecewise SBasis with prescribed values at prescribed times.
*
* \param times: vector of times at which the values are given. Should be sorted in increasing order.
* \param values: vector of prescribed values. Should have the same size as times and be sorted accordingly.
* \param smoothness: (defaults to 1) regularity class of the result: 0=piecewise linear, 1=continuous derivative, etc...
*/
Piecewise<SBasis> interpolate(std::vector<double> times, std::vector<double> values, unsigned smoothness){
assert ( values.size() == times.size() );
if ( values.size() == 0 ) return Piecewise<SBasis>();
if ( values.size() == 1 ) return Piecewise<SBasis>(values[0]);//what about time??
 
SBasis sk = shift(Linear(1.),smoothness);
SBasis bump_in = integral(sk);
bump_in -= bump_in.at0();
bump_in /= bump_in.at1();
SBasis bump_out = reverse( bump_in );
Piecewise<SBasis> result;
result.cuts.push_back(times[0]);
for (unsigned i = 0; i<values.size()-1; i++){
result.push(bump_out*values[i]+bump_in*values[i+1],times[i+1]);
}
return result;
}
 
}
 
/*
Local Variables:
mode:c++
377,4 → 288,4
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
// vim: filetype = cpp:expandtab:shiftwidth = 4:tabstop = 8:softtabstop = 4:encoding = utf-8:textwidth = 99 :
/trunk/Scribus/scribus/third_party/lib2geom/convex-cover.cpp
29,12 → 29,9
*
*/
 
#include <convex-cover.h>
#include <exception.h>
#include "convex-cover.h"
#include <algorithm>
#include <map>
#include <assert.h>
 
/** Todo:
+ modify graham scan to work top to bottom, rather than around angles
+ intersection
49,7 → 46,6
using std::vector;
using std::map;
using std::pair;
using std::make_pair;
 
namespace Geom{
 
65,16 → 61,12
public:
Point o;
angle_cmp(Point o) : o(o) {}
 
#if 0
bool
operator()(Point a, Point b) {
// not remove this check or std::sort could crash
if (a == b) return false;
Point da = a - o;
Point db = b - o;
if (da == -db) return false;
 
#if 1
double aa = da[0];
double ab = db[0];
99,23 → 91,6
return L2sq(da) < L2sq(db);
return false;
}
#else
bool operator() (Point const& a, Point const& b)
{
// not remove this check or std::sort could generate
// a segmentation fault because it needs a strict '<'
// but due to round errors a == b doesn't mean dxy == dyx
if (a == b) return false;
Point da = a - o;
Point db = b - o;
if (da == -db) return false;
double dxy = da[X] * db[Y];
double dyx = da[Y] * db[X];
if (dxy > dyx) return true;
else if (dxy < dyx) return false;
return L2sq(da) < L2sq(db);
}
#endif
};
 
void
122,10 → 97,10
ConvexHull::find_pivot() {
// Find pivot P;
unsigned pivot = 0;
for (unsigned i = 1; i < boundary.size(); i++)
for(unsigned i = 1; i < boundary.size(); i++)
if(boundary[i] <= boundary[pivot])
pivot = i;
 
std::swap(boundary[0], boundary[pivot]);
}
 
136,14 → 111,12
std::sort(boundary.begin()+1, boundary.end(), angle_cmp(boundary[0]));
}
 
 
void
ConvexHull::graham_scan() {
if (boundary.size() < 4) return;
unsigned stac = 2;
for(unsigned int i = 2; i < boundary.size(); i++) {
double o = SignedTriangleArea(boundary[stac-2],
boundary[stac-1],
for(unsigned i = 2; i < boundary.size(); i++) {
double o = SignedTriangleArea(boundary[stac-2],
boundary[stac-1],
boundary[i]);
if(o == 0) { // colinear - dangerous...
stac--;
151,8 → 124,8
} else { // remove concavity
while(o >= 0 && stac > 2) {
stac--;
o = SignedTriangleArea(boundary[stac-2],
boundary[stac-1],
o = SignedTriangleArea(boundary[stac-2],
boundary[stac-1],
boundary[i]);
}
}
163,8 → 136,6
 
void
ConvexHull::graham() {
if(is_degenerate()) // nothing to do
return;
find_pivot();
angle_sort();
graham_scan();
172,7 → 143,7
 
//Mathematically incorrect mod, but more useful.
int mod(int i, int l) {
return i >= 0 ?
return i >= 0 ?
i % l : (i % l) + l;
}
//OPT: usages can often be replaced by conditions
181,13 → 152,6
* 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::strict_left
* Tests if a point is left (outside) of a particular segment, n. */
bool
ConvexHull::is_strict_left(Point p, int n) {
return SignedTriangleArea((*this)[n], (*this)[n+1], p) > 0;
}
 
202,22 → 166,8
}
return -1;
}
//OPT: do a spread iteration - quasi-random with no repeats and full coverage.
 
 
/*** 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_strict_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_strict_left(p, i)) return i;
}
return -1;
}
 
//OPT: do a spread iteration - quasi-random 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. */
226,14 → 176,6
return find_left(p) == -1;
}
 
/*** ConvexHull::strict_contains_point
* In order to test whether a point is strictly inside (not on the boundary) 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::strict_contains_point(Point p) {
return find_strict_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?*/
250,9 → 192,9
 
bool pushed = false;
 
bool pre = is_strict_left(p, -1);
bool pre = is_left(p, -1);
for(int i = 0; i < l; i++) {
bool cur = is_strict_left(p, i);
bool cur = is_left(p, i);
if(pre) {
if(cur) {
if(!pushed) {
269,7 → 211,7
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.
303,12 → 245,12
bool
ConvexHull::top_point_first() const {
std::vector<Point>::const_iterator pivot = boundary.begin();
for(std::vector<Point>::const_iterator it(boundary.begin()+1),
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]) &&
else if(((*it)[1] == (*pivot)[1]) &&
((*it)[0] < (*pivot)[0]))
pivot = it;
}
322,8 → 264,7
*/
bool
ConvexHull::no_colinear_points() const {
// XXX: implement me!
THROW_NOTIMPLEMENTED();
return true;
}
 
bool
340,81 → 281,47
}
 
 
int sgn(double x) {
if(x == 0) return 0;
return (x<0)?-1:1;
}
/* 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;
 
bool same_side(Point L[2], Point xs[4]) {
int side = 0;
for(int i = 0; i < 4; i++) {
int sn = sgn(SignedTriangleArea(L[0], L[1], xs[i]));
if(sn and not side)
side = sn;
else if(sn != side) return false;
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 true;
return make_pair(abridges, bbridges);
}
 
/** find bridging pairs between two convex hulls.
* this code is based on Hormoz Pirzadeh's masters thesis. There is room for optimisation:
* 1. reduce recomputation
* 2. use more efficient angle code
* 3. write as iterator
*/
std::vector<pair<int, int> > bridges(ConvexHull a, ConvexHull b) {
vector<pair<int, int> > ret;
// 1. find maximal points on a and b
int ai = 0, bi = 0;
// 2. find first copodal pair
double ap_angle = atan2(a[ai+1] - a[ai]);
double bp_angle = atan2(b[bi+1] - b[bi]);
Point L[2] = {a[ai], b[bi]};
while(ai < int(a.size()) or bi < int(b.size())) {
if(ap_angle == bp_angle) {
// In the case of parallel support lines, we must consider all four pairs of copodal points
{
assert(0); // untested
Point xs[4] = {a[ai-1], a[ai+1], b[bi-1], b[bi+1]};
if(same_side(L, xs)) ret.push_back(make_pair(ai, bi));
xs[2] = b[bi];
xs[3] = b[bi+2];
if(same_side(L, xs)) ret.push_back(make_pair(ai, bi));
xs[0] = a[ai];
xs[1] = a[ai+2];
if(same_side(L, xs)) ret.push_back(make_pair(ai, bi));
xs[2] = b[bi-1];
xs[3] = b[bi+1];
if(same_side(L, xs)) ret.push_back(make_pair(ai, bi));
}
ai++;
ap_angle += angle_between(a[ai] - a[ai-1], a[ai+1] - a[ai]);
L[0] = a[ai];
bi++;
bp_angle += angle_between(b[bi] - b[bi-1], b[bi+1] - b[bi]);
L[1] = b[bi];
std::cout << "parallel\n";
} else if(ap_angle < bp_angle) {
ai++;
ap_angle += angle_between(a[ai] - a[ai-1], a[ai+1] - a[ai]);
L[0] = a[ai];
Point xs[4] = {a[ai-1], a[ai+1], b[bi-1], b[bi+1]};
if(same_side(L, xs)) ret.push_back(make_pair(ai, bi));
} else {
bi++;
bp_angle += angle_between(b[bi] - b[bi-1], b[bi+1] - b[bi]);
L[1] = b[bi];
Point xs[4] = {a[ai-1], a[ai+1], b[bi-1], b[bi+1]};
if(same_side(L, xs)) ret.push_back(make_pair(ai, bi));
}
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() &&
while(it < a.boundary.size() &&
a.boundary[it][Y] > a.boundary[it-1][Y])
it++;
return it-1;
428,10 → 335,10
*/
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++;
440,10 → 347,10
(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]);
return ret;
// double sweep_y = std::min(a.boundary[al][Y],
// b.boundary[bl][Y]);
}
 
/*** ConvexHull intersection(ConvexHull a, ConvexHull b);
451,13 → 358,12
* (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 intersection(ConvexHull a, ConvexHull b) {
ConvexHull ret;
/*
int ai = 0, bi = 0;
int aj = a.boundary.size() - 1;
int bj = b.boundary.size() - 1;
*/
// int ai = 0, bi = 0;
// unsigned aj = a.boundary.size() - 1;
// unsigned bj = b.boundary.size() - 1;
/*while (true) {
if(a[ai]
}*/
464,11 → 370,6
return ret;
}
 
template <typename T>
T idx_to_pair(pair<T, T> p, int idx) {
return idx?p.second:p.first;
}
 
/*** ConvexHull merge(ConvexHull a, ConvexHull b);
* find the smallest convex hull that surrounds a and b.
*/
475,80 → 376,52
ConvexHull merge(ConvexHull a, ConvexHull b) {
ConvexHull ret;
 
std::cout << "---\n";
std::vector<pair<int, int> > bpair = bridges(a, b);
// Given our list of bridges {(pb1, qb1), ..., (pbk, qbk)}
// we start with the highest point in p0, q0, say it is p0.
// then the merged hull is p0, ..., pb1, qb1, ..., qb2, pb2, ...
// In other words, either of the two polygons vertices are added in order until the vertex coincides with a bridge point, at which point we swap.
pair< map<int, int>, map<int, int> > bpair = bridges(a, b);
map<int, int> ab = bpair.first;
map<int, int> bb = bpair.second;
 
unsigned state = (a[0][Y] < b[0][Y])?0:1;
ret.boundary.reserve(a.size() + b.size());
ConvexHull chs[2] = {a, b};
unsigned idx = 0;
for(unsigned k = 0; k < bpair.size(); k++) {
unsigned limit = idx_to_pair(bpair[k], state);
std::cout << bpair[k].first << " , " << bpair[k].second << "; "
<< idx << ", " << limit << ", s: "
<< state
<< " \n";
while(idx <= limit) {
ret.boundary.push_back(chs[state][idx++]);
}
state = 1-state;
idx = idx_to_pair(bpair[k], state);
}
while(idx < chs[state].size()) {
ret.boundary.push_back(chs[state][idx++]);
}
return ret;
 
/*
ab[-1] = 0;
bb[-1] = 0;
 
int i = -1; // XXX: i is int but refers to vector indices
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 >= (int)a.boundary.size()) return ret;
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 >= (int)b.boundary.size()) return ret;
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(),
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
559,67 → 432,7
}
}*/
 
double ConvexHull::centroid_and_area(Geom::Point& centroid) const {
const unsigned n = boundary.size();
if (n < 2)
return 0;
if(n < 3) {
centroid = (boundary[0] + boundary[1])/2;
return 0;
}
Geom::Point centroid_tmp(0,0);
double atmp = 0;
for (unsigned i = n-1, j = 0; j < n; i = j, j++) {
const double ai = -cross(boundary[j], boundary[i]);
atmp += ai;
centroid_tmp += (boundary[j] + boundary[i])*ai; // first moment.
}
if (atmp != 0) {
centroid = centroid_tmp / (3 * atmp);
}
return atmp / 2;
}
 
// TODO: This can be made lg(n) using golden section/fibonacci search three starting points, say 0,
// n/2, n-1 construct a new point, say (n/2 + n)/2 throw away the furthest boundary point iterate
// until interval is a single value
Point const * ConvexHull::furthest(Point direction) const {
Point const * p = &boundary[0];
double d = dot(*p, direction);
for(unsigned i = 1; i < boundary.size(); i++) {
double dd = dot(boundary[i], direction);
if(d < dd) {
p = &boundary[i];
d = dd;
}
}
return p;
}
 
 
// returns (a, (b,c)), three points which define the narrowest diameter of the hull as the pair of
// lines going through b,c, and through a, parallel to b,c TODO: This can be made linear time by
// moving point tc incrementally from the previous value (it can only move in one direction). It
// is currently n*O(furthest)
double ConvexHull::narrowest_diameter(Point &a, Point &b, Point &c) {
Point tb = boundary.back();
double d = INFINITY;
for(unsigned i = 0; i < boundary.size(); i++) {
Point tc = boundary[i];
Point n = -rot90(tb-tc);
Point ta = *furthest(n);
double td = dot(n, ta-tb)/dot(n,n);
if(td < d) {
a = ta;
b = tb;
c = tc;
d = td;
}
tb = tc;
}
return d;
}
 
};
 
/*
626,9 → 439,12
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
c-file-offsets:((innamespace . 0)(substatement-open . 0))
indent-tabs-mode:nil
c-brace-offset:0
fill-column:99
End:
vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
 
 
/trunk/Scribus/scribus/third_party/lib2geom/solver.h
1,50 → 1,11
/**
* \file
* \brief \todo brief description
*
* Authors:
* ? <?@?.?>
*
* Copyright ?-? authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
*/
 
#ifndef _SOLVE_SBASIS_H
#define _SOLVE_SBASIS_H
#include "point.h"
#include "sbasis.h"
 
 
#include <vector>
 
 
namespace Geom{
 
class Point;
class Bezier;
 
unsigned
crossing_count(Geom::Point const *V, /* Control pts of Bezier curve */
60,8 → 21,6
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 */
68,24 → 27,7
unsigned degree, /* The degree of the polynomial */
std::vector<double> & solutions, /* RETURN candidate t-values */
unsigned depth, /* The depth of the recursion */
double left_t=0, double right_t=1, bool use_secant=true);
double left_t=0, double right_t=1);
 
};
 
void
find_bernstein_roots(std::vector<double> &solutions, /* RETURN candidate t-values */
Geom::Bezier const& bz,
double left_t, double right_t);
 
#endif
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/linear.h
1,6 → 1,5
/**
* \file
* \brief Linear fragment function class
/*
* linear.h - Linear fragment function class
*
* Authors:
* Nathan Hurst <njh@mail.csse.monash.edu.au>
34,18 → 33,9
 
#ifndef SEEN_LINEAR_H
#define SEEN_LINEAR_H
#include "isnan.h"
#include "interval.h"
#include "isnan.h"
 
 
//#define USE_SBASIS_OF
 
#ifdef USE_SBASIS_OF
 
#include "linear-of.h"
 
#else
 
namespace Geom{
 
inline double lerp(double t, double a, double b) { return a*(1-t) + b*t; }
52,13 → 42,37
 
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(double aa) {a[0] = aa; a[1] = aa;}
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);
74,7 → 88,7
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 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]; }
85,14 → 99,14
//defined in sbasis.h
inline SBasis toSBasis() const;
 
inline OptInterval bounds_exact() const { return Interval(a[0], a[1]); }
inline OptInterval bounds_fast() const { return bounds_exact(); }
inline OptInterval bounds_local(double u, double v) const { return Interval(valueAt(u), valueAt(v)); }
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)); }
 
double tri() const {
operator Tri() const {
return a[1] - a[0];
}
double hat() const {
operator Hat() const {
return (a[1] + a[0])/2;
}
};
154,19 → 168,6
a[0] /= b; a[1] /= b;
return a;
}
};
 
}
#endif
 
#endif //SEEN_LINEAR_H
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/choose.h
1,6 → 1,5
/**
* \file choose.h
* \brief \todo brief description
/*
* choose.h
*
* Copyright 2006 Nathan Hurst <njh@mail.csse.monash.edu.au>
*
31,9 → 30,8
 
#ifndef _CHOOSE_H
#define _CHOOSE_H
#include <vector>
 
// XXX: Can we keep only the left terms easily?
// 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
44,7 → 42,7
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(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);
54,7 → 52,7
unsigned p = pascals_triangle.size() - rows_done;
pascals_triangle.push_back(1);
for(unsigned i = 0; i < rows_done-1; i++) {
pascals_triangle.push_back(pascals_triangle[p]
pascals_triangle.push_back(pascals_triangle[p]
+ pascals_triangle[p+1]);
p++;
}
66,76 → 64,4
return pascals_triangle[row+k];
}
 
// Is it faster to store them or compute them on demand?
/*template <typename T>
T choose(unsigned n, unsigned k) {
T r = 1;
for(unsigned i = 1; i <= k; i++)
r = (r*(n-k+i))/i;
return r;
}*/
 
 
 
template <typename ValueType>
class BinomialCoefficient
{
public:
typedef ValueType value_type;
typedef std::vector<value_type> container_type;
 
BinomialCoefficient(unsigned int _n)
: n(_n), m(n >> 1)
{
coefficients.reserve(m+1);
coefficients.push_back(1);
int h = m + 1;
value_type bct = 1;
for (int i = 1; i < h; ++i)
{
bct *= (n-i+1);
bct /= i;
coefficients.push_back(bct);
}
}
 
unsigned int size() const
{
return degree() +1;
}
 
unsigned int degree() const
{
return n;
}
 
value_type operator[] (unsigned int k) const
{
if (k > m) k = n - k;
return coefficients[k];
}
 
private:
const int n;
const unsigned int m;
container_type coefficients;
};
 
 
 
 
 
 
 
#endif
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/sbasis-2d.cpp
1,10 → 1,9
#include <sbasis-2d.h>
#include <sbasis-geometric.h>
#include "sbasis-2d.h"
 
namespace Geom{
 
SBasis extract_u(SBasis2d const &a, double u) {
SBasis sb(a.vs, Linear());
SBasis sb;
double s = u*(1-u);
for(unsigned vi = 0; vi < a.vs; vi++) {
14,7 → 13,7
bo += (extract_u(a.index(ui, vi), u))*sk;
sk *= s;
}
sb[vi] = bo;
sb.push_back(bo);
}
return sb;
21,7 → 20,7
}
 
SBasis extract_v(SBasis2d const &a, double v) {
SBasis sb(a.us, Linear());
SBasis sb;
double s = v*(1-v);
for(unsigned ui = 0; ui < a.us; ui++) {
31,7 → 30,7
bo += (extract_v(a.index(ui, vi), v))*sk;
sk *= s;
}
sb[ui] = bo;
sb.push_back(bo);
}
return sb;
70,133 → 69,4
return D2<SBasis>(compose(fg[X], p), compose(fg[Y], p));
}
 
SBasis2d partial_derivative(SBasis2d const &f, int dim) {
SBasis2d result;
for(unsigned i = 0; i < f.size(); i++) {
result.push_back(Linear2d(0,0,0,0));
}
result.us = f.us;
result.vs = f.vs;
 
for(unsigned i = 0; i < f.us; i++) {
for(unsigned j = 0; j < f.vs; j++) {
Linear2d lin = f.index(i,j);
Linear2d dlin(lin[1+dim]-lin[0], lin[1+2*dim]-lin[dim], lin[3-dim]-lin[2*(1-dim)], lin[3]-lin[2-dim]);
result[i+j*result.us] += dlin;
unsigned di = dim?j:i;
if (di>=1){
float motpi = dim?-1:1;
Linear2d ds_lin_low( lin[0], -motpi*lin[1], motpi*lin[2], -lin[3] );
result[(i+dim-1)+(j-dim)*result.us] += di*ds_lin_low;
Linear2d ds_lin_hi( lin[1+dim]-lin[0], lin[1+2*dim]-lin[dim], lin[3]-lin[2-dim], lin[3-dim]-lin[2-dim] );
result[i+j*result.us] += di*ds_lin_hi;
}
}
}
return result;
}
 
/**
* Finds a path which traces the 0 contour of f, traversing from A to B as a single d2<sbasis>.
* degmax specifies the degree (degree = 2*degmax-1, so a degmax of 2 generates a cubic fit).
* The algorithm is based on dividing out derivatives at each end point and does not use the curvature for fitting.
* It is less accurate than sb2d_cubic_solve, although this may be fixed in the future.
*/
D2<SBasis>
sb2dsolve(SBasis2d const &f, Geom::Point const &A, Geom::Point const &B, unsigned degmax){
//g_warning("check f(A)= %f = f(B) = %f =0!", f.apply(A[X],A[Y]), f.apply(B[X],B[Y]));
 
SBasis2d dfdu = partial_derivative(f, 0);
SBasis2d dfdv = partial_derivative(f, 1);
Geom::Point dfA(dfdu.apply(A[X],A[Y]),dfdv.apply(A[X],A[Y]));
Geom::Point dfB(dfdu.apply(B[X],B[Y]),dfdv.apply(B[X],B[Y]));
Geom::Point nA = dfA/(dfA[X]*dfA[X]+dfA[Y]*dfA[Y]);
Geom::Point nB = dfB/(dfB[X]*dfB[X]+dfB[Y]*dfB[Y]);
 
D2<SBasis>result(SBasis(degmax, Linear()), SBasis(degmax, Linear()));
double fact_k=1;
double sign = 1.;
for(int dim = 0; dim < 2; dim++)
result[dim][0] = Linear(A[dim],B[dim]);
for(unsigned k=1; k<degmax; k++){
// these two lines make the solutions worse!
//fact_k *= k;
//sign = -sign;
SBasis f_on_curve = compose(f,result);
Linear reste = f_on_curve[k];
double ax = -reste[0]/fact_k*nA[X];
double ay = -reste[0]/fact_k*nA[Y];
double bx = -sign*reste[1]/fact_k*nB[X];
double by = -sign*reste[1]/fact_k*nB[Y];
 
result[X][k] = Linear(ax,bx);
result[Y][k] = Linear(ay,by);
//sign *= 3;
}
return result;
}
 
/**
* Finds a path which traces the 0 contour of f, traversing from A to B as a single cubic d2<sbasis>.
* The algorithm is based on matching direction and curvature at each end point.
*/
//TODO: handle the case when B is "behind" A for the natural orientation of the level set.
//TODO: more generally, there might be up to 4 solutions. Choose the best one!
D2<SBasis>
sb2d_cubic_solve(SBasis2d const &f, Geom::Point const &A, Geom::Point const &B){
D2<SBasis>result;//(Linear(A[X],B[X]),Linear(A[Y],B[Y]));
//g_warning("check 0 = %f = %f!", f.apply(A[X],A[Y]), f.apply(B[X],B[Y]));
 
SBasis2d f_u = partial_derivative(f , 0);
SBasis2d f_v = partial_derivative(f , 1);
SBasis2d f_uu = partial_derivative(f_u, 0);
SBasis2d f_uv = partial_derivative(f_v, 0);
SBasis2d f_vv = partial_derivative(f_v, 1);
 
Geom::Point dfA(f_u.apply(A[X],A[Y]),f_v.apply(A[X],A[Y]));
Geom::Point dfB(f_u.apply(B[X],B[Y]),f_v.apply(B[X],B[Y]));
 
Geom::Point V0 = rot90(dfA);
Geom::Point V1 = rot90(dfB);
double D2fVV0 = f_uu.apply(A[X],A[Y])*V0[X]*V0[X]+
2*f_uv.apply(A[X],A[Y])*V0[X]*V0[Y]+
f_vv.apply(A[X],A[Y])*V0[Y]*V0[Y];
double D2fVV1 = f_uu.apply(B[X],B[Y])*V1[X]*V1[X]+
2*f_uv.apply(B[X],B[Y])*V1[X]*V1[Y]+
f_vv.apply(B[X],B[Y])*V1[Y]*V1[Y];
 
std::vector<D2<SBasis> > candidates = cubics_fitting_curvature(A,B,V0,V1,D2fVV0,D2fVV1);
if (candidates.size()==0) {
return D2<SBasis>(Linear(A[X],B[X]),Linear(A[Y],B[Y]));
}
//TODO: I'm sure std algorithm could do that for me...
double error = -1;
unsigned best = 0;
for (unsigned i=0; i<candidates.size(); i++){
Interval bounds = *bounds_fast(compose(f,candidates[i]));
double new_error = (fabs(bounds.max())>fabs(bounds.min()) ? fabs(bounds.max()) : fabs(bounds.min()) );
if ( new_error < error || error < 0 ){
error = new_error;
best = i;
}
}
return candidates[best];
}
 
 
 
 
};
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/sbasis-roots.cpp
8,7 → 8,7
* multi-roots 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,
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
44,33 → 44,16
#include <cmath>
#include <map>
 
#include <sbasis.h>
#include <sbasis-to-bezier.h>
#include <solver.h>
#include "sbasis.h"
#include "sbasis-to-bezier.h"
#include "solver.h"
 
using namespace std;
 
namespace Geom{
 
/** Find the smallest interval that bounds a
\param a sbasis function
\returns inteval
 
*/
 
#ifdef USE_SBASIS_OF
OptInterval bounds_exact(SBasisOf<double> const &a) {
Interval bounds_exact(SBasis const &a) {
Interval result = Interval(a.at0(), a.at1());
SBasisOf<double> df = derivative(a);
vector<double>extrema = roots(df);
for (unsigned i=0; i<extrema.size(); i++){
result.extendTo(a(extrema[i]));
}
return result;
}
#else
OptInterval 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++){
78,21 → 61,9
}
return result;
}
#endif
 
/** Find a small interval that bounds a
\param a sbasis function
\returns inteval
 
*/
// I have no idea how this works, some clever bounding argument by jfb.
#ifdef USE_SBASIS_OF
OptInterval bounds_fast(const SBasisOf<double> &sb, int order) {
#else
OptInterval bounds_fast(const SBasis &sb, int order) {
#endif
Interval res(0,0); // an empty sbasis is 0.
 
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];
118,19 → 89,8
return res;
}
 
/** Find a small interval that bounds a(t) for t in i to order order
\param sb sbasis function
\param i domain interval
\param order number of terms
\return interval
 
*/
#ifdef USE_SBASIS_OF
OptInterval bounds_local(const SBasisOf<double> &sb, const OptInterval &i, int order) {
#else
OptInterval bounds_local(const SBasis &sb, const OptInterval &i, int order) {
#endif
double t0=i->min(), t1=i->max(), lo=0., hi=0.;
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];
164,7 → 124,7
going from f(a) up to C with slope M takes at least time (C-f(a))/M
From this we conclude there are no roots before a'=a+min((f(a)-c)/m,(C-f(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'].
-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...
*/
175,13 → 135,8
return(upper_bound(levels.begin(),levels.end(),x-tol)-levels.begin());
}
 
#ifdef USE_SBASIS_OF
static void multi_roots_internal(SBasis const &f,
SBasis const &df,
#else
static void multi_roots_internal(SBasis const &f,
SBasis const &df,
#endif
std::vector<double> const &levels,
std::vector<std::vector<double> > &roots,
double htol,
190,7 → 145,7
double fa,
double b,
double fb){
 
if (f.size()==0){
int idx;
idx=upper_level(levels,0,vtol);
200,7 → 155,7
}
return;
}
////usefull?
////usefull?
// if (f.size()==1){
// int idxa=upper_level(levels,fa);
// int idxb=upper_level(levels,fb);
231,11 → 186,11
}
return;
}
 
int idxa=upper_level(levels,fa,vtol);
int idxb=upper_level(levels,fb,vtol);
 
Interval bs = *bounds_local(df,Interval(a,b));
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;
262,9 → 217,9
if (bs.max()>0 && idxb>0)
tb_lo=b+(levels.at(idxb-1)-fb)/bs.max();
}
 
double t0,t1;
t0=std::min(ta_hi,ta_lo);
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.
289,29 → 244,6
}
}
 
/** Solve f(t)=c for several c at once.
\param f sbasis function
\param levels vector of 'y' values
\param htol, vtol
\param a, b left and right bounds
\returns a vector of vectors, one for each y giving roots
 
Effectively computes:
results = roots(f(y_i)) for all y_i
 
* 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 (C-f(a))/M
From this we conclude there are no roots before a'=a+min((f(a)-c)/m,(C-f(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 "rounding-errors proof" and take care about repetition of roots!
*/
std::vector<std::vector<double> > multi_roots(SBasis const &f,
std::vector<double> const &levels,
double htol,
322,223 → 254,69
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));
multi_roots_internal(f,df,levels,roots,htol,vtol,a,f(a),b,f(b));
 
return(roots);
}
//-------------------------------------
 
 
static bool compareIntervalMin( Interval I, Interval J ){
return I.min()<J.min();
}
static bool compareIntervalMax( Interval I, Interval J ){
return I.max()<J.max();
}
 
//find the first interval whose max is >= x
static unsigned upper_level(vector<Interval> const &levels, double x ){
return( lower_bound( levels.begin(), levels.end(), Interval(x,x), compareIntervalMax) - levels.begin() );
}
 
static std::vector<Interval> fuseContiguous(std::vector<Interval> const &sets, double tol=0.){
std::vector<Interval> result;
if (sets.size() == 0 ) return result;
result.push_back( sets.front() );
for (unsigned i=1; i < sets.size(); i++ ){
if ( result.back().max() + tol >= sets[i].min() ){
result.back().unionWith( sets[i] );
}else{
result.push_back( sets[i] );
}
}
return result;
}
 
/** level_sets internal method.
* algorithm: (~adaptation of Newton method versus 'accroissements finis')
-compute f at both ends of the given segment [a,b].
-compute bounds m<df(t)<M for df on the segment.
Suppose f(a) is between two 'levels' c and C. Then
f wont enter c before a + (f(a)-c.max())/m
f wont enter C before a + (C.min()-f(a))/M
From this we conclude nothing happens before a'=a+min((f(a)-c.max())/m,(C.min()-f(a))/M).
We do the same for b: compute some b' such that nothing happens in (b',b].
-if [a',b'] is not empty, repeat the process with [a',(a'+b')/2] and [(a'+b')/2,b'].
 
If f(a) or f(b) belongs to some 'level' C, then use the same argument to find a' or b' such
that f remains in C on [a,a'] or [b',b]. In case f is monotonic, we also know f won't enter another
level before or after some time, allowing us to restrict the search a little more.
 
unfortunately, extra care is needed about rounding errors, and also to avoid the repetition of roots,
making things tricky and unpleasant...
*/
 
static void level_sets_internal(SBasis const &f,
SBasis const &df,
std::vector<Interval> const &levels,
std::vector<std::vector<Interval> > &solsets,
double a,
double fa,
double b,
double fb,
double tol=1e-5){
 
if (f.size()==0){
unsigned idx;
idx=upper_level( levels, 0. );
if (idx<levels.size() && levels[idx].contains(0.)){
solsets[idx].push_back( Interval(a,b) ) ;
#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;
}
return;
err *= 1e-7; // 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*H-G*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;
}
 
unsigned idxa=upper_level(levels,fa);
unsigned idxb=upper_level(levels,fb);
 
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; // f remains below next level for t<ta_hi
double ta_lo; // f remains above prev level for t<ta_lo
double tb_hi; // f remains below next level for t>tb_hi
double tb_lo; // f remains above next level for t>tb_lo
 
ta_hi=ta_lo=b+1;//default values => no root there.
tb_hi=tb_lo=a-1;//default values => no root there.
 
//--- if f(a) belongs to a level.-------
if ( idxa < levels.size() && levels[idxa].contains( fa ) ){
//find the first time when we may exit this level.
ta_lo = a + ( levels[idxa].min() - fa)/bs.min();
ta_hi = a + ( levels[idxa].max() - fa)/bs.max();
if ( ta_lo < a || ta_lo > b ) ta_lo = b;
if ( ta_hi < a || ta_hi > b ) ta_hi = b;
//move to that time for the next iteration.
solsets[idxa].push_back( Interval( a, std::min( ta_lo, ta_hi ) ) );
}else{
//--- if f(b) does not belong to a level.-------
if ( idxa == 0 ){
ta_lo = b;
}else{
ta_lo = a + ( levels[idxa-1].max() - fa)/bs.min();
if ( ta_lo < a ) ta_lo = b;
}
if ( idxa == levels.size() ){
ta_hi = b;
}else{
ta_hi = a + ( levels[idxa].min() - fa)/bs.max();
if ( ta_hi < a ) ta_hi = b;
}
}
 
//--- if f(b) belongs to a level.-------
if (idxb<levels.size() && levels.at(idxb).contains(fb)){
//find the first time from b when we may exit this level.
tb_lo = b + ( levels[idxb].min() - fb ) / bs.max();
tb_hi = b + ( levels[idxb].max() - fb ) / bs.min();
if ( tb_lo > b || tb_lo < a ) tb_lo = a;
if ( tb_hi > b || tb_hi < a ) tb_hi = a;
//move to that time for the next iteration.
solsets[idxb].push_back( Interval( std::max( tb_lo, tb_hi ), b) );
}else{
//--- if f(b) does not belong to a level.-------
if ( idxb == 0 ){
tb_lo = a;
}else{
tb_lo = b + ( levels[idxb-1].max() - fb)/bs.max();
if ( tb_lo > b ) tb_lo = a;
}
if ( idxb == levels.size() ){
tb_hi = a;
}else{
tb_hi = b + ( levels[idxb].min() - fb)/bs.min();
if ( tb_hi > b ) tb_hi = a;
}
 
 
if ( bs.min() < 0 && idxb < levels.size() )
tb_hi = b + ( levels[idxb ].min() - fb ) / bs.min();
if ( bs.max() > 0 && idxb > 0 )
tb_lo = b + ( levels[idxb-1].max() - fb ) / bs.max();
}
 
//let [t0,t1] be the next interval where to search.
double t0=std::min(ta_hi,ta_lo);
double t1=std::max(tb_hi,tb_lo);
 
if (t0>=t1) return;//no root here.
 
//if the interval is smaller than our resolution:
//pretend f simultaneously meets all the levels between f(t0) and f(t1)...
if ( t1 - t0 <= tol ){
Interval f_t0t1 ( f(t0), f(t1) );
unsigned idxmin = std::min(idxa, idxb);
unsigned idxmax = std::max(idxa, idxb);
//push [t0,t1] into all crossed level. Cheat to avoid overlapping intervals on different levels?
if ( idxmax > idxmin ){
for (unsigned idx = idxmin; idx < idxmax; idx++){
solsets[idx].push_back( Interval( t0, t1 ) );
}
}
if ( idxmax < levels.size() && f_t0t1.intersects( levels[idxmax] ) ){
solsets[idxmax].push_back( Interval( t0, t1 ) );
}
return;
}
 
//To make sure we finally exit the level jump at least by tol:
t0 = std::min( std::max( t0, a + tol ), b );
t1 = std::max( std::min( t1, b - tol ), a );
 
double t =(t0+t1)/2;
double ft=f(t);
level_sets_internal( f, df, levels, solsets, t0, f(t0), t, ft );
level_sets_internal( f, df, levels, solsets, t, ft, t1, f(t1) );
//std::cout << "xk = " << xk << std::endl;
return xk;
}
#endif
 
std::vector<std::vector<Interval> > level_sets(SBasis const &f,
std::vector<Interval> const &levels,
double a, double b, double tol){
 
std::vector<std::vector<Interval> > solsets(levels.size(), std::vector<Interval>());
 
SBasis df=derivative(f);
level_sets_internal(f,df,levels,solsets,a,f(a),b,f(b),tol);
// Fuse overlapping intervals...
for (unsigned i=0; i<solsets.size(); i++){
if ( solsets[i].size() == 0 ) continue;
std::sort( solsets[i].begin(), solsets[i].end(), compareIntervalMin );
solsets[i] = fuseContiguous( solsets[i], tol );
}
return solsets;
}
 
std::vector<Interval> level_set (SBasis const &f, double level, double vtol, double a, double b, double tol){
Interval fat_level( level - vtol, level + vtol );
return level_set(f, fat_level, a, b, tol);
}
std::vector<Interval> level_set (SBasis const &f, Interval const &level, double a, double b, double tol){
std::vector<Interval> levels(1,level);
return level_sets(f,levels, a, b, tol).front() ;
}
std::vector<std::vector<Interval> > level_sets (SBasis const &f, std::vector<double> const &levels, double vtol, double a, double b, double tol){
std::vector<Interval> fat_levels( levels.size(), Interval());
for (unsigned i = 0; i < levels.size(); i++){
fat_levels[i] = Interval( levels[i]-vtol, levels[i]+vtol);
}
return level_sets(f, fat_levels, a, b, tol);
}
 
 
//-------------------------------------
//-------------------------------------
 
 
void subdiv_sbasis(SBasis const & s,
std::vector<double> & roots,
std::vector<double> & roots,
double left, double right) {
OptInterval bs = bounds_fast(s);
if(!bs || bs->min() > 0 || bs->max() < 0)
Interval bs = bounds_fast(s);
if(bs.min() > 0 || bs.max() < 0)
return; // no roots here
if(s.tailError(1) < 1e-7) {
double t = s[0][0] / (s[0][0] - s[0][1]);
552,61 → 330,11
 
// It is faster to use the bernstein root finder for small degree polynomials (<100?.
 
std::vector<double> roots1(SBasis const & s) {
std::vector<double> res;
double d = s[0][0] - s[0][1];
if(d != 0) {
double r = s[0][0] / d;
if(0 <= r && r <= 1)
res.push_back(r);
}
return res;
}
 
std::vector<double> roots1(SBasis const & s, Interval const ivl) {
std::vector<double> res;
double d = s[0][0] - s[0][1];
if(d != 0) {
double r = s[0][0] / d;
if(ivl.contains(r))
res.push_back(r);
}
return res;
}
 
/** Find all t s.t s(t) = 0
\param a sbasis function
\returns vector of zeros (roots)
 
*/
std::vector<double> roots(SBasis const & s) {
switch(s.size()) {
case 0:
return std::vector<double>();
case 1:
return roots1(s);
default:
{
Bezier bz;
sbasis_to_bezier(bz, s);
return bz.roots();
}
}
if(s.size() == 0) return std::vector<double>();
return sbasis_to_bezier(s).roots();
}
std::vector<double> roots(SBasis const & s, Interval const ivl) {
switch(s.size()) {
case 0:
return std::vector<double>();
case 1:
return roots1(s, ivl);
default:
{
Bezier bz;
sbasis_to_bezier(bz, s);
return bz.roots(ivl);
}
}
}
 
};
 
/trunk/Scribus/scribus/third_party/lib2geom/interval.h
1,7 → 1,6
/**
* \file
* \brief Simple closed interval class
*//*
/*
* interval.h - Simple closed interval class
*
* Copyright 2007 Michael Sloan <mgsloan@gmail.com>
*
* Original Rect/Range code by:
34,354 → 33,196
* the specific language governing rights and limitations.
*
*/
#ifndef LIB2GEOM_SEEN_INTERVAL_H
#define LIB2GEOM_SEEN_INTERVAL_H
#ifndef SEEN_INTERVAL_H
#define SEEN_INTERVAL_H
 
#include <assert.h>
#include <boost/none.hpp>
#include <boost/optional.hpp>
#include <boost/operators.hpp>
#include "coord.h"
#include "isnan.h"
 
#include <boost/optional/optional.hpp>
 
//error in miesh_distortion
#ifdef min
# undef min
#endif
 
#ifdef max
# undef max
#endif
 
namespace Geom {
 
class OptInterval;
 
/**
* @brief Range of numbers that is never empty.
*
* Intervals are closed ranges \f$[a, b]\f$, which means they include their endpoints.
* To use them as open ranges, you can use the interiorContains() methods.
*
* @ingroup Primitives
*/
class Interval
: boost::equality_comparable< Interval
, boost::additive< Interval
, boost::multipliable< Interval
, boost::arithmetic< Interval, Coord
, boost::orable< Interval
> > > > >
{
//
class Interval {
private:
/// @invariant _b[0] <= _b[1]
Coord _b[2];
 
public:
/// @name Create intervals.
/// @{
/** @brief Create an interval that contains only zero. */
explicit Interval() { _b[0] = 0; _b[1] = 0; }
/** @brief Create an interval that contains a single point. */
//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; }
/** @brief Create an interval that contains all points between @c u and @c v. */
Interval(Coord u, Coord v) {
if (u <= v) {
if(u < v) {
_b[0] = u; _b[1] = v;
} else {
_b[0] = v; _b[1] = u;
}
}
 
/** @brief Create an interval containing a range of values.
* The resulting interval will contain all values from the given range.
* The return type of iterators must be convertible to double. The given range
* must not be empty. For potentially empty ranges, see OptInterval.
* @param start Beginning of the range
* @param end End of the range
* @return Interval that contains all values from [start, end). */
template <typename InputIterator>
static Interval from_range(InputIterator start, InputIterator end) {
assert(start != end);
Interval result(*start++);
for (; start != end; ++start) result.extendTo(*start);
return result;
double operator[](unsigned i) const {
assert(i < 2);
return _b[i];
}
/** @brief Create an interval from a C-style array of values it should contain. */
static Interval from_array(Coord const *c, int n) {
Interval result = from_range(c, c+n);
return result;
}
/// @}
 
/// @name Inspect endpoints.
/// @{
Coord operator[](unsigned i) const { return _b[i]; }
Coord& operator[](unsigned i) { return _b[i]; }
 
Coord min() const { return _b[0]; }
Coord max() const { return _b[1]; }
Coord extent() const { return _b[1] - _b[0]; }
Coord middle() const { return (_b[1] + _b[0]) * 0.5; }
bool isSingular() const { return _b[0] == _b[1]; }
bool isFinite() const {
return IS_FINITE(_b[0]) && IS_FINITE(_b[1]);
}
/// @}
 
/// @name Test coordinates and other intervals for inclusion.
/// @{
/** @brief Check whether the interval includes this number. */
bool contains(Coord val) const { return _b[0] <= val && val <= _b[1]; }
/** @brief Check whether the interior of the interval includes this number.
* Interior means all numbers in the interval except its ends. */
bool interiorContains(Coord val) const { return _b[0] < val && val < _b[1]; }
/** @brief Check whether the interval includes the given interval. */
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]; }
/** @brief Check whether the interior of the interval includes the given interval.
* Interior means all numbers in the interval except its ends. */
bool interiorContains(const Interval & val) const { return _b[0] < val._b[0] && val._b[1] < _b[1]; }
/** @brief Check whether the intervals have any common elements. */
bool intersects(const Interval & val) const {
return contains(val._b[0]) || contains(val._b[1]) || val.contains(*this);
}
/// @}
 
/// @name Modify the interval.
/// @{
//TODO: NaN handleage for the next two?
/** @brief Set the lower boundary of the interval.
* When the given number is larger than the interval's largest element,
* it will be reduced to the single number @c val. */
void setMin(Coord val) {
if(val > _b[1]) {
_b[0] = _b[1] = val;
} else {
_b[0] = val;
}
}
/** @brief Set the upper boundary of the interval.
* When the given number is smaller than the interval's smallest element,
* it will be reduced to the single number @c val. */
void setMax(Coord val) {
if(val < _b[0]) {
_b[1] = _b[0] = val;
} else {
_b[1] = val;
}
}
/** @brief Extend the interval to include the given number. */
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
}
/** @brief Expand or shrink the interval in both directions by the given amount.
* After this method, the interval's length (extent) will be increased by
* <code>amount * 2</code>. Negative values can be given; they will shrink the interval.
* Shrinking by a value larger than half the interval's length will create a degenerate
* interval containing only the midpoint of the original. */
void expandBy(double amount) {
_b[0] -= amount;
_b[1] += amount;
if (_b[0] > _b[1]) {
Coord halfway = (_b[0]+_b[1])/2;
_b[0] = _b[1] = halfway;
}
}
/** @brief Union the interval with another one.
* The resulting interval will contain all points of both intervals.
* It might also contain some points which didn't belong to either - this happens
* when the intervals did not have any common elements. */
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];
}
/// @}
 
/// @name Operators
/// @{
inline operator OptInterval();
bool operator==(Interval const &other) const { 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]; }
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;
/** @brief Offset the interval by a specified amount */
Interval &operator+=(Coord amnt) {
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;
}
/** @brief Offset the interval by the negation of the specified amount */
Interval &operator-=(Coord amnt) {
inline Interval operator-=(Coord amnt) {
_b[0] -= amnt; _b[1] -= amnt;
return *this;
}
// IMPL: ScalableConcept
/** @brief Return an interval mirrored about 0 */
inline Interval operator-() const { return Interval(-_b[1], -_b[0]); }
/** @brief Scale an interval */
Interval &operator*=(Coord s) {
_b[0] *= s;
_b[1] *= s;
if(s < 0) std::swap(_b[0], _b[1]);
//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;
}
/** @brief Scale an interval by the inverse of the specified value */
Interval &operator/=(Coord s) {
_b[0] /= s;
_b[1] /= s;
if(s < 0) std::swap(_b[0], _b[1]);
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;
}
// IMPL: AddableConcept
/** @brief Add two intervals.
* Sum is defined as the set of points that can be obtained by adding any two values
* from both operands: \f$S = \{x \in A, y \in B: x + y\}\f$ */
Interval &operator+=(Interval const &o) {
_b[0] += o._b[0];
_b[1] += o._b[1];
return *this;
}
/** @brief Subtract two intervals.
* Difference is defined as the set of points that can be obtained by subtracting
* any value from the second operand from any value from the first operand:
* \f$S = \{x \in A, y \in B: x - y\}\f$ */
Interval &operator-=(Interval const &o) {
// equal to *this += -o
_b[0] -= o._b[1];
_b[1] -= o._b[0];
return *this;
}
/** @brief Multiply two intervals.
* Product is defined as the set of points that can be obtained by multiplying
* any value from the second operand by any value from the first operand:
* \f$S = \{x \in A, y \in B: x * y\}\f$ */
Interval &operator*=(Interval const &o) {
// TODO implement properly
Coord mn = min(), mx = max();
extendTo(mn * o.min());
extendTo(mn * o.max());
extendTo(mx * o.min());
extendTo(mx * o.max());
return *this;
}
/** @brief Union two intervals.
* Note that intersection is only defined for OptIntervals, because the result
* of an intersection can be empty, while an Interval cannot. */
Interval &operator|=(Interval const &o) {
unionWith(o);
return *this;
}
/// @}
};
 
/** @brief Union two intervals
* @relates Interval */
inline Interval unify(Interval const &a, Interval const &b) {
return a | b;
}
 
/**
* @brief A range of numbers that can be empty.
* @ingroup Primitives
*/
class OptInterval
: public boost::optional<Interval>
, boost::orable< OptInterval
, boost::andable< OptInterval
> >
{
public:
/// @name Create optionally empty intervals.
/// @{
/** @brief Create an empty interval. */
OptInterval() : boost::optional<Interval>() {};
/** @brief Wrap an existing interval. */
OptInterval(Interval const &a) : boost::optional<Interval>(a) {};
/** @brief Create an interval containing a single point. */
OptInterval(Coord u) : boost::optional<Interval>(Interval(u)) {};
/** @brief Create an interval containing a range of numbers. */
OptInterval(Coord u, Coord v) : boost::optional<Interval>(Interval(u,v)) {};
 
/** @brief Create a possibly empty interval containing a range of values.
* The resulting interval will contain all values from the given range.
* The return type of iterators must be convertible to double. The given range
* may be empty.
* @param start Beginning of the range
* @param end End of the range
* @return Interval that contains all values from [start, end), or nothing if the range
* is empty. */
template <typename InputIterator>
static OptInterval from_range(InputIterator start, InputIterator end) {
if (start == end) {
OptInterval ret;
return ret;
//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;
}
OptInterval ret(Interval::from_range(start, end));
return ret;
}
/// @}
 
/** @brief Check whether this OptInterval is empty. */
bool isEmpty() { return !*this; };
 
/** @brief Union with another interval, gracefully handling empty ones. */
inline void unionWith(OptInterval const &a) {
if (a) {
if (*this) { // check that we are not empty
(*this)->unionWith(*a);
} else {
*this = a;
}
//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 intersectWith(OptInterval const &o) {
if (o && *this) {
Coord u, v;
u = std::max((*this)->min(), o->min());
v = std::min((*this)->max(), o->max());
if (u <= v) {
*this = Interval(u, v);
return;
}
}
(*static_cast<boost::optional<Interval>*>(this)) = boost::none;
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
}
OptInterval &operator|=(OptInterval const &o) {
unionWith(o);
return *this;
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;
}
OptInterval &operator&=(OptInterval const &o) {
intersectWith(o);
return *this;
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];
}
};
 
/** @brief Intersect two intervals and return a possibly empty range of numbers
* @relates OptInterval */
inline OptInterval intersect(Interval const &a, Interval const &b) {
return OptInterval(a) & OptInterval(b);
//IMPL: AddableConcept
inline Interval operator+(const Interval & a, const Interval & b) {
return Interval(a.min() + b.min(), a.max() + b.max());
}
/** @brief Intersect two intervals and return a possibly empty range of numbers
* @relates OptInterval */
inline OptInterval operator&(Interval const &a, Interval const &b) {
return OptInterval(a) & OptInterval(b);
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; }
 
inline Interval::operator OptInterval() {
return OptInterval(*this);
//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; }
 
#ifdef _GLIBCXX_IOSTREAM
inline std::ostream &operator<< (std::ostream &os,
const Geom::Interval &I) {
os << "Interval("<<I[0] << ", "<<I[1] << ")";
return os;
/* 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;
}
#endif
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
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/point.cpp
1,46 → 1,27
#include "point.h"
#include <assert.h>
#include <math.h>
#include <point.h>
#include <transforms.h>
#include "coord.h"
#include "isnan.h" //temporary fix for isnan()
#include "matrix.h"
#include <limits>
 
 
namespace Geom {
 
/**
* @class Point
* @brief Two-dimensional point that doubles as a vector.
/** Scales this vector to make it a unit vector (within rounding error).
*
* Points in 2Geom are represented in Cartesian coordinates, e.g. as a pair of numbers
* that store the X and Y coordinates. Each point is also a vector in \f$\mathbb{R}^2\f$
* from the origin (point at 0,0) to the stored coordinates,
* and has methods implementing several vector operations (like length()).
* The current version tries to handle infinite coordinates gracefully,
* but it's not clear that any callers need that.
*
* \par Operator note
* \par
* Most operators are provided by Boost operator helpers, so they are not visible in this class.
* If @a p, @a q, @a r denote points, @a s a floating-point scalar, and @a m a transformation matrix,
* then the following operations are available:
* @code
p += q; p -= q; r = p + q; r = p - q;
p *= s; p /= s; q = p * s; q = s * p; q = p / s;
p *= m; p /= m; q = p * m; q = m * p; q = p / m;
@endcode
* It is possible to left-multiply a point by a matrix, even though mathematically speaking
* this is undefined. The result is a point identical to that obtained by right-multiplying.
* Division of points by matrices is defined as multiplication by their inverses.
*
* @ingroup Primitives */
 
/** @brief Normalize the vector representing the point.
* After this method returns, the length of the vector will be 1 (unless both coordinates are
* zero - the zero point will be returned then). The function tries to handle infinite
* coordinates gracefully. If any of the coordinates are NaN, the function will do nothing.
* @post \f$-\epsilon < \left|this\right| - 1 < \epsilon\f$
* @see unit_vector(Geom::Point const &) */
* \pre \f$this \neq (0, 0)\f$
* \pre Neither component is NaN.
* \post \f$-\epsilon<\left|this\right|-1<\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 = HUGE_VAL;
if(is_nan(len)) return;
static double const inf = std::numeric_limits<double>::infinity();
if(len != inf) {
*this /= len;
} else {
59,30 → 40,27
}
}
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;
}
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;
}
}
}
}
 
/** @brief Compute the first norm (Manhattan distance) of @a p.
* This is equal to the sum of absolutes values of the coordinates.
* @return \f$|p_X| + |p_Y|\f$
* @relates Point */
/** 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++ ) {
91,53 → 69,57
return d;
}
 
/** @brief Compute the infinity norm (maximum norm) of @a p.
* @return \f$\max(p_X, p_Y)\f$
* @relates Point */
/** 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)
return ( a < b || is_nan(b)
? b
: a );
}
 
/** @brief True if the point has both coordinates zero.
* NaNs are treated as not equal to zero.
* @relates Point */
bool is_zero(Point const &p) {
/** Returns true iff p is a zero vector, i.e.\ Point(0, 0).
*
* (NaN is considered non-zero.)
*/
bool
is_zero(Point const &p)
{
return ( p[0] == 0 &&
p[1] == 0 );
}
 
/** @brief True if the point has a length near 1. The are_near() function is used.
* @relates Point */
bool is_unit_vector(Point const &p) {
return are_near(L2(p), 1.0);
bool
is_unit_vector(Point const &p)
{
return fabs(1.0 - L2(p)) <= 1e-4;
/* The tolerance of 1e-4 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. */
}
/** @brief Return the angle between the point and the +X axis.
* @return Angle in \f$(-\pi, \pi]\f$.
* @relates Point */
Coord atan2(Point const &p) {
 
Coord atan2(Point const p) {
return std::atan2(p[Y], p[X]);
}
 
/** @brief Compute the angle between a and b relative to the origin.
* The computation is done by projecting b onto the basis defined by a, rot90(a).
* @return Angle in \f$(-\pi, \pi]\f$.
* @relates Point */
Coord angle_between(Point const &a, Point const &b) {
/** 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));
}
 
/** @brief Create a normalized version of a point.
* This is equivalent to copying the point and calling its normalize() method.
* The returned point will be (0,0) if the argument has both coordinates equal to zero.
* If any coordinate is NaN, this function will do nothing.
* @param a Input point
* @return Point on the unit circle in the same direction from origin as a, or the origin
* if a has both coordinates equal to zero
* @relates Point */
 
 
/** 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);
144,54 → 126,33
ret.normalize();
return ret;
}
/** @brief Return the "absolute value" of the point's vector.
* This is defined in terms of the default lexicographical ordering. If the point is "larger"
* that the origin (0, 0), its negation is returned. This corresponds to making the Y coordinate
* positive. You can check whether the points' vectors have the same direction (e.g. lie
* on the same line passing through the origin) using
* @code abs(a).normalize() == abs(b).normalize() @endcode.
* To check with some margin of error, use
* @code are_near(abs(a).normalize(), abs(b).normalize()) @endcode.
* Although naively this should take the absolute value of each coordinate, such an operation
* is not very useful.
* @return \f$p' = (p_X, -p_Y)\f$
* @relates Point */
 
Point abs(Point const &b)
{
Point ret = b;
ret[Y] = fabs(ret[Y]);
Point ret;
for ( int i = 0 ; i < 2 ; i++ ) {
ret[i] = fabs(b[i]);
}
return ret;
}
 
/** @brief Transform the point by the specified matrix. */
Point &Point::operator*=(Affine const &m) {
double x = _pt[X], y = _pt[Y];
Point operator*(Point const &v, Matrix const &m) {
Point ret;
for(int i = 0; i < 2; i++) {
_pt[i] = x * m[i] + y * m[i + 2] + m[i + 4];
ret[i] = v[X] * m[i] + v[Y] * m[i + 2] + m[i + 4];
}
return *this;
return ret;
}
 
/** @brief Snap the angle B - A - dir to miltiples of \f$2\pi/n\f$.
* The 'dir' argument must be normalized (have an unit length), otherwise the result
* is undefined.
* @return Point with the same distance from A as B, with a snapped angle.
* @post distance(A, B) == distance(A, result)
* @post angle_between(result - A, dir) == \f$2k\pi/n, k \in \mathbb{N}\f$
* @relates Point */
Point constrain_angle(Point const &A, Point const &B, unsigned int n, Point const &dir)
Point operator/(Point const &p, Matrix const &m) { return p * m.inverse(); }
 
Point &Point::operator*=(Matrix const &m)
{
// for special cases we could perhaps use explicit testing (which might be faster)
if (n == 0.0) {
return B;
}
Point diff(B - A);
double angle = -angle_between(diff, dir);
double k = round(angle * (double)n / (2.0*M_PI));
return A + dir * Rotate(k * 2.0 * M_PI / (double)n) * L2(diff);
*this = *this * m;
return *this;
}
 
} //namespace Geom
} //Namespace Geom
 
/*
Local Variables:
/trunk/Scribus/scribus/third_party/lib2geom/sbasis.h
1,6 → 1,5
/**
* \file
* \brief Defines S-power basis function class
/*
* sbasis.h - S-power basis function class
*
* Authors:
* Nathan Hurst <njh@mail.csse.monash.edu.au>
43,79 → 42,21
#include "utils.h"
#include "exception.h"
 
//#define USE_SBASISN 1
namespace Geom {
 
 
#if defined(USE_SBASIS_OF)
 
#include "sbasis-of.h"
 
#elif defined(USE_SBASISN)
 
#include "sbasisN.h"
namespace Geom{
 
/*** An empty SBasis is identically 0. */
class SBasis : public SBasisN<1>;
 
};
#else
 
namespace Geom{
 
/**
* \brief S-power basis function class
*
* An empty SBasis is identically 0. */
class SBasis{
std::vector<Linear> d;
void push_back(Linear const&l) { d.push_back(l); }
 
class SBasis : public std::vector<Linear>{
public:
// As part of our migration away from SBasis isa vector we provide this minimal set of vector interface methods.
size_t size() const {return d.size();}
Linear operator[](unsigned i) const {
return d[i];
}
Linear& operator[](unsigned i) { return d.at(i); }
Linear const* begin() const { return (Linear const*)&*d.begin();}
Linear const* end() const { return (Linear const*)&*d.end();}
Linear* begin() { return (Linear*)&*d.begin();}
Linear* end() { return (Linear*)&*d.end();}
bool empty() const {return d.empty();}
Linear &back() {return d.back();}
Linear const &back() const {return d.back();}
void pop_back() { d.pop_back();}
void resize(unsigned n) { d.resize(n);}
void resize(unsigned n, Linear const& l) { d.resize(n, l);}
void reserve(unsigned n) { d.reserve(n);}
void clear() {d.clear();}
void insert(Linear* before, const Linear* src_begin, const Linear* src_end) { d.insert(std::vector<Linear>::iterator(before), src_begin, src_end);}
//void insert(Linear* aa, Linear* bb, Linear* cc} { d.insert(aa, bb, cc);}
Linear& at(unsigned i) { return d.at(i);}
//void insert(Linear* before, int& n, Linear const &l) { d.insert(std::vector<Linear>::iterator(before), n, l);}
bool operator==(SBasis const&B) const { return d == B.d;}
bool operator!=(SBasis const&B) const { return d != B.d;}
operator std::vector<Linear>() { return d;}
 
SBasis() {}
explicit SBasis(double a) {
push_back(Linear(a,a));
}
explicit SBasis(double a, double b) {
push_back(Linear(a,b));
}
SBasis(SBasis const & a) :
d(a.d)
std::vector<Linear>(a)
{}
SBasis(Linear const & bo) {
push_back(bo);
}
SBasis(Linear* bo) {
push_back(*bo);
}
explicit SBasis(size_t n, Linear const&l) : d(n, l) {}
 
//IMPL: FragmentConcept
typedef double output_type;
128,9 → 69,8
}
inline bool isConstant() const {
if (empty()) return true;
if(!(*this)[0].isConstant()) return false;
for (unsigned i = 1; i < size(); i++) {
if(!(*this)[i].isZero()) return false;
for (unsigned i = 0; i < size(); i++) {
if(!(*this)[i].isConstant()) return false;
}
return true;
}
142,26 → 82,41
inline double at1() const{
if(empty()) return 0; else return (*this)[0][1];
}
int degreesOfFreedom() const { return size()*2;}
 
double valueAt(double t) const {
double s = t*(1-t);
double p0 = 0, p1 = 0;
for(unsigned k = size(); k > 0; k--) {
const Linear &lin = (*this)[k-1];
p0 = p0*s + lin[0];
p1 = p1*s + lin[1];
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 (1-t)*p0 + t*p1;
}
//double valueAndDerivative(double t, double &der) const {
//}
double valueAndDerivative(double t, double &der) const {
double s = t*(1-t);
double p0 = 0, p1 = 0;
double sk = 1;
//TODO: rewrite as horner
for(unsigned k = 0; k < size(); k++) {
p0 += sk*(*this)[k][0];
p1 += sk*(*this)[k][1];
sk *= s;
}
// p0 and p1 at this point form a linear approximation at t
der = p1 - p0;
return (1-t)*p0 + t*p1;
}
double operator()(double t) const {
return valueAt(t);
}
 
std::vector<double> valueAndDerivatives(double t, unsigned n) const;
std::vector<double> valueAndDerivatives(double /*t*/, unsigned /*n*/) const {
//TODO
throwNotImplemented(0);
}
 
SBasis toSBasis() const { return SBasis(*this); }
 
170,16 → 125,20
// compute f(g)
SBasis operator()(SBasis const & g) const;
 
Linear operator[](unsigned i) const {
assert(i < size());
return std::vector<Linear>::operator[](i);
}
 
//MUTATOR PRISON
Linear& operator[](unsigned i) { return this->at(i); }
 
//remove extra zeros
void normalize() {
while(!empty() && 0 == back()[0] && 0 == back()[1])
pop_back();
}
 
void truncate(unsigned k) { if(k < size()) resize(k); }
private:
void derive(); // in place version
};
 
//TODO: figure out how to stick this in linear, while not adding an sbasis dep
186,21 → 145,15
inline SBasis Linear::toSBasis() const { return SBasis(*this); }
 
//implemented in sbasis-roots.cpp
OptInterval bounds_exact(SBasis const &a);
OptInterval bounds_fast(SBasis const &a, int order = 0);
OptInterval bounds_local(SBasis const &a, const OptInterval &t, int order = 0);
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);
 
/** Returns a function which reverses the domain of a.
\param a sbasis function
\relates SBasis
 
useful for reversing a parameteric curve.
*/
inline SBasis reverse(SBasis const &a) {
SBasis result(a.size(), Linear());
SBasis result;
result.reserve(a.size());
for(unsigned k = 0; k < a.size(); k++)
result[k] = reverse(a[k]);
result.push_back(reverse(a[k]));
return result;
}
 
207,10 → 160,11
//IMPL: ScalableConcept
inline SBasis operator-(const SBasis& p) {
if(p.isZero()) return SBasis();
SBasis result(p.size(), Linear());
SBasis result;
result.reserve(p.size());
for(unsigned i = 0; i < p.size(); i++) {
result[i] = -p[i];
result.push_back(-p[i]);
}
return result;
}
227,7 → 181,7
SBasis& operator-=(SBasis& a, const SBasis& b);
 
//TODO: remove?
/*inline SBasis operator+(const SBasis & a, Linear const & b) {
inline SBasis operator+(const SBasis & a, Linear const & b) {
if(b.isZero()) return a;
if(a.isZero()) return b;
SBasis result(a);
253,7 → 207,7
else
a[0] -= b;
return a;
}*/
}
 
//IMPL: OffsetableConcept
inline SBasis operator+(const SBasis & a, double b) {
270,7 → 224,7
}
inline SBasis& operator+=(SBasis& a, double b) {
if(a.isZero())
a = SBasis(Linear(b,b));
a.push_back(Linear(b,b));
else
a[0] += b;
return a;
277,7 → 231,7
}
inline SBasis& operator-=(SBasis& a, double b) {
if(a.isZero())
a = SBasis(Linear(-b,-b));
a.push_back(Linear(-b,-b));
else
a[0] -= b;
return a;
293,8 → 247,6
}
 
SBasis multiply(SBasis const &a, SBasis const &b);
// This performs a multiply and accumulate operation in about the same time as multiply. return a*b + c
SBasis multiply_add(SBasis const &a, SBasis const &b, SBasis c);
 
SBasis integral(SBasis const &c);
SBasis derivative(SBasis const &a);
314,12 → 266,7
return a;
}
 
/** Returns the degree of the first non zero coefficient.
\param a sbasis function
\param tol largest abs val considered 0
\return first non zero coefficient
\relates SBasis
*/
//valuation: degree of the first non zero coefficient.
inline unsigned
valuation(SBasis const &a, double tol=0){
unsigned val=0;
338,14 → 285,7
//TODO: requires g(0)=0 & g(1)=1 atm. generalization should be obvious.
SBasis compose_inverse(SBasis const &f, SBasis const &g, unsigned order=2, double tol=1e-3);
 
/** Returns the sbasis on domain [0,1] that was t on [from, to]
\param t sbasis function
\param from,to interval
\return sbasis
\relates SBasis
*/
inline SBasis portion(const SBasis &t, double from, double to) { return compose(t, Linear(from, to)); }
inline SBasis portion(const SBasis &t, Interval ivl) { return compose(t, Linear(ivl[0], ivl[1])); }
 
// compute f(g)
inline SBasis
365,12 → 305,10
return out_file;
}
 
// These are deprecated, use sbasis-math.h versions if possible
SBasis sin(Linear bo, int k);
SBasis cos(Linear bo, int k);
 
std::vector<double> roots(SBasis const & s);
std::vector<double> roots(SBasis const & s, Interval const inside);
std::vector<std::vector<double> > multi_roots(SBasis const &f,
std::vector<double> const &levels,
double htol=1e-7,
377,70 → 315,8
double vtol=1e-7,
double a=0,
double b=1);
 
//--------- Levelset like functions -----------------------------------------------------
 
/** Solve f(t) = v +/- tolerance. The collection of intervals where
* v - vtol <= f(t) <= v+vtol
* is returned (with a precision tol on the boundaries).
\param f sbasis function
\param level the value of v.
\param vtol: error tolerance on v.
\param a, b limit search on domain [a,b]
\param tol: tolerance on the result bounds.
\returns a vector of intervals.
*/
std::vector<Interval> level_set (SBasis const &f,
double level,
double vtol = 1e-5,
double a=0.,
double b=1.,
double tol = 1e-5);
 
/** Solve f(t)\in I=[u,v], which defines a collection of intervals (J_k). More precisely,
* a collection (J'_k) is returned with J'_k = J_k up to a given tolerance.
\param f sbasis function
\param level: the given interval of deisred values for f.
\param a, b limit search on domain [a,b]
\param tol: tolerance on the bounds of the result.
\returns a vector of intervals.
*/
std::vector<Interval> level_set (SBasis const &f,
Interval const &level,
double a=0.,
double b=1.,
double tol = 1e-5);
 
/** 'Solve' f(t) = v +/- tolerance for several values of v at once.
\param f sbasis function
\param levels vector of values, that should be sorted.
\param vtol: error tolerance on v.
\param a, b limit search on domain [a,b]
\param tol: the bounds of the returned intervals are exact up to that tolerance.
\returns a vector of vectors of intervals.
*/
std::vector<std::vector<Interval> > level_sets (SBasis const &f,
std::vector<double> const &levels,
double a=0.,
double b=1.,
double vtol = 1e-5,
double tol = 1e-5);
 
/** 'Solve' f(t)\in I=[u,v] for several intervals I at once.
\param f sbasis function
\param levels vector of 'y' intervals, that should be disjoints and sorted.
\param a, b limit search on domain [a,b]
\param tol: the bounds of the returned intervals are exact up to that tolerance.
\returns a vector of vectors of intervals.
*/
std::vector<std::vector<Interval> > level_sets (SBasis const &f,
std::vector<Interval> const &levels,
double a=0.,
double b=1.,
double tol = 1e-5);
 
}
#endif
 
/*
Local Variables:
/trunk/Scribus/scribus/third_party/lib2geom/basic-intersection.h
1,145 → 1,28
/**
* \file
* \brief \todo brief description
*
* Authors:
* ? <?@?.?>
*
* Copyright ?-? authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
*/
 
#ifndef SEEN_GEOM_BASICINTERSECTION_H
#define SEEN_GEOM_BASICINTERSECTION_H
 
#include "point.h"
#include "sbasis.h"
#include "bezier-to-sbasis.h"
#include "sbasis-to-bezier.h"
#include "d2.h"
 
#include <vector>
#include <utility>
 
#define USE_RECURSIVE_INTERSECTOR 0
 
 
namespace Geom {
 
//why not allowing precision to be set here?
void find_intersections(std::vector<std::pair<double, double> >& xs,
D2<SBasis> const & A,
D2<SBasis> const & B);
std::vector<std::pair<double, double> >
find_intersections( D2<SBasis> const & A,
D2<SBasis> const & B);
 
void find_intersections(std::vector< std::pair<double, double> > & xs,
std::vector<Point> const& A,
std::vector<Point> const& B,
double precision = 1e-5);
std::vector<std::pair<double, double> >
find_self_intersections(D2<SBasis> const & A);
 
//why not allowing precision to be set here?
void find_self_intersections(std::vector<std::pair<double, double> >& xs,
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);
 
//--not implemented
//void find_self_intersections(std::vector<std::pair<double, double> >& xs,
// std::vector<Point> const & A);
};
 
 
//TODO: this should be moved to .cpp, shouldn't it?
// #ifdef USE_RECURSIVE_INTERSECTOR
// /*
// * find_intersection
// *
// * input: A, B - set of control points of two Bezier curve
// * input: precision - required precision of computation
// * output: xs - set of pairs of parameter values
// * at which crossing happens
// */
// void find_intersections_bezier_recursive (std::vector< std::pair<double, double> > & xs,
// std::vector<Point> const& A,
// std::vector<Point> const& B,
// double precision = 1e-5);
// #else
/*
* find_intersection
*
* input: A, B - set of control points of two Bezier curve
* input: precision - required precision of computation
* output: xs - set of pairs of parameter values
* at which crossing happens
*
* This routine is based on the Bezier Clipping Algorithm,
* see: Sederberg, Nishita, 1990 - Curve intersection using Bezier clipping
*/
void find_intersections_bezier_clipping (std::vector< std::pair<double, double> > & xs,
std::vector<Point> const& A,
std::vector<Point> const& B,
double precision = 1e-5);
//#endif
 
 
 
/*
* find_collinear_normal
*
* input: A, B - set of control points of two Bezier curve
* input: precision - required precision of computation
* output: xs - set of pairs of parameter values
* at which there are collinear normals
*
* This routine is based on the Bezier Clipping Algorithm,
* see: Sederberg, Nishita, 1990 - Curve intersection using Bezier clipping
*/
void find_collinear_normal (std::vector< std::pair<double, double> >& xs,
std::vector<Point> const& A,
std::vector<Point> const& B,
double precision = 1e-5);
 
void polish_intersections(std::vector<std::pair<double, double> > &xs,
D2<SBasis> const &A,
D2<SBasis> const &B);
 
 
/**
* Compute the Hausdorf distance from A to B only.
*/
double hausdorfl(D2<SBasis>& A, D2<SBasis> const& B,
double m_precision,
double *a_t=0, double* b_t=0);
 
/**
* Compute the symmetric Hausdorf distance.
*/
double hausdorf(D2<SBasis>& A, D2<SBasis> const& B,
double m_precision,
double *a_t=0, double* b_t=0);
}
 
#endif // !SEEN_GEOM_BASICINTERSECTION_H
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
/trunk/Scribus/scribus/third_party/lib2geom/geom.h
1,5 → 1,5
/**
* \file
* \file geom.h
* \brief Various geometrical calculations
*
* Authors:
37,10 → 37,7
//TODO: move somewhere else
 
#include <vector>
#include "forward.h"
#include <boost/optional/optional.hpp>
#include "bezier-curve.h"
#include "line.h"
#include "point.h"
 
namespace Geom {
 
57,9 → 54,6
 
/* intersectors */
 
#if 0
// Use the new routines provided in line.h
 
IntersectorKind
line_intersection(Geom::Point const &n0, double const d0,
Geom::Point const &n1, double const d1,
74,35 → 68,9
line_twopoint_intersect(Geom::Point const &p00, Geom::Point const &p01,
Geom::Point const &p10, Geom::Point const &p11,
Geom::Point &result);
#endif
 
#if 0
std::vector<Geom::Point>
rect_line_intersect(Geom::Point const &E, Geom::Point const &F,
Geom::Point const &p0, Geom::Point const &p1);
#endif
int centroid(std::vector<Geom::Point> p, Geom::Point& centroid, double &area);
 
boost::optional<Geom::LineSegment>
rect_line_intersect(Geom::Rect &r,
Geom::LineSegment ls);
 
boost::optional<Geom::LineSegment>
rect_line_intersect(Geom::Rect &r,
Geom::Line l);
 
int centroid(std::vector<Geom::Point> const &p, Geom::Point& centroid, double &area);
 
}
 
#endif
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/conjugate_gradient.cpp
32,7 → 32,7
#include <stdlib.h>
#include <valarray>
#include <cassert>
#include <conjugate_gradient.h>
#include "conjugate_gradient.h"
 
/* lifted wholely from wikipedia. */
 
46,22 → 46,18
unsigned n = vec.size();
unsigned m = result.size();
assert(m*n == matrix.size());
const double* mp = &const_cast<valarray<double>&>(matrix)[0];
for (unsigned i = 0; i < m; i++) {
double res = 0;
for (unsigned j = 0; j < n; j++)
res += *mp++ * vec[j];
res += matrix[i*m+j] * vec[j];
result[i] = res;
}
}
 
/**
// only used in commented code below
/*
static double Linfty(valarray<double> const &vec) {
return std::max(vec.max(), -vec.min());
}
**/
 
*/
double
inner(valarray<double> const &x,
valarray<double> const &y) {
99,7 → 95,7
valarray<double> &x,
valarray<double> const &b,
unsigned n, double tol,
unsigned max_iterations, bool /*ortho1*/) {
unsigned max_iterations, bool ortho1) {
valarray<double> Ap(n), p(n), r(n);
matrix_times_vector(A,x,Ap);
r=b-Ap;
125,7 → 121,6
//std::max(-r.min(), r.max()), sqrt(r_r));
// x is solution
}
 
/*
Local Variables:
mode:c++
135,4 → 130,4
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
/trunk/Scribus/scribus/third_party/lib2geom/d2-sbasis.h
1,43 → 1,4
/**
* \file
* \brief Do not include this file \todo brief description
*
* 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.
*
* Authors:
* ? <?@?.?>
*
* Copyright ?-? authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
*/
 
#ifdef _2GEOM_D2
/*This is intentional: we don't actually want anyone to
#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
46,7 → 7,7
#include "sbasis.h"
#include "sbasis-2d.h"
#include "piecewise.h"
#include "affine.h"
#include "matrix.h"
 
//TODO: implement intersect
 
71,20 → 32,17
//Piecewise<D2<SBasis> > specific decls:
 
Piecewise<D2<SBasis> > sectionize(D2<Piecewise<SBasis> > const &a);
D2<Piecewise<SBasis> > make_cuts_independent(Piecewise<D2<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> dot(Piecewise<D2<SBasis> > const &a, Point const &b);
Piecewise<SBasis> cross(Piecewise<D2<SBasis> > const &a, Piecewise<D2<SBasis> > const &b);
 
Piecewise<D2<SBasis> > operator*(Piecewise<D2<SBasis> > const &a, Affine const &m);
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);
Piecewise<D2<SBasis> > force_continuity(Piecewise<D2<SBasis> > const &f,
double tol=0,
bool closed=false);
 
std::vector<Piecewise<D2<SBasis> > > fuse_nearby_ends(std::vector<Piecewise<D2<SBasis> > > const &f, double tol=0);
 
std::vector<Geom::Piecewise<Geom::D2<Geom::SBasis> > > split_at_discontinuities (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwsbin, double tol = .0001);
 
class CoordIterator
: public std::iterator<std::input_iterator_tag, SBasis const>
{
118,45 → 76,16
}
 
//bounds specializations with order
inline OptRect bounds_fast(D2<SBasis> const & s, unsigned order=0) {
OptRect retval;
OptInterval xint = bounds_fast(s[X], order);
if (xint) {
OptInterval yint = bounds_fast(s[Y], order);
if (yint) {
retval = Rect(*xint, *yint);
}
}
return retval;
inline Rect bounds_fast(D2<SBasis> const & s, unsigned order=0) {
return Rect(bounds_fast(s[X], order),
bounds_fast(s[Y], order));
}
inline OptRect bounds_local(D2<SBasis> const & s, OptInterval i, unsigned order=0) {
OptRect retval;
OptInterval xint = bounds_local(s[X], i, order);
OptInterval yint = bounds_local(s[Y], i, order);
if (xint && yint) {
retval = Rect(*xint, *yint);
}
return retval;
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));
}
 
std::vector<Interval> level_set( D2<SBasis> const &f, Rect region);
std::vector<Interval> level_set( D2<SBasis> const &f, Point p, double tol);
std::vector<std::vector<Interval> > level_sets( D2<SBasis> const &f, std::vector<Rect> regions);
std::vector<std::vector<Interval> > level_sets( D2<SBasis> const &f, std::vector<Point> pts, double tol);
 
}
 
#endif
#endif
 
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/svg-path.h
1,6 → 1,5
/**
* \file
* \brief callback interface for SVG path data
/*
* callback interface for SVG path data
*
* Copyright 2007 MenTaLguY <mental@rydia.net>
*
33,7 → 32,6
#define SEEN_SVG_PATH_H
 
#include "path.h"
#include "curves.h"
#include <iterator>
 
namespace Geom {
41,8 → 39,6
class SVGPathSink {
public:
virtual void moveTo(Point p) = 0;
virtual void hlineTo(Coord v) = 0;
virtual void vlineTo(Coord v) = 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;
64,48 → 60,18
void moveTo(Point p) {
finish();
_path.start(p);
_start_p = p;
_in_path = true;
}
//TODO: what if _in_path = false?
 
void hlineTo(Coord v) {
// check for implicit moveto, like in: "M 1,1 L 2,2 z l 2,2 z"
if (!_in_path) {
moveTo(_start_p);
}
_path.template appendNew<HLineSegment>(Point(v, _path.finalPoint()[Y]));
}
 
void vlineTo(Coord v) {
// check for implicit moveto, like in: "M 1,1 L 2,2 z l 2,2 z"
if (!_in_path) {
moveTo(_start_p);
}
_path.template appendNew<VLineSegment>(Point(_path.finalPoint()[X], v));
}
 
void lineTo(Point p) {
// check for implicit moveto, like in: "M 1,1 L 2,2 z l 2,2 z"
if (!_in_path) {
moveTo(_start_p);
}
_path.template appendNew<LineSegment>(p);
}
 
void quadTo(Point c, Point p) {
// check for implicit moveto, like in: "M 1,1 L 2,2 z l 2,2 z"
if (!_in_path) {
moveTo(_start_p);
}
_path.template appendNew<QuadraticBezier>(c, p);
}
 
void curveTo(Point c0, Point c1, Point p) {
// check for implicit moveto, like in: "M 1,1 L 2,2 z l 2,2 z"
if (!_in_path) {
moveTo(_start_p);
}
_path.template appendNew<CubicBezier>(c0, c1, p);
}
 
112,10 → 78,6
void arcTo(double rx, double ry, double angle,
bool large_arc, bool sweep, Point p)
{
// check for implicit moveto, like in: "M 1,1 L 2,2 z l 2,2 z"
if (!_in_path) {
moveTo(_start_p);
}
_path.template appendNew<SVGEllipticalArc>(rx, ry, angle,
large_arc, sweep, p);
}
138,7 → 100,6
bool _in_path;
OutputIterator _out;
Path _path;
Point _start_p;
};
 
typedef std::back_insert_iterator<std::vector<Path> > iter;
/trunk/Scribus/scribus/third_party/lib2geom/transforms.cpp
1,154 → 1,48
/**
* @file
* @brief Affine transformation classes
*//*
* Authors:
* ? <?@?.?>
* Krzysztof Kosiński <tweenk.pl@gmail.com>
*
* Copyright ?-2009 Authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*/
#include "transforms.h"
 
#include <boost/concept_check.hpp>
#include <point.h>
#include <transforms.h>
 
namespace Geom {
 
// Point transformation methods.
Point &Point::operator*=(Translate const &t)
{
_pt[X] += t.vec[X];
_pt[Y] += t.vec[Y];
return *this;
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;
}
Point &Point::operator*=(Scale const &s)
{
_pt[X] *= s.vec[X];
_pt[Y] *= s.vec[Y];
return *this;
}
Point &Point::operator*=(Rotate const &r)
{
double x = _pt[X], y = _pt[Y];
_pt[X] = x * r.vec[X] - y * r.vec[Y];
_pt[Y] = y * r.vec[X] + x * r.vec[Y];
return *this;
}
Point &Point::operator*=(HShear const &h)
{
_pt[X] += h.f * _pt[X];
return *this;
}
Point &Point::operator*=(VShear const &v)
{
_pt[Y] += v.f * _pt[Y];
return *this;
}
 
// Affine multiplication methods.
 
/** @brief Combine this transformation with a translation. */
Affine &Affine::operator*=(Translate const &t) {
_c[4] += t[X];
_c[5] += t[Y];
return *this;
Matrix operator*(Translate const &t, Rotate const &r) {
Matrix ret(r);
ret.setTranslation(t.vec * ret);
return ret;
}
 
/** @brief Combine this transformation with scaling. */
Affine &Affine::operator*=(Scale const &s) {
_c[0] *= s[X]; _c[1] *= s[Y];
_c[2] *= s[X]; _c[3] *= s[Y];
_c[4] *= s[X]; _c[5] *= s[Y];
return *this;
Matrix operator*(Scale const &s, Translate const &t) {
return Matrix(s[0], 0,
0 , s[1],
t[0], t[1]);
}
 
/** @brief Combine this transformation a rotation. */
Affine &Affine::operator*=(Rotate const &r) {
// TODO: we just convert the Rotate to an Affine and use the existing operator*=()
// is there a better way?
*this *= (Affine) r;
return *this;
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;
}
 
/** @brief Combine this transformation with horizontal shearing (skew). */
Affine &Affine::operator*=(HShear const &h) {
_c[0] += h.f * _c[1];
_c[2] += h.f * _c[3];
_c[4] += h.f * _c[5];
return *this;
Matrix operator*(Matrix const &m, Translate const &t) {
Matrix ret(m);
ret[4] += t[X];
ret[5] += t[Y];
return ret;
}
 
/** @brief Combine this transformation with vertical shearing (skew). */
Affine &Affine::operator*=(VShear const &v) {
_c[1] += v.f * _c[0];
_c[3] += v.f * _c[2];
_c[5] += v.f * _c[4];
return *this;
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;
}
 
// this checks whether the requirements of TransformConcept are satisfied for all transforms.
// if you add a new transform type, include it here!
void check_transforms()
{
#ifdef BOOST_CONCEPT_ASSERT
BOOST_CONCEPT_ASSERT((TransformConcept<Translate>));
BOOST_CONCEPT_ASSERT((TransformConcept<Scale>));
BOOST_CONCEPT_ASSERT((TransformConcept<Rotate>));
BOOST_CONCEPT_ASSERT((TransformConcept<HShear>));
BOOST_CONCEPT_ASSERT((TransformConcept<VShear>));
BOOST_CONCEPT_ASSERT((TransformConcept<Affine>)); // Affine is also a transform
#endif
 
// check inter-transform multiplication
Affine m;
Translate t(Translate::identity());
Scale s(Scale::identity());
Rotate r(Rotate::identity());
HShear h(HShear::identity());
VShear v(VShear::identity());
 
// notice that the first column is always the same and enumerates all transform types,
// while the second one changes to each transform type in turn.
m = t * t; m = t * s; m = t * r; m = t * h; m = t * v;
m = s * t; m = s * s; m = s * r; m = s * h; m = s * v;
m = r * t; m = r * s; m = r * r; m = r * h; m = r * v;
m = h * t; m = h * s; m = h * r; m = h * h; m = h * v;
m = v * t; m = v * s; m = v * r; m = v * h; m = v * v;
}
 
}
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/sbasis-geometric.cpp
1,8 → 1,8
#include <sbasis-geometric.h>
#include <sbasis.h>
#include <sbasis-math.h>
//#include <2geom/solver.h>
#include <sbasis-geometric.h>
#include "sbasis-geometric.h"
#include "sbasis.h"
#include "sbasis-math.h"
//#include "solver.h"
#include "sbasis-geometric.h"
 
/** Geometric operators on D2<SBasis> (1D->2D).
* Copyright 2007 JF Barraud
27,11 → 27,6
 
//Some utils first.
//TODO: remove this!!
/**
* Return a list of doubles that appear in both a and b to within error tol
* a, b, vector of double
* tol tolerance
*/
static vector<double>
vect_intersect(vector<double> const &a, vector<double> const &b, double tol=0.){
vector<double> inter;
50,12 → 45,8
return inter;
}
 
//------------------------------------------------------------------------------
static SBasis divide_by_sk(SBasis const &a, int k) {
if ( k>=(int)a.size()){
//make sure a is 0?
return SBasis();
}
assert( k<(int)a.size());
if(k < 0) return shift(a,-k);
SBasis c;
c.insert(c.begin(), a.begin()+k, a.end());
101,8 → 92,7
static D2<SBasis> RescaleForNonVanishingEnds(D2<SBasis> const &MM, double ZERO=1.e-4){
D2<SBasis> M = MM;
//TODO: divide by all the s at once!!!
while ((M[0].size()>0||M[1].size()>0) &&
fabs(M[0].at0())<ZERO &&
while (fabs(M[0].at0())<ZERO &&
fabs(M[1].at0())<ZERO &&
fabs(M[0].at1())<ZERO &&
fabs(M[1].at1())<ZERO){
109,13 → 99,11
M[0] = divide_by_sk(M[0],1);
M[1] = divide_by_sk(M[1],1);
}
while ((M[0].size()>0||M[1].size()>0) &&
fabs(M[0].at0())<ZERO && fabs(M[1].at0())<ZERO){
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 ((M[0].size()>0||M[1].size()>0) &&
fabs(M[0].at1())<ZERO && fabs(M[1].at1())<ZERO){
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);
}
122,14 → 110,6
return M;
}
 
/*static D2<SBasis> RescaleForNonVanishing(D2<SBasis> const &MM, double ZERO=1.e-4){
std::vector<double> levels;
levels.push_back(-ZERO);
levels.push_back(ZERO);
//std::vector<std::vector<double> > mr = multi_roots(MM, levels);
}*/
 
 
//=================================================================
//TODO: what's this for?!?!
Piecewise<D2<SBasis> >
147,16 → 127,10
return partition(M,rts);
}
 
/** Return a function which gives the angle of vect at each point.
\param vect a piecewise parameteric curve.
\param tol the maximum error allowed.
\param order the maximum degree to use for approximation
\relates Piecewise
*/
Piecewise<SBasis>
Geom::atan2(Piecewise<D2<SBasis> > const &vect, double tol, unsigned order){
Piecewise<SBasis> result;
Piecewise<D2<SBasis> > v = cutAtRoots(vect,tol);
Piecewise<D2<SBasis> > v = cutAtRoots(vect);
result.cuts.push_back(v.cuts.front());
for (unsigned i=0; i<v.size(); i++){
 
178,67 → 152,25
}
return result;
}
/** Return a function which gives the angle of vect at each point.
\param vect a piecewise parameteric curve.
\param tol the maximum error allowed.
\param order the maximum degree to use for approximation
\relates Piecewise, D2
*/
Piecewise<SBasis>
Geom::atan2(D2<SBasis> const &vect, double tol, unsigned order){
return atan2(Piecewise<D2<SBasis> >(vect),tol,order);
}
 
/** tan2 is the pseudo-inverse of atan2. It takes an angle and returns a unit_vector that points in the direction of angle.
\param angle a piecewise function of angle wrt t.
\param tol the maximum error allowed.
\param order the maximum degree to use for approximation
\relates D2, SBasis
*/
D2<Piecewise<SBasis> >
Geom::tan2(SBasis const &angle, double tol, unsigned order){
return tan2(Piecewise<SBasis>(angle), tol, order);
}
 
/** tan2 is the pseudo-inverse of atan2. It takes an angle and returns a unit_vector that points in the direction of angle.
\param angle a piecewise function of angle wrt t.
\param tol the maximum error allowed.
\param order the maximum degree to use for approximation
\relates Piecewise, D2
*/
D2<Piecewise<SBasis> >
Geom::tan2(Piecewise<SBasis> const &angle, double tol, unsigned order){
return D2<Piecewise<SBasis> >(cos(angle, tol, order), sin(angle, tol, order));
}
 
/** Return a Piecewise<D2<SBasis> > which points in the same direction as V_in, but has unit_length.
\param V_in the original path.
\param tol the maximum error allowed.
\param order the maximum degree to use for approximation
 
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)
 
\relates Piecewise, D2
*/
//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){
//TODO: Handle vanishing vectors...
// -This approach is numerically bad. Find a stable way to rescale V_in to have non vanishing ends.
// -This done, unitVector will have jumps at zeros: fill the gaps with arcs of circles.
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];
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());
SBasis a = SBasis(order+1, Linear(0.));
a[0] = Linear(-v0[1],-v1[1]);
SBasis b = SBasis(order+1, Linear(0.));
b[0] = Linear( v0[0], v1[0]);
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);
254,14 → 186,13
// 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.at0())*v0[0]-rr0/2*v0[1];
b0 = r0/dot(v0,V.at0())*v0[1]+rr0/2*v0[0];
a1 = r1/dot(v1,V.at1())*v1[0]-rr1/2*v1[1];
b1 = r1/dot(v1,V.at1())*v1[1]+rr1/2*v1[0];
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[k] = Linear(a0,a1);
b[k] = Linear(b0,b1);
 
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);
274,6 → 205,7
 
//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;
291,16 → 223,6
}
}
 
/** Return a Piecewise<D2<SBasis> > which points in the same direction as V_in, but has unit_length.
\param V_in the original path.
\param tol the maximum error allowed.
\param order the maximum degree to use for approximation
 
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)
 
\relates Piecewise
*/
Piecewise<D2<SBasis> >
Geom::unitVector(Piecewise<D2<SBasis> > const &V, double tol, unsigned order){
Piecewise<D2<SBasis> > result;
315,11 → 237,6
return result;
}
 
/** returns a function giving the arclength at each point in M.
\param M the Element.
\param tol the maximum error allowed.
\relates Piecewise
*/
Piecewise<SBasis>
Geom::arcLengthSb(Piecewise<D2<SBasis> > const &M, double tol){
Piecewise<D2<SBasis> > dM = derivative(M);
328,18 → 245,11
length-=length.segs.front().at0();
return length;
}
 
/** returns a function giving the arclength at each point in M.
\param M the Element.
\param tol the maximum error allowed.
\relates Piecewise, D2
*/
Piecewise<SBasis>
Geom::arcLengthSb(D2<SBasis> const &M, double tol){
return arcLengthSb(Piecewise<D2<SBasis> >(M), tol);
}
 
#if 0
double
Geom::length(D2<SBasis> const &M,
double tol){
352,14 → 262,9
Piecewise<SBasis> length = arcLengthSb(M, tol);
return length.segs.back().at1();
}
#endif
 
/** returns a function giving the curvature at each point in M.
\param M the Element.
\param tol the maximum error allowed.
\relates Piecewise, D2
\todo claimed incomplete. Check.
*/
 
// incomplete.
Piecewise<SBasis>
Geom::curvature(D2<SBasis> const &M, double tol) {
D2<SBasis> dM=derivative(M);
371,12 → 276,6
return(k);
}
 
/** returns a function giving the curvature at each point in M.
\param M the Element.
\param tol the maximum error allowed.
\relates Piecewise
\todo claimed incomplete. Check.
*/
Piecewise<SBasis>
Geom::curvature(Piecewise<D2<SBasis> > const &V, double tol){
Piecewise<SBasis> result;
393,12 → 292,6
 
//=================================================================
 
/** Reparameterise M to have unit speed.
\param M the Element.
\param tol the maximum error allowed.
\param order the maximum degree to use for approximation
\relates Piecewise, D2
*/
Piecewise<D2<SBasis> >
Geom::arc_length_parametrization(D2<SBasis> const &M,
unsigned order,
422,12 → 315,6
return u;
}
 
/** Reparameterise M to have unit speed.
\param M the Element.
\param tol the maximum error allowed.
\param order the maximum degree to use for approximation
\relates Piecewise
*/
Piecewise<D2<SBasis> >
Geom::arc_length_parametrization(Piecewise<D2<SBasis> > const &M,
unsigned order,
440,83 → 327,17
return(result);
}
 
#include <gsl/gsl_integration.h>
static double sb_length_integrating(double t, void* param) {
SBasis* pc = (SBasis*)param;
return sqrt((*pc)(t));
}
/** 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.
 
/** Calculates the length of a D2<SBasis> through gsl integration.
\param B the Element.
\param tol the maximum error allowed.
\param result variable to be incremented with the length of the path
\param abs_error variable to be incremented with the estimated error
\relates D2
If you only want the length, this routine may be faster/more accurate.
*/
void Geom::length_integrating(D2<SBasis> const &B, double &result, double &abs_error, double tol) {
D2<SBasis> dB = derivative(B);
SBasis dB2 = dot(dB, dB);
gsl_function F;
gsl_integration_workspace * w
= gsl_integration_workspace_alloc (20);
F.function = &sb_length_integrating;
F.params = (void*)&dB2;
double quad_result, err;
/* We could probably use the non adaptive code here if we removed any cusps first. */
gsl_integration_qag (&F, 0, 1, 0, tol, 20,
GSL_INTEG_GAUSS21, w, &quad_result, &err);
abs_error += err;
result += quad_result;
}
 
/** Calculates the length of a D2<SBasis> through gsl integration.
\param s the Element.
\param tol the maximum error allowed.
\relates D2
If you only want the total length, this routine faster and more accurate than constructing an arcLengthSb.
*/
double
Geom::length(D2<SBasis> const &s,
double tol){
double result = 0;
double abs_error = 0;
length_integrating(s, result, abs_error, tol);
return result;
}
/** Calculates the length of a Piecewise<D2<SBasis> > through gsl integration.
\param s the Element.
\param tol the maximum error allowed.
\relates Piecewise
If you only want the total length, this routine faster and more accurate than constructing an arcLengthSb.
*/
double
Geom::length(Piecewise<D2<SBasis> > const &s,
double tol){
double result = 0;
double abs_error = 0;
for (unsigned i=0; i < s.size();i++){
length_integrating(s[i], result, abs_error, tol);
}
return result;
}
 
/**
* Centroid using sbasis integration.
\param p the Element.
\param centroid on return contains the centroid of the shape
\param area on return contains the signed area of the shape.
\relates Piecewise
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. Note that without an uncross operation the output is not the absolute area.
 
* 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;
542,221 → 363,6
return 2;
}
 
/**
* Find cubics with prescribed curvatures at both ends.
*
* this requires to solve a system of the form
*
* \f[
* \lambda_1 = a_0 \lambda_0^2 + c_0
* \lambda_0 = a_1 \lambda_1^2 + c_1
* \f]
*
* which is a deg 4 equation in lambda 0.
* Below are basic functions dedicated to solving this assuming a0 and a1 !=0.
*/
 
static OptInterval
find_bounds_for_lambda0(double aa0,double aa1,double cc0,double cc1,
int insist_on_speeds_signs){
 
double a0=aa0,a1=aa1,c0=cc0,c1=cc1;
Interval result;
bool flip = a1<0;
if (a1<0){a1=-a1; c1=-c1;}
if (a0<0){a0=-a0; c0=-c0;}
double a = (a0<a1 ? a0 : a1);
double c = (c0<c1 ? c0 : c1);
double delta = 1-4*a*c;
if ( delta < 0 )
return OptInterval();//return empty interval
double lambda_max = (1+std::sqrt(delta))/2/a;
result = Interval(c,lambda_max);
if (flip)
result *= -1;
if (insist_on_speeds_signs == 1){
if (result.max() < 0)//Caution: setMin with max<new min...
return OptInterval();//return empty interval
result.setMin(0);
}
result = Interval(result.min()-.1,result.max()+.1);//just in case all our approx. were exact...
return result;
}
 
static
std::vector<double>
solve_lambda0(double a0,double a1,double c0,double c1,
int insist_on_speeds_signs){
 
SBasis p(3, Linear());
p[0] = Linear( a1*c0*c0+c1, a1*a0*(a0+ 2*c0) +a1*c0*c0 +c1 -1 );
p[1] = Linear( -a1*a0*(a0+2*c0), -a1*a0*(3*a0+2*c0) );
p[2] = Linear( a1*a0*a0 );
 
OptInterval domain = find_bounds_for_lambda0(a0,a1,c0,c1,insist_on_speeds_signs);
if ( !domain )
return std::vector<double>();
p = compose(p,Linear(domain->min(),domain->max()));
std::vector<double>rts = roots(p);
for (unsigned i=0; i<rts.size(); i++){
rts[i] = domain->min() + rts[i] * domain->extent();
}
return rts;
}
 
/**
* \brief returns the cubics fitting direction and curvature of a given
* input curve at two points.
*
* The input can be the
* value, speed, and acceleration
* or
* value, speed, and cross(acceleration,speed)
* of the original curve at the both ends.
* (the second is often technically usefull, as it avoids unnecessary division by |v|^2)
* Recall that K=1/R=cross(acceleration,speed)/|speed|^3.
*
* Moreover, a 7-th argument 'insist_on_speed_signs' can be supplied to select solutions:
* If insist_on_speed_signs == 1, only consider solutions where speeds at both ends are positively
* proportional to the given ones.
* If insist_on_speed_signs == 0, allow speeds to point in the opposite direction (both at the same time)
* If insist_on_speed_signs == -1, allow speeds to point in both direction independantly.
*
* \relates D2
*/
std::vector<D2<SBasis> >
Geom::cubics_fitting_curvature(Point const &M0, Point const &M1,
Point const &dM0, Point const &dM1,
double d2M0xdM0, double d2M1xdM1,
int insist_on_speed_signs,
double epsilon){
std::vector<D2<SBasis> > result;
 
//speed of cubic bezier will be lambda0*dM0 and lambda1*dM1,
//with lambda0 and lambda1 s.t. curvature at both ends is the same
//as the curvature of the given curve.
std::vector<double> lambda0,lambda1;
double dM1xdM0=cross(dM1,dM0);
if (fabs(dM1xdM0)<epsilon){
if (fabs(d2M0xdM0)<epsilon || fabs(d2M1xdM1)<epsilon){
return result;
}
double lbda02 = 6.*cross(M1-M0,dM0)/d2M0xdM0;
double lbda12 =-6.*cross(M1-M0,dM1)/d2M1xdM1;
if (lbda02<0 || lbda12<0){
return result;
}
lambda0.push_back(std::sqrt(lbda02) );
lambda1.push_back(std::sqrt(lbda12) );
}else{
//solve: lambda1 = a0 lambda0^2 + c0
// lambda0 = a1 lambda1^2 + c1
double a0,c0,a1,c1;
a0 = -d2M0xdM0/2/dM1xdM0;
c0 = 3*cross(M1-M0,dM0)/dM1xdM0;
a1 = -d2M1xdM1/2/dM1xdM0;
c1 = -3*cross(M1-M0,dM1)/dM1xdM0;
 
if (fabs(a0)<epsilon){
lambda1.push_back( c0 );
lambda0.push_back( a1*c0*c0 + c1 );
}else if (fabs(a1)<epsilon){
lambda0.push_back( c1 );
lambda1.push_back( a0*c1*c1 + c0 );
}else{
//find lamda0 by solving a deg 4 equation d0+d1*X+...+d4*X^4=0
double a[5];
a[0] = c1+a1*c0*c0;
a[1] = -1;
a[2] = 2*a1*a0*c0;
a[3] = 0;
a[4] = a1*a0*a0;
//vector<double> solns=solve_poly(a,4);
vector<double> solns=solve_lambda0(a0,a1,c0,c1,insist_on_speed_signs);
for (unsigned i=0;i<solns.size();i++){
double lbda0=solns[i];
double lbda1=c0+a0*lbda0*lbda0;
//is this solution pointing in the + direction at both ends?
if (lbda0>=0. && lbda1>=0.){
lambda0.push_back( lbda0);
lambda1.push_back( lbda1);
}
//is this solution pointing in the - direction at both ends?
else if (lbda0<=0. && lbda1<=0. && insist_on_speed_signs<=0){
lambda0.push_back( lbda0);
lambda1.push_back( lbda1);
}
//ok,this solution is pointing in the + and - directions.
else if (insist_on_speed_signs<0){
lambda0.push_back( lbda0);
lambda1.push_back( lbda1);
}
}
}
}
for (unsigned i=0; i<lambda0.size(); i++){
Point V0 = lambda0[i]*dM0;
Point V1 = lambda1[i]*dM1;
D2<SBasis> cubic;
for(unsigned dim=0;dim<2;dim++){
SBasis c(2, Linear());
c[0] = Linear(M0[dim],M1[dim]);
c[1] = Linear( M0[dim]-M1[dim]+V0[dim],
-M0[dim]+M1[dim]-V1[dim]);
cubic[dim] = c;
}
#if 0
Piecewise<SBasis> k = curvature(result);
double dM0_l = dM0.length();
double dM1_l = dM1.length();
g_warning("Target radii: %f, %f", dM0_l*dM0_l*dM0_l/d2M0xdM0,dM1_l*dM1_l*dM1_l/d2M1xdM1);
g_warning("Obtained radii: %f, %f",1/k.valueAt(0),1/k.valueAt(1));
#endif
result.push_back(cubic);
}
return(result);
}
 
std::vector<D2<SBasis> >
Geom::cubics_fitting_curvature(Point const &M0, Point const &M1,
Point const &dM0, Point const &dM1,
Point const &d2M0, Point const &d2M1,
int insist_on_speed_signs,
double epsilon){
double d2M0xdM0 = cross(d2M0,dM0);
double d2M1xdM1 = cross(d2M1,dM1);
return cubics_fitting_curvature(M0,M1,dM0,dM1,d2M0xdM0,d2M1xdM1,insist_on_speed_signs,epsilon);
}
 
std::vector<D2<SBasis> >
Geom::cubics_with_prescribed_curvature(Point const &M0, Point const &M1,
Point const &dM0, Point const &dM1,
double k0, double k1,
int insist_on_speed_signs,
double epsilon){
double length;
length = dM0.length();
double d2M0xdM0 = k0*length*length*length;
length = dM1.length();
double d2M1xdM1 = k1*length*length*length;
return cubics_fitting_curvature(M0,M1,dM0,dM1,d2M0xdM0,d2M1xdM1,insist_on_speed_signs,epsilon);
}
 
 
/**
* \brief returns all the parameter values of A whose tangent passes through P.
* \relates D2
*/
std::vector<double> find_tangents(Point P, D2<SBasis> const &A) {
SBasis crs (cross(A - P, derivative(A)));
crs = shift(crs*Linear(-1, 0)*Linear(-1, 0), -2); // We know that there is a double root at t=0 so we divide out t^2
// JFB points out that this is equivalent to (t-1)^2 followed by a divide by s^2 (shift)
return roots(crs);
}
 
 
//}; // namespace
 
 
/trunk/Scribus/scribus/third_party/lib2geom/shape.cpp
1,50 → 1,12
/**
* \brief Shapes are special paths on which boolops can be performed
*
* Authors:
* Michael G. Sloan <mgsloan@gmail.com>
* Nathan Hurst <njh@mail.csse.monash.edu.au>
* MenTaLguY <mental@rydia.net>
*
* Copyright 2007-2009 Authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
*/
#include "shape.h"
#include "utils.h"
#include "sweep.h"
#include "ord.h"
 
#include <shape.h>
 
#include <utils.h>
#include <sweep.h>
#include <ord.h>
 
#include <iostream>
#include <algorithm>
#include <cstdlib>
 
//#define SHAPE_DEBUG // turns on debug outputting to cout.
 
namespace Geom {
 
// A little sugar for appending a list to another
229,7 → 191,7
* NOTE: currently doesn't work, as the CrossingSet reversal functions crash
*/
Shape boolop(Shape const &a, Shape const &b, unsigned flags, CrossingSet const &crs) {
THROW_NOTIMPLEMENTED();
throwNotImplemented(0);
flags &= 15;
if(flags <= BOOLOP_UNION) {
switch(flags) {
378,9 → 340,7
void crossing_dual(unsigned &i, unsigned &j, CrossingSet const & crs) {
Crossing cur = crs[i][j];
i = cur.getOther(i);
#ifdef SHAPE_DEBUG
std::cout << i << "\n";
#endif
// std::cout << i << "\n";
if(crs[i].empty())
j = 0;
else
389,7 → 349,7
 
//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());
Rect bounds = ps[ix].boundsFast();
double ry = bounds[Y].middle();
double max_val = bounds.left(), max_t = 0;
ix = ps.size();
469,24 → 429,18
to = crs[ix][jx];
if(dir) {
// backwards
#ifdef SHAPE_DEBUG
std::cout << "r" << ix << "[" << from.getTime(ix) << ", " << to.getTime(ix) << "]\n";
#endif
// 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], Path::STITCH_DISCONTINUOUS);
res.append(p[i]);
} else {
// forwards
#ifdef SHAPE_DEBUG
std::cout << "f" << ix << "[" << from.getTime(ix) << ", " << to.getTime(ix) << "]\n";
#endif
// 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]);
#ifdef SHAPE_DEBUG
std::cout << "added " << res.size() << "\n";
#endif
// std::cout << "added " << res.size() << "\n";
result_paths.push_back(res);
}
for(unsigned i = 0; i < crs.size(); i++) {
622,7 → 576,7
/* 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*(Affine const &m) const {
Shape Shape::operator*(Matrix const &m) const {
Shape ret;
for(unsigned i = 0; i < size(); i++)
ret.content.push_back(content[i] * m);
676,14 → 630,3
}
 
}
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/circle-circle.cpp
42,7 → 42,7
*/
#include <stdio.h>
#include <math.h>
#include <point.h>
#include "point.h"
 
namespace Geom{
 
129,13 → 129,3
}
#endif
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/matrix.cpp
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 x-axis.
\param y_basis the vector for the y-axis.
\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 x-scaling imparted by the Matrix. This is the scaling applied to
* the original x-axis region. It is \emph{not} the overall x-scaling 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 y-scaling imparted by the Matrix. This is the scaling applied before
* the other transformations. It is \emph{not} the overall y-scaling 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*B-4*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++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/sbasis-poly.h
4,38 → 4,8
#include "poly.h"
#include "sbasis.h"
 
/**
* \file
* \brief Conversion between SBasis and Poly. Not recommended for general use due to instability.
*
* Authors:
* ? <?@?.?>
*
* Copyright ?-? authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
/*** Conversion between SBasis and Poly. Not recommended for general
* use due to instability.
*/
 
namespace Geom{
/trunk/Scribus/scribus/third_party/lib2geom/coord.h
1,6 → 1,5
/**
* \file
* \brief Defines the Coord "real" type with sufficient precision for coordinates.
/*
* coord.h
*
* Copyright 2006 Nathan Hurst <njh@mail.csse.monash.edu.au>
*
33,7 → 32,6
#define SEEN_Geom_COORD_H
 
#include <cmath>
#include <limits>
 
namespace Geom {
 
48,11 → 46,8
 
const Coord EPSILON = 1e-5; //1e-18;
 
inline Coord infinity() { return std::numeric_limits<Coord>::infinity(); }
 
//IMPL: NearConcept
inline bool are_near(Coord a, Coord b, double eps=EPSILON) { return a-b <= eps && a-b >= -eps; }
inline bool rel_error_bound(Coord a, Coord b, double eps=EPSILON) { return a <= eps*b && a >= -eps*b; }
inline bool are_near(Coord a, Coord b, double eps=EPSILON) { return fabs(a-b) <= eps; }
 
} /* namespace Geom */
 
/trunk/Scribus/scribus/third_party/lib2geom/circulator.h
1,6 → 1,5
/**
* \file circulator.h
* \brief \todo brief description
/*
* ciculator.h
*
* Copyright 2006 MenTaLguY <mental@rydia.net>
*
140,9 → 139,11
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
c-file-offsets:((innamespace . 0)(substatement-open . 0))
indent-tabs-mode:nil
c-brace-offset:0
fill-column:99
End:
vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
 
/trunk/Scribus/scribus/third_party/lib2geom/bezier-utils.cpp
48,16 → 48,18
#define noBEZIER_DEBUG
 
#ifdef HAVE_IEEEFP_H
# include <ieeefp.h>
# include <ieefp.h>
#endif
 
#include <bezier-utils.h>
#include "bezier-utils.h"
 
#include <isnan.h>
#include "isnan.h"
#include <assert.h>
 
namespace Geom {
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);
66,16 → 68,16
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[], Point const bezCurve[]);
static double NewtonRaphsonRootFind(Point const Q[], Point const &P, double u);
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,
Point const bezCurve[], double tolerance,
BezierCurve const bezCurve, double tolerance,
unsigned *splitPoint);
static double compute_hook(Point const &a, Point const &b, double const u, Point const bezCurve[],
static double compute_hook(Point const &a, Point const &b, double const u, BezierCurve const bezCurve,
double const tolerance);
 
 
163,20 → 165,19
if ( si == src_len ) {
return 0;
}
if (!IS_NAN(src[si][X]) &&
!IS_NAN(src[si][Y])) {
if (!is_nan(src[si][X]) &&
!is_nan(src[si][Y])) {
dest[0] = Point(src[si]);
++si;
break;
}
si++;
}
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])) {
&& !is_nan(src_pt[X])
&& !is_nan(src_pt[Y])) {
dest[++di] = src_pt;
}
}
215,7 → 216,7
bezier[0] = data[0];
bezier[3] = data[len - 1];
double const dist = distance(bezier[0], bezier[3]) / 3.0;
if (IS_NAN(dist)) {
if (is_nan(dist)) {
/* Numerical problem, fall back to straight line segment. */
bezier[1] = bezier[0];
bezier[2] = bezier[3];
544,7 → 545,7
reparameterize(Point const d[],
unsigned const len,
double u[],
Point const bezCurve[])
BezierCurve const bezCurve)
{
assert( 2 <= len );
 
570,7 → 571,7
* \return Improved u
*/
static double
NewtonRaphsonRootFind(Point const Q[], Point const &P, double const u)
NewtonRaphsonRootFind(BezierCurve const Q, Point const &P, double const u)
{
assert( 0.0 <= u );
assert( u <= 1.0 );
618,7 → 619,7
}
}
 
if (!IS_FINITE(improved_u)) {
if (!is_finite(improved_u)) {
improved_u = u;
} else if ( improved_u < 0.0 ) {
improved_u = 0.0;
852,7 → 853,7
double tot_len = u[len - 1];
if(!( tot_len != 0 ))
return;
if (IS_FINITE(tot_len)) {
if (is_finite(tot_len)) {
for (unsigned i = 1; i < len; ++i) {
u[i] /= tot_len;
}
902,7 → 903,7
*/
static double
compute_max_error_ratio(Point const d[], double const u[], unsigned const len,
Point const bezCurve[], double const tolerance,
BezierCurve const bezCurve, double const tolerance,
unsigned *const splitPoint)
{
assert( 2 <= len );
972,7 → 973,7
* distance.)
*/
static double
compute_hook(Point const &a, Point const &b, double const u, Point const bezCurve[],
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);
/trunk/Scribus/scribus/third_party/lib2geom/sturm.h
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 sign-changes */
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++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/quadtree.h
1,44 → 1,6
/**
* \file
* \brief \todo brief description
*
* Authors:
* ? <?@?.?>
*
* Copyright ?-? authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
*/
 
#include <vector>
#include <cassert>
 
#include "d2.h"
 
namespace Geom{
 
class Quad{
public:
Quad* children[4];
48,23 → 10,6
children[i] = 0;
}
typedef std::vector<int>::iterator iterator;
Rect bounds(unsigned i, double x, double y, double d) {
double dd = d/2;
switch(i % 4) {
case 0:
return Rect(Interval(x, x+dd), Interval(y, y+dd));
case 1:
return Rect(Interval(x+dd, x+d), Interval(y, y+dd));
case 2:
return Rect(Interval(x, x+dd), Interval(y+dd, y+d));
case 3:
return Rect(Interval(x+dd, x+d), Interval(y+dd, y+d));
default:
/* just to suppress warning message
* this case should be never reached */
assert(false);
}
}
};
 
class QuadTree{
78,22 → 23,19
 
Quad* search(double x0, double y0, double x1, double y1);
void insert(double x0, double y0, double x1, double y1, int shape);
Quad* search(Geom::Rect const &r);
void insert(Geom::Rect const &r, int shape);
void erase(Quad *q, int shape);
private:
bool clean_root();
};
 
};
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
c-file-offsets:((innamespace . 0)(substatement-open . 0))
indent-tabs-mode:nil
c-brace-offset:0
fill-column:99
End:
vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
 
/trunk/Scribus/scribus/third_party/lib2geom/piecewise.h
1,6 → 1,5
/**
* \file
* \brief Piecewise function class
/*
* piecewise.h - Piecewise function class
*
* Copyright 2007 Michael Sloan <mgsloan@gmail.com>
*
41,28 → 40,7
#include <boost/concept_check.hpp>
 
namespace Geom {
/**
* %Piecewise function class.
* The Piecewise class manages a sequence of elements of a type as segments and
* the ’cuts’ between them. These cuts are time values which separate the pieces.
* This function representation allows for more interesting functions, as it provides
* a viable output for operations such as inversion, which may require multiple
* SBasis to properly invert the original.
* As for technical details, while the actual SBasis segments begin on the first
* cut and end on the last, the function is defined throughout all inputs by ex-
* tending the first and last segments. The exact switching between segments is
* arbitrarily such that beginnings (t=0) have preference over endings (t=1). This
* only matters if it is discontinuous at the location.
* \f[
* f(t) \rightarrow \left\{
* \begin{array}{cc}
* s_1,& t <= c_2 \\
* s_2,& c_2 <= t <= c_3\\
* \ldots \\
* s_n,& c_n <= t
* \end{array}\right.
* \f]
*/
 
template <typename T>
class Piecewise {
BOOST_CLASS_REQUIRE(T, Geom, FragmentConcept);
80,8 → 58,6
push_cut(1.);
}
 
unsigned input_dim(){return 1;}
 
typedef typename T::output_type output_type;
 
explicit Piecewise(const output_type & v) {
90,8 → 66,6
push_cut(1.);
}
 
inline void reserve(unsigned i) { segs.reserve(i); cuts.reserve(i + 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); }
99,27 → 73,6
unsigned n = segN(t);
return segs[n](segT(t, n));
}
inline output_type firstValue() const {
return valueAt(cuts.front());
}
inline output_type lastValue() const {
return valueAt(cuts.back());
}
 
/**
* The size of the returned vector equals n_derivs+1.
*/
std::vector<output_type> valueAndDerivatives(double t, unsigned n_derivs) const {
unsigned n = segN(t);
std::vector<output_type> ret, val = segs[n].valueAndDerivatives(segT(t, n), n_derivs);
double mult = 1;
for(unsigned i = 0; i < val.size(); i++) {
ret.push_back(val[i] * mult);
mult /= cuts[n+1] - cuts[n];
}
return ret;
}
 
//TODO: maybe it is not a good idea to have this?
Piecewise<T> operator()(SBasis f);
Piecewise<T> operator()(Piecewise<SBasis>f);
126,10 → 79,6
 
inline unsigned size() const { return segs.size(); }
inline bool empty() const { return segs.empty(); }
inline void clear() {
segs.clear();
cuts.clear();
}
 
/**Convenience/implementation hiding function to add segment/cut pairs.
* Asserts that basic size and order invariants are correct
141,7 → 90,7
}
//Convenience/implementation hiding function to add cuts.
inline void push_cut(double c) {
ASSERT_INVARIANTS(cuts.empty() || c > cuts.back());
assert_invariants(cuts.empty() || c > cuts.back());
cuts.push_back(c);
}
//Convenience/implementation hiding function to add segments.
184,7 → 133,7
 
//Offsets the piecewise domain
inline void offsetDomain(double o) {
assert(IS_FINITE(o));
assert(is_finite(o));
if(o != 0)
for(unsigned i = 0; i <= size(); i++)
cuts[i] += o;
207,18 → 156,14
//Transforms the domain into another interval
inline void setDomain(Interval dom) {
if(empty()) return;
/* dom can not be empty
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;
//fix floating point precision errors.
cuts[0] = dom.min();
cuts[size()] = dom.max();
}
 
//Concatenates this Piecewise function with another, offseting time of the other to match the end.
232,7 → 177,6
 
segs.insert(segs.end(), other.segs.begin(), other.segs.end());
double t = cuts.back() - other.cuts.front();
cuts.reserve(cuts.size() + other.size());
for(unsigned i = 0; i < other.size(); i++)
push_cut(other.cuts[i + 1] + t);
}
241,12 → 185,16
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()) { segs = other.segs; cuts = other.cuts; return; }
if(empty()) {
for(unsigned i = 0; i < other.size(); i++)
push_seg(other[i] + y);
cuts = other.cuts;
return;
}
 
typename T::output_type y = segs.back().at1() - other.segs.front().at0();
double t = cuts.back() - other.cuts.front();
reserve(size() + other.size());
for(unsigned i = 0; i < other.size(); i++)
push(other[i] + y, other.cuts[i + 1] + t);
}
265,11 → 213,6
 
};
 
/**
* ...
* \return ...
* \relates Piecewise
*/
template<typename T>
inline typename FragmentConcept<T>::BoundsType bounds_fast(const Piecewise<T> &f) {
boost::function_requires<FragmentConcept<T> >();
281,11 → 224,6
return ret;
}
 
/**
* ...
* \return ...
* \relates Piecewise
*/
template<typename T>
inline typename FragmentConcept<T>::BoundsType bounds_exact(const Piecewise<T> &f) {
boost::function_requires<FragmentConcept<T> >();
297,18 → 235,12
return ret;
}
 
/**
* ...
* \return ...
* \relates Piecewise
*/
template<typename T>
inline typename FragmentConcept<T>::BoundsType bounds_local(const Piecewise<T> &f, const OptInterval &_m) {
inline typename FragmentConcept<T>::BoundsType bounds_local(const Piecewise<T> &f, const Interval &m) {
boost::function_requires<FragmentConcept<T> >();
 
if(f.empty() || !_m) return typename FragmentConcept<T>::BoundsType();
Interval const &m = *_m;
if(m.isSingular()) return typename FragmentConcept<T>::BoundsType(f(m.min()));
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);
323,10 → 255,7
return ret;
}
 
/**
* Returns a portion of a piece of a Piecewise<T>, given the piece's index and a to/from time.
* \relates Piecewise
*/
//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());
342,8 → 271,6
* Piecewise<T> ac = a.partition(b.cuts);
* Piecewise<T> bc = b.partition(a.cuts);
* //ac.cuts should be equivalent to bc.cuts
*
* \relates Piecewise
*/
template<typename T>
Piecewise<T> partition(const Piecewise<T> &pw, std::vector<double> const &c) {
351,7 → 278,8
if(c.empty()) return Piecewise<T>(pw);
 
Piecewise<T> ret = Piecewise<T>();
ret.reserve(c.size() + pw.cuts.size() - 1);
ret.cuts.reserve(c.size() + pw.cuts.size());
ret.segs.reserve(c.size() + pw.cuts.size() - 1);
 
if(pw.empty()) {
ret.cuts = c;
409,9 → 337,8
return ret;
}
 
/**
* Returns a Piecewise<T> with a defined domain of [min(from, to), max(from, to)].
* \relates Piecewise
/**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) {
425,7 → 352,7
 
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
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;
}
432,8 → 359,6
ret.push_seg(portion( pw[i], pw.segT(from, i), 1.0 ));
i++;
unsigned fi = pw.segN(to, i);
ret.reserve(fi - i + 1);
if (to == pw.cuts[fi]) fi-=1;
 
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
444,17 → 369,10
return ret;
}
 
//TODO: seems like these should be mutating
/**
* ...
* \return ...
* \relates Piecewise
*/
template<typename T>
Piecewise<T> remove_short_cuts(Piecewise<T> const &f, double tol) {
if(f.empty()) return f;
Piecewise<T> ret;
ret.reserve(f.size());
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) {
464,17 → 382,10
return ret;
}
 
//TODO: seems like these should be mutating
/**
* ...
* \return ...
* \relates Piecewise
*/
template<typename T>
Piecewise<T> remove_short_cuts_extending(Piecewise<T> const &f, double tol) {
if(f.empty()) return f;
Piecewise<T> ret;
ret.reserve(f.size());
ret.push_cut(f.cuts[0]);
double last = f.cuts[0]; // last cut included
for(unsigned i=0; i<f.size(); i++){
486,11 → 397,6
return ret;
}
 
/**
* ...
* \return ...
* \relates Piecewise
*/
template<typename T>
std::vector<double> roots(const Piecewise<T> &pw) {
std::vector<double> ret;
503,17 → 409,11
}
 
//IMPL: OffsetableConcept
/**
* ...
* \return \f$ a + b = \f$
* \relates Piecewise
*/
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;
ret.segs.reserve(a.size());
Piecewise<T> ret = Piecewise<T>();
ret.cuts = a.cuts;
for(unsigned i = 0; i < a.size();i++)
ret.push_seg(a[i] + b);
523,8 → 423,7
Piecewise<T> operator-(Piecewise<T> const &a, typename T::output_type b) {
boost::function_requires<OffsetableConcept<T> >();
//TODO: empty
Piecewise<T> ret;
ret.segs.reserve(a.size());
Piecewise<T> ret = Piecewise<T>();
ret.cuts = a.cuts;
for(unsigned i = 0; i < a.size();i++)
ret.push_seg(a[i] - b);
531,7 → 430,7
return ret;
}
template<typename T>
Piecewise<T>& operator+=(Piecewise<T>& a, typename T::output_type b) {
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; }
541,10 → 440,10
return a;
}
template<typename T>
Piecewise<T>& operator-=(Piecewise<T>& a, typename T::output_type b) {
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; }
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;
552,27 → 451,16
}
 
//IMPL: ScalableConcept
/**
* ...
* \return \f$ -a = \f$
* \relates Piecewise
*/
template<typename T>
Piecewise<T> operator-(Piecewise<T> const &a) {
boost::function_requires<ScalableConcept<T> >();
 
Piecewise<T> ret;
ret.segs.reserve(a.size());
ret.cuts = a.cuts;
for(unsigned i = 0; i < a.size();i++)
ret.push_seg(- a[i]);
return ret;
}
/**
* ...
* \return \f$ a * b = \f$
* \relates Piecewise
*/
template<typename T>
Piecewise<T> operator*(Piecewise<T> const &a, double b) {
boost::function_requires<ScalableConcept<T> >();
580,36 → 468,12
if(a.empty()) return Piecewise<T>();
 
Piecewise<T> ret;
ret.segs.reserve(a.size());
ret.cuts = a.cuts;
for(unsigned i = 0; i < a.size();i++)
ret.push_seg(a[i] * b);
return ret;
}
/**
* ...
* \return \f$ a * b = \f$
* \relates Piecewise
*/
template<typename T>
Piecewise<T> operator*(Piecewise<T> const &a, T b) {
boost::function_requires<ScalableConcept<T> >();
 
if(a.empty()) return Piecewise<T>();
 
Piecewise<T> ret;
ret.segs.reserve(a.size());
ret.cuts = a.cuts;
for(unsigned i = 0; i < a.size();i++)
ret.push_seg(a[i] * b);
return ret;
}
/**
* ...
* \return \f$ a / b = \f$
* \relates Piecewise
*/
template<typename T>
Piecewise<T> operator/(Piecewise<T> const &a, double b) {
boost::function_requires<ScalableConcept<T> >();
 
617,7 → 481,6
if(a.empty()) return Piecewise<T>();
 
Piecewise<T> ret;
ret.segs.reserve(a.size());
ret.cuts = a.cuts;
for(unsigned i = 0; i < a.size();i++)
ret.push_seg(a[i] / b);
624,18 → 487,21
return ret;
}
template<typename T>
Piecewise<T>& operator*=(Piecewise<T>& a, double b) {
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) {
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;
643,29 → 509,18
}
 
//IMPL: AddableConcept
/**
* ...
* \return \f$ a + b = \f$
* \relates Piecewise
*/
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> ret = Piecewise<T>();
assert(pa.size() == pb.size());
ret.segs.reserve(pa.size());
ret.cuts = pa.cuts;
for (unsigned i = 0; i < pa.size(); i++)
ret.push_seg(pa[i] + pb[i]);
return ret;
}
/**
* ...
* \return \f$ a - b = \f$
* \relates Piecewise
*/
template<typename T>
Piecewise<T> operator-(Piecewise<T> const &a, Piecewise<T> const &b) {
boost::function_requires<AddableConcept<T> >();
673,7 → 528,6
Piecewise<T> pa = partition(a, b.cuts), pb = partition(b, a.cuts);
Piecewise<T> ret = Piecewise<T>();
assert(pa.size() == pb.size());
ret.segs.reserve(pa.size());
ret.cuts = pa.cuts;
for (unsigned i = 0; i < pa.size(); i++)
ret.push_seg(pa[i] - pb[i]);
680,21 → 534,16
return ret;
}
template<typename T>
inline Piecewise<T>& operator+=(Piecewise<T> &a, Piecewise<T> const &b) {
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) {
inline Piecewise<T> operator-=(Piecewise<T> &a, Piecewise<T> const &b) {
a = a-b;
return a;
}
 
/**
* ...
* \return \f$ a \cdot b = \f$
* \relates Piecewise
*/
template<typename T1,typename T2>
Piecewise<T2> operator*(Piecewise<T1> const &a, Piecewise<T2> const &b) {
//function_requires<MultiplicableConcept<T1> >();
704,7 → 553,6
Piecewise<T2> pb = partition(b, a.cuts);
Piecewise<T2> ret = Piecewise<T2>();
assert(pa.size() == pb.size());
ret.segs.reserve(pa.size());
ret.cuts = pa.cuts;
for (unsigned i = 0; i < pa.size(); i++)
ret.push_seg(pa[i] * pb[i]);
711,13 → 559,8
return ret;
}
 
/**
* ...
* \return \f$ a \cdot b \f$
* \relates Piecewise
*/
template<typename T>
inline Piecewise<T>& operator*=(Piecewise<T> &a, Piecewise<T> const &b) {
inline Piecewise<T> operator*=(Piecewise<T> &a, Piecewise<T> const &b) {
a = a * b;
return a;
}
742,14 → 585,9
std::vector<double> const &levels,
SBasis const &g);
 
/**
* ...
* \return ...
* \relates Piecewise
*/
//TODO: add concept check
template<typename T>
Piecewise<T> compose(Piecewise<T> const &f, SBasis const &g){
/// \todo add concept check
Piecewise<T> result;
if (f.empty()) return result;
if (g.isZero()) return Piecewise<T>(f(0));
759,7 → 597,7
}
 
//first check bounds...
Interval bs = *bounds_fast(g);
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;
793,14 → 631,9
return(result);
}
 
/**
* ...
* \return ...
* \relates Piecewise
*/
//TODO: add concept check for following composition functions
template<typename T>
Piecewise<T> compose(Piecewise<T> const &f, Piecewise<SBasis> const &g){
/// \todo add concept check
Piecewise<T> result;
for(unsigned i = 0; i < g.segs.size(); i++){
Piecewise<T> fgi=compose(f, g.segs[i]);
810,37 → 643,11
return result;
}
 
/*
Piecewise<D2<SBasis> > compose(D2<SBasis2d> const &sb2d, Piecewise<D2<SBasis> > const &pwd2sb){
/// \todo add concept check
Piecewise<D2<SBasis> > result;
result.push_cut(0.);
for(unsigned i = 0; i < pwd2sb.size(); i++){
result.push(compose_each(sb2d,pwd2sb[i]),i+1);
}
return result;
}*/
 
/** Compose an SBasis with the inverse of another.
* WARNING: It's up to the user to check that the second SBasis is indeed
* invertible (i.e. strictly increasing or decreasing).
* \return \f$ f \cdot g^{-1} \f$
* \relates Piecewise
*/
Piecewise<SBasis> pw_compose_inverse(SBasis const &f, SBasis const &g, unsigned order, double zero);
 
 
 
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);}
 
/**
* ...
* \return ...
* \relates Piecewise
*/
template<typename T>
Piecewise<T> integral(Piecewise<T> const &a) {
Piecewise<T> result;
855,11 → 662,6
return result;
}
 
/**
* ...
* \return ...
* \relates Piecewise
*/
template<typename T>
Piecewise<T> derivative(Piecewise<T> const &a) {
Piecewise<T> result;
873,52 → 675,8
 
std::vector<double> roots(Piecewise<SBasis> const &f);
 
std::vector<std::vector<double> >multi_roots(Piecewise<SBasis> const &f, std::vector<double> const &values);
 
//TODO: implement level_sets directly for pwsb instead of sb (and derive it fo sb).
//It should be faster than the reverse as the algorithm may jump over full cut intervals.
std::vector<Interval> level_set(Piecewise<SBasis> const &f, Interval const &level, double tol=1e-5);
std::vector<Interval> level_set(Piecewise<SBasis> const &f, double v, double vtol, double tol=1e-5);
//std::vector<Interval> level_sets(Piecewise<SBasis> const &f, std::vector<Interval> const &levels, double tol=1e-5);
//std::vector<Interval> level_sets(Piecewise<SBasis> const &f, std::vector<double> &v, double vtol, double tol=1e-5);
 
 
/**
* ...
* \return ...
* \relates Piecewise
*/
template<typename T>
Piecewise<T> reverse(Piecewise<T> const &f) {
Piecewise<T> ret = Piecewise<T>();
ret.reserve(f.size());
double start = f.cuts[0];
double end = f.cuts.back();
for (unsigned i = 0; i < f.cuts.size(); i++) {
double x = f.cuts[f.cuts.size() - 1 - i];
ret.push_cut(end - (x - start));
}
for (unsigned i = 0; i < f.segs.size(); i++)
ret.push_seg(reverse(f[f.segs.size() - i - 1]));
return ret;
}
 
/**
* Interpolates between a and b.
* \return a if t = 0, b if t = 1, or an interpolation between a and b for t in [0,1]
* \relates Piecewise
*/
template<typename T>
Piecewise<T> lerp(double t, Piecewise<T> const &a, Piecewise<T> b) {
// Make sure both paths have the same number of segments and cuts at the same locations
b.setDomain(a.domain());
Piecewise<T> pA = partition(a, b.cuts);
Piecewise<T> pB = partition(b, a.cuts);
 
return (pA*(1-t) + pB*t);
}
 
}
#endif //SEEN_GEOM_PW_SB_H
/*
Local Variables:
/trunk/Scribus/scribus/third_party/lib2geom/convex-cover.h
1,9 → 1,8
#ifndef GEOM_CONVEX_COVER_H
#define GEOM_CONVEX_COVER_H
 
/**
* \file
* \brief \todo brief description
/*
* convex-cover.h
*
* Copyright 2006 Nathan Hurst <njh@mail.csse.monash.edu.au>
* Copyright 2006 Michael G. Sloan <mgsloan@gmail.com>
62,14 → 61,11
public:
std::vector<Point> boundary;
//Point centroid;
 
void merge(Point p);
bool contains_point(Point p);
bool strict_contains_point(Point p);
 
inline size_t size() const { return boundary.size();}
inline Point operator[](int i) const {
 
int l = boundary.size();
if(l == 0) return Point();
return boundary[i >= 0 ? i % l : (i % l) + l];
90,11 → 86,7
 
template <typename T>
ConvexHull(T b, T e) :boundary(b,e) {}
 
~ConvexHull()
{
}
 
public:
/** Is the convex hull clockwise? We use the definition of clockwise from point.h
**/
102,10 → 94,10
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;}
 
112,29 → 104,21
// all points are on a line
bool linear() const { return boundary.size() == 2;}
bool is_degenerate() const;
 
// area of the convex hull
double centroid_and_area(Geom::Point& centroid) const;
double area() const {
Point tmp;
return centroid_and_area(tmp);
}
 
// furthest point in a direction (lg time)
double area() const;
// furthest point in a direction (lg time)
Point const * furthest(Point direction) const;
 
bool is_left(Point p, int n);
bool is_strict_left(Point p, int n);
int find_left(Point p);
int find_strict_left(Point p);
double narrowest_diameter(Point &a, Point &b, Point &c);
 
};
 
// do two convex hulls intersect?
bool intersectp(ConvexHull a, ConvexHull b);
 
std::vector<std::pair<int, int> > bridges(ConvexHull a, ConvexHull b);
std::vector<Point> bridge_points(ConvexHull a, ConvexHull b);
 
// find the convex hull intersection
ConvexHull intersection(ConvexHull a, ConvexHull b);
154,9 → 138,9
*/
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);
}
163,14 → 147,12
return pr;
}
 
ConvexHull clip(ConvexHull const & ch, Point n, double d);
 
//TODO: reinstate
/*class ConvexCover{
public:
Path const* path;
std::vector<ConvexHull> cc;
 
ConvexCover(Path const &sp);
};*/
 
182,9 → 164,11
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
c-file-offsets:((innamespace . 0)(substatement-open . 0))
indent-tabs-mode:nil
c-brace-offset:0
fill-column:99
End:
vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
 
/trunk/Scribus/scribus/third_party/lib2geom/basic-intersection.cpp
1,93 → 1,87
#include <basic-intersection.h>
#include <sbasis-to-bezier.h>
#include <exception.h>
#include "basic-intersection.h"
#include "exception.h"
#include "angle.h"
 
#ifdef HAVE_GSL
#include <gsl/gsl_vector.h>
#include <gsl/gsl_multiroots.h>
#ifndef M_SQRT2
#define M_SQRT2 1.41421356237309504880
#endif
 
 
unsigned intersect_steps = 0;
 
using std::vector;
namespace Geom {
 
//#ifdef USE_RECURSIVE_INTERSECTOR
 
// void find_intersections(std::vector<std::pair<double, double> > &xs,
// D2<SBasis> const & A,
// D2<SBasis> const & B) {
// vector<Point> BezA, BezB;
// sbasis_to_bezier(BezA, A);
// sbasis_to_bezier(BezB, B);
class OldBezier {
public:
std::vector<Geom::Point> p;
OldBezier() {
}
void split(double t, OldBezier &a, OldBezier &b) const;
// xs.clear();
// find_intersections_bezier_recursive(xs, BezA, BezB);
// }
// void find_intersections(std::vector< std::pair<double, double> > & xs,
// std::vector<Point> const& A,
// std::vector<Point> const& B,
// double precision){
// find_intersections_bezier_recursive(xs, A, B, precision);
// }
~OldBezier() {}
 
//#else
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];
}
 
namespace detail{ namespace bezier_clipping {
void portion (std::vector<Point> & B, Interval const& I);
}; };
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];
}
 
void find_intersections(std::vector<std::pair<double, double> > &xs,
D2<SBasis> const & A,
D2<SBasis> const & B) {
vector<Point> BezA, BezB;
sbasis_to_bezier(BezA, A);
sbasis_to_bezier(BezB, B);
 
xs.clear();
}
find_intersections_bezier_clipping(xs, BezA, BezB);
}
void find_intersections(std::vector< std::pair<double, double> > & xs,
std::vector<Point> const& A,
std::vector<Point> const& B,
double precision){
find_intersections_bezier_clipping(xs, A, B, precision);
}
};
 
//#endif
static std::vector<std::pair<double, double> >
find_intersections( OldBezier a, OldBezier b);
 
/*
* 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 split(vector<Point> const &p, double t,
vector<Point> &left, vector<Point> &right) {
const unsigned sz = p.size();
Geom::Point Vtemp[sz][sz];
static std::vector<std::pair<double, double> >
find_self_intersections(OldBezier const &Sb, D2<SBasis> const & A);
 
/* Copy control points */
std::copy(p.begin(), p.end(), Vtemp[0]);
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);
}
 
/* Triangle computation */
for (unsigned i = 1; i < sz; i++) {
for (unsigned j = 0; j < sz - i; j++) {
Vtemp[i][j] = lerp(t, Vtemp[i-1][j], Vtemp[i-1][j+1]);
}
}
std::vector<std::pair<double, double> >
find_self_intersections(OldBezier const &Sb) {
throwNotImplemented(0);
}
 
left.resize(sz);
right.resize(sz);
for (unsigned j = 0; j < sz; j++)
left[j] = Vtemp[j][0];
for (unsigned j = 0; j < sz; j++)
right[j] = Vtemp[sz-1-j][j];
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);
}
 
 
void
find_self_intersections(std::vector<std::pair<double, double> > &xs,
D2<SBasis> const & 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]));
97,320 → 91,266
dr.push_back(1);
// We want to be sure that we have no empty segments
sort(dr.begin(), dr.end());
vector<double>::iterator new_end = unique(dr.begin(), dr.end());
dr.resize( new_end - dr.begin() );
 
vector<vector<Point> > pieces;
unique(dr.begin(), dr.end());
std::vector<std::pair<double, double> > all_si;
vector<OldBezier> pieces;
{
vector<Point> in, l, r;
sbasis_to_bezier(in, A);
OldBezier in = Sb, l, r;
for(unsigned i = 0; i < dr.size()-1; i++) {
split(in, (dr[i+1]-dr[i]) / (1 - dr[i]), l, r);
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( section, pieces[i], pieces[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))
if( ( l > 1-1e-4 ) && (r < 1e-4) )//FIXME: what precision should be used here???
if((l == 1) && (r == 0))
continue;
xs.push_back(std::make_pair((1-l)*dr[i] + l*dr[i+1],
all_si.push_back(std::make_pair((1-l)*dr[i] + l*dr[i+1],
(1-r)*dr[j] + r*dr[j+1]));
}
}
}
 
// Because i is in order, xs should be roughly already in order?
//sort(xs.begin(), xs.end());
//unique(xs.begin(), xs.end());
// 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;
}
 
#ifdef HAVE_GSL
#include <gsl/gsl_multiroots.h>
 
struct rparams
{
D2<SBasis> const &A;
D2<SBasis> const &B;
};
 
static int
intersect_polish_f (const gsl_vector * x, void *params,
gsl_vector * f)
{
const double x0 = gsl_vector_get (x, 0);
const double x1 = gsl_vector_get (x, 1);
 
Geom::Point dx = ((struct rparams *) params)->A(x0) -
((struct rparams *) params)->B(x1);
 
gsl_vector_set (f, 0, dx[0]);
gsl_vector_set (f, 1, dx[1]);
 
return GSL_SUCCESS;
}
#endif
 
union dbl_64{
long long i64;
double d64;
};
 
static double EpsilonBy(double value, int eps)
{
dbl_64 s;
s.d64 = value;
s.i64 += eps;
return s.d64;
}
 
 
static void intersect_polish_root (D2<SBasis> const &A, double &s,
D2<SBasis> const &B, double &t) {
#ifdef HAVE_GSL
const gsl_multiroot_fsolver_type *T;
gsl_multiroot_fsolver *sol;
 
int status;
size_t iter = 0;
#endif
std::vector<Point> as, bs;
as = A.valueAndDerivatives(s, 2);
bs = B.valueAndDerivatives(t, 2);
Point F = as[0] - bs[0];
double best = dot(F, F);
/* The value of 1.0 / (1L<<14) is enough for most applications */
const double INV_EPS = (1L<<14);
for(int i = 0; i < 4; i++) {
/**
we want to solve
J*(x1 - x0) = f(x0)
|dA(s)[0] -dB(t)[0]| (X1 - X0) = A(s) - B(t)
|dA(s)[1] -dB(t)[1]|
**/
/*
* 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);
 
// We're using the standard transformation matricies, which is numerically rather poor. Much better to solve the equation using elimination.
 
Affine jack(as[1][0], as[1][1],
-bs[1][0], -bs[1][1],
0, 0);
Point soln = (F)*jack.inverse();
double ns = s - soln[0];
double nt = t - soln[1];
as = A.valueAndDerivatives(ns, 2);
bs = B.valueAndDerivatives(nt, 2);
F = as[0] - bs[0];
double trial = dot(F, F);
if (trial > best*0.1) {// we have standards, you know
// At this point we could do a line search
break;
left.p.resize(sz);
right.p.resize(sz);
left.p[0] = Vtemp[0];
right.p[sz-1] = Vtemp[sz-1];
/* 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]);
}
best = trial;
s = ns;
t = nt;
left.p[i] = Vtemp[0];
right.p[sz-1-i] = Vtemp[sz-1-i];
}
}
 
#ifdef HAVE_GSL
const size_t n = 2;
struct rparams p = {A, B};
gsl_multiroot_function f = {&intersect_polish_f, n, &p};
/*
* 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 short-circuit
* 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.
*/
 
double x_init[2] = {s, t};
gsl_vector *x = gsl_vector_alloc (n);
 
gsl_vector_set (x, 0, x_init[0]);
gsl_vector_set (x, 1, x_init[1]);
 
T = gsl_multiroot_fsolver_hybrids;
sol = gsl_multiroot_fsolver_alloc (T, 2);
gsl_multiroot_fsolver_set (sol, &f, x);
 
do
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 2-D 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 near-tangential 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> > &parameters)
{
intersect_steps ++;
if( deptha > 0 )
{
iter++;
status = gsl_multiroot_fsolver_iterate (sol);
 
if (status) /* check if solver is stuck */
break;
 
status =
gsl_multiroot_test_residual (sol->f, 1e-12);
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 );
}
}
while (status == GSL_CONTINUE && iter < 1000);
 
s = gsl_vector_get (sol->x, 0);
t = gsl_vector_get (sol->x, 1);
 
gsl_multiroot_fsolver_free (sol);
gsl_vector_free (x);
#endif
{
// This code does a neighbourhood search for minor improvements.
double best_v = L1(A(s) - B(t));
//std::cout << "------\n" << best_v << std::endl;
Point best(s,t);
while (true) {
Point trial = best;
double trial_v = best_v;
for(int nsi = -1; nsi < 2; nsi++) {
for(int nti = -1; nti < 2; nti++) {
Point n(EpsilonBy(best[0], nsi),
EpsilonBy(best[1], nti));
double c = L1(A(n[0]) - B(n[1]));
//std::cout << c << "; ";
if (c < trial_v) {
trial = n;
trial_v = c;
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 )));
}
}
}
if(trial == best) {
//std::cout << "\n" << s << " -> " << s - best[0] << std::endl;
//std::cout << t << " -> " << t - best[1] << std::endl;
//std::cout << best_v << std::endl;
s = best[0];
t = best[1];
return;
} else {
best = trial;
best_v = trial_v;
}
}
}
}
 
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.
*/
 
void polish_intersections(std::vector<std::pair<double, double> > &xs,
D2<SBasis> const &A, D2<SBasis> const &B)
{
for(unsigned i = 0; i < xs.size(); i++)
intersect_polish_root(A, xs[i].first,
B, xs[i].second);
double Lmax(Point p) {
return std::max(fabs(p[X]), fabs(p[Y]));
}
 
 
/**
* Compute the Hausdorf distance from A to B only.
*/
 
 
#if 0
/** Compute the value of a bezier
Todo: find a good palce for this.
*/
// suggested by Sederberg.
Point OldBezier::operator()(double t) const {
int n = p.size()-1;
double u, bc, tn, tmp;
int i;
Point r;
for(int dim = 0; dim < 2; dim++) {
u = 1.0 - t;
bc = 1;
tn = 1;
tmp = p[0][dim]*u;
for(i=1; i<n; i++){
tn = tn*t;
bc = bc*(n-i+1)/i;
tmp = (tmp + tn*bc*p[i][dim])*u;
}
r[dim] = (tmp + tn*t*p[n][dim]);
}
return r;
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;
}
#endif
 
/**
* Compute the Hausdorf distance from A to B only.
*/
double hausdorfl(D2<SBasis>& A, D2<SBasis> const& B,
double m_precision,
double *a_t, double* b_t) {
std::vector< std::pair<double, double> > xs;
std::vector<Point> Az, Bz;
sbasis_to_bezier (Az, A);
sbasis_to_bezier (Bz, B);
find_collinear_normal(xs, Az, Bz, m_precision);
double h_dist = 0, h_a_t = 0, h_b_t = 0;
double dist = 0;
Point Ax = A.at0();
double t = Geom::nearest_point(Ax, B);
dist = Geom::distance(Ax, B(t));
if (dist > h_dist) {
h_a_t = 0;
h_b_t = t;
h_dist = dist;
}
Ax = A.at1();
t = Geom::nearest_point(Ax, B);
dist = Geom::distance(Ax, B(t));
if (dist > h_dist) {
h_a_t = 1;
h_b_t = t;
h_dist = dist;
}
for (size_t i = 0; i < xs.size(); ++i)
std::vector<std::pair<double, double> > find_intersections( OldBezier a, OldBezier b)
{
std::vector<std::pair<double, double> > parameters;
if( intersect_BB( a, b ) )
{
Point At = A(xs[i].first);
Point Bu = B(xs[i].second);
double distAtBu = Geom::distance(At, Bu);
t = Geom::nearest_point(At, B);
dist = Geom::distance(At, B(t));
//FIXME: we might miss it due to floating point precision...
if (dist >= distAtBu-.1 && distAtBu > h_dist) {
h_a_t = xs[i].first;
h_b_t = xs[i].second;
h_dist = distAtBu;
}
recursively_intersect( a, 0., 1., wangs_theorem(a),
b, 0., 1., wangs_theorem(b),
parameters);
}
if(a_t) *a_t = h_a_t;
if(b_t) *b_t = h_b_t;
return h_dist;
std::sort(parameters.begin(), parameters.end());
return parameters;
}
 
/**
* Compute the symmetric Hausdorf distance.
*/
double hausdorf(D2<SBasis>& A, D2<SBasis> const& B,
double m_precision,
double *a_t, double* b_t) {
double h_dist = hausdorfl(A, B, m_precision, a_t, b_t);
double dist = 0;
Point Bx = B.at0();
double t = Geom::nearest_point(Bx, A);
dist = Geom::distance(Bx, A(t));
if (dist > h_dist) {
if(a_t) *a_t = t;
if(b_t) *b_t = 0;
h_dist = dist;
}
Bx = B.at1();
t = Geom::nearest_point(Bx, A);
dist = Geom::distance(Bx, A(t));
if (dist > h_dist) {
if(a_t) *a_t = t;
if(b_t) *b_t = 1;
h_dist = dist;
}
return h_dist;
}
};
 
/*
/trunk/Scribus/scribus/third_party/lib2geom/svg-elliptical-arc.h
1,14 → 1,7
/**
* \file
* \brief SVG 1.1-compliant elliptical arc curve
/*
* SVG Elliptical Path Support Class
*
*//*
* Authors:
* MenTaLguY <mental@rydia.net>
* Marco Cecchetti <mrcekets at gmail.com>
* Krzysztof Kosiński <tweenk.pl@gmail.com>
*
* Copyright 2007-2009 Authors
* 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
35,236 → 28,359
*/
 
 
#ifndef _2GEOM_SVG_ELLIPTICAL_ARC_H_
#define _2GEOM_SVG_ELLIPTICAL_ARC_H_
#ifndef _SVG_ELLIPTICAL_ARC_H_
#define _SVG_ELLIPTICAL_ARC_H_
 
#include "curve.h"
 
#include "angle.h"
#include "utils.h"
#include "bezier-curve.h"
#include "elliptical-arc.h"
#include "sbasis-curve.h" // for non-native methods
#include "numeric/vector.h"
#include "numeric/fitting-tool.h"
#include "numeric/fitting-model.h"
#include <algorithm>
#include "matrix.h"
#include "sbasis.h"
#include "d2.h"
 
 
namespace Geom
{
 
class SVGEllipticalArc : public EllipticalArc {
public:
SVGEllipticalArc()
: EllipticalArc()
{}
SVGEllipticalArc( Point _initial_point, double _rx, double _ry,
double _rot_angle, bool _large_arc, bool _sweep,
Point _final_point
)
: EllipticalArc(_initial_point, _rx, _ry, _rot_angle, _large_arc, _sweep, _final_point)
{}
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();
}
 
#ifndef DOXYGEN_SHOULD_SKIP_THIS
virtual Curve *duplicate() const {
return new SVGEllipticalArc(*this);
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;
}
virtual Coord valueAt(Coord t, Dim2 d) const {
if (isDegenerate()) return chord().valueAt(t, d);
return EllipticalArc::valueAt(t, d);
 
public:
double center(Geom::Dim2 i) const
{
return m_center[i];
}
virtual Point pointAt(Coord t) const {
if (isDegenerate()) return chord().pointAt(t);
return EllipticalArc::pointAt(t);
 
Point center() const
{
return m_center;
}
virtual std::vector<Point> pointAndDerivatives(Coord t, unsigned int n) const {
if (isDegenerate()) return chord().pointAndDerivatives(t, n);
return EllipticalArc::pointAndDerivatives(t, n);
 
Point initialPoint() const
{
return m_initial_point;
}
virtual Rect boundsExact() const {
if (isDegenerate()) return chord().boundsExact();
return EllipticalArc::boundsExact();
 
Point finalPoint() const
{
return m_final_point;
}
virtual OptRect boundsLocal(OptInterval const &i, unsigned int deg) const {
if (isDegenerate()) return chord().boundsLocal(i, deg);
return EllipticalArc::boundsLocal(i, deg);
 
double start_angle() const
{
return m_start_angle;
}
 
virtual Curve *derivative() const {
if (isDegenerate()) return chord().derivative();
return EllipticalArc::derivative();
double end_angle() const
{
return m_end_angle;
}
 
virtual std::vector<Coord> roots(Coord v, Dim2 d) const {
if (isDegenerate()) return chord().roots(v, d);
return EllipticalArc::roots(v, d);
double ray(Geom::Dim2 i) const
{
return (i == 0) ? m_rx : m_ry;
}
virtual std::vector<Coord> allNearestPoints( Point const& p, double from = 0, double to = 1 ) const {
if (isDegenerate()) {
std::vector<Coord> result;
result.push_back(chord().nearestPoint(p, from, to));
return result;
}
return EllipticalArc::allNearestPoints(p, from, to);
 
bool large_arc_flag() const
{
return m_large_arc;
}
virtual D2<SBasis> toSBasis() const {
if (isDegenerate()) return chord().toSBasis();
return EllipticalArc::toSBasis();
}
virtual bool isSVGCompliant() const { return true; }
// TODO move SVG-specific behavior here.
//protected:
//virtual void _updateCenterAndAngles();
#endif
}; // end class SVGEllipticalArc
 
/*
* useful for testing and debugging
*/
template< class charT >
inline
std::basic_ostream<charT> &
operator<< (std::basic_ostream<charT> & os, const SVGEllipticalArc & ea)
{
os << "{ cx: " << ea.center(X) << ", cy: " << ea.center(Y)
<< ", rx: " << ea.ray(X) << ", ry: " << ea.ray(Y)
<< ", rot angle: " << decimal_round(rad_to_deg(ea.rotationAngle()),2)
<< ", start angle: " << decimal_round(rad_to_deg(ea.initialAngle()),2)
<< ", end angle: " << decimal_round(rad_to_deg(ea.finalAngle()),2)
<< " }";
// void large_arc_flag(bool v)
// {
// m_large_arc = v;
// }
 
return os;
}
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();
}
 
// forward declation
namespace detail
{
struct ellipse_equation;
}
void setFinal( const Point _point)
{
m_final_point = _point;
calculate_center_and_extreme_angles();
}
 
// TODO this needs to be rewritten and moved to EllipticalArc header
/*
* make_elliptical_arc
*
* convert a parametric polynomial curve given in symmetric power basis form
* into an SVGEllipticalArc type; in order to be successfull the input curve
* has to look like an actual elliptical arc even if a certain tolerance
* is allowed through an ad-hoc parameter.
* The conversion is performed through an interpolation on a certain amount of
* sample points computed on the input curve;
* the interpolation computes the coefficients of the general implicit equation
* of an ellipse (A*X^2 + B*XY + C*Y^2 + D*X + E*Y + F = 0), then from the
* implicit equation we compute the parametric form.
*
*/
class make_elliptical_arc
{
public:
typedef D2<SBasis> curve_type;
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();
}
 
/*
* constructor
*
* it doesn't execute the conversion but set the input and output parameters
*
* _ea: the output SVGEllipticalArc that will be generated;
* _curve: the input curve to be converted;
* _total_samples: the amount of sample points to be taken
* on the input curve for performing the conversion
* _tolerance: how much likelihood is required between the input curve
* and the generated elliptical arc; the smaller it is the
* the tolerance the higher it is the likelihood.
*/
make_elliptical_arc( EllipticalArc& _ea,
curve_type const& _curve,
unsigned int _total_samples,
double _tolerance );
bool isDegenerate() const
{
return are_near(initialPoint(), finalPoint());
}
 
private:
bool bound_exceeded( unsigned int k, detail::ellipse_equation const & ee,
double e1x, double e1y, double e2 );
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);
}
}
 
bool check_bound(double A, double B, double C, double D, double E, double F);
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;
}
 
void fit();
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;
}
 
bool make_elliptiarc();
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;
}
 
void print_bound_error(unsigned int k)
EllipticalArc* portion(double f, double t) const
{
std::cerr
<< "tolerance error" << std::endl
<< "at point: " << k << std::endl
<< "error value: "<< dist_err << std::endl
<< "bound: " << dist_bound << std::endl
<< "angle error: " << angle_err
<< " (" << angle_tol << ")" << std::endl;
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;
}
 
public:
/*
* perform the actual conversion
* return true if the conversion is successfull, false on the contrary
*/
bool operator()()
// the arc is the same but traversed in the opposite direction
EllipticalArc* reverse() const
{
// initialize the reference
const NL::Vector & coeff = fitter.result();
fit();
if ( !check_bound(1, coeff[0], coeff[1], coeff[2], coeff[3], coeff[4]) )
return false;
if ( !(make_elliptiarc()) ) return false;
return true;
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;
}
 
/*
* you can set a boolean parameter to tell the conversion routine
* if the output elliptical arc has to be svg compliant or not;
* the default value is true
*/
bool svg_compliant_flag() const
private:
 
double sweep_angle() const
{
return svg_compliant;
Coord d = end_angle() - start_angle();
if ( !sweep_flag() ) d = -d;
if ( d < 0 || are_near(d, 0) )
d += 2*M_PI;
return d;
}
 
void svg_compliant_flag(bool _svg_compliant)
Coord from_01_to_02PI(Coord t) const
{
svg_compliant = _svg_compliant;
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:
EllipticalArc& ea; // output elliptical arc
const curve_type & curve; // input curve
Piecewise<D2<SBasis> > dcurve; // derivative of the input curve
NL::LFMEllipse model; // model used for fitting
// perform the actual fitting task
NL::least_squeares_fitter<NL::LFMEllipse> fitter;
// tolerance: the user-defined tolerance parameter;
// tol_at_extr: the tolerance at end-points automatically computed
// on the value of "tolerance", and usually more strict;
// tol_at_center: tolerance at the center of the ellipse
// angle_tol: tolerance for the angle btw the input curve tangent
// versor and the ellipse normal versor at the sample points
double tolerance, tol_at_extr, tol_at_center, angle_tol;
Point initial_point, final_point; // initial and final end-points
unsigned int N; // total samples
unsigned int last; // N-1
double partitions; // N-1
std::vector<Point> p; // sample points
double dist_err, dist_bound, angle_err;
bool svg_compliant;
Point m_initial_point, m_final_point;
double m_rx, m_ry, m_rot_angle;
bool m_large_arc, m_sweep;
 
double m_start_angle, m_end_angle;
Point m_center;
};
 
 
} // end namespace Geom
}
 
 
#endif /*_SVG_ELLIPTICAL_ARC_H_*/
 
 
#endif /* _2GEOM_SVG_ELLIPTICAL_ARC_H_ */
 
/*
Local Variables:
mode:c++
275,4 → 391,3
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
 
/trunk/Scribus/scribus/third_party/lib2geom/d2-sbasis.cpp
1,4 → 1,4
#include <d2.h>
#include "d2.h"
/* One would think that we would include d2-sbasis.h, however,
* you cannot actually include it in anything - only d2 may import it.
* This is due to the trickinesses of template submatching. */
38,7 → 38,7
return ret;
}
 
D2<Piecewise<SBasis> > make_cuts_independent(Piecewise<D2<SBasis> > const &a) {
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++)
58,19 → 58,8
return result;
}
 
/** @brief Calculates the 'dot product' or 'inner product' of \c a and \c b
* @return \f[
* f(t) \rightarrow \left\{
* \begin{array}{c}
* a_1 \bullet b_1 \\
* a_2 \bullet b_2 \\
* \ldots \\
* a_n \bullet b_n \\
* \end{array}\right.
* \f]
* @relates Piecewise */
Piecewise<SBasis> dot(Piecewise<D2<SBasis> > const &a, Piecewise<D2<SBasis> > const &b)
{
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);
83,30 → 72,6
return result;
}
 
/** @brief Calculates the 'dot product' or 'inner product' of \c a and \c b
* @return \f[
* f(t) \rightarrow \left\{
* \begin{array}{c}
* a_1 \bullet b \\
* a_2 \bullet b \\
* \ldots \\
* a_n \bullet b \\
* \end{array}\right.
* \f]
* @relates Piecewise */
Piecewise<SBasis> dot(Piecewise<D2<SBasis> > const &a, Point const &b)
{
Piecewise<SBasis > result;
if (a.empty()) return result;
 
result.push_cut(a.cuts.front());
for (unsigned i = 0; i < a.size(); ++i){
result.push(dot(a.segs[i],b), a.cuts[i+1]);
}
return result;
}
 
 
Piecewise<SBasis> cross(Piecewise<D2<SBasis> > const &a,
Piecewise<D2<SBasis> > const &b){
Piecewise<SBasis > result;
121,7 → 86,7
return result;
}
 
Piecewise<D2<SBasis> > operator*(Piecewise<D2<SBasis> > const &a, Affine const &m) {
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]);
132,8 → 97,9
}
 
//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)
{
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;
148,12 → 114,12
SBasis &cur_sb =result.segs[cur][dim];
Coord const c=pt0[dim];
if (prev_sb.empty()) {
prev_sb = SBasis(Linear(0.0, c));
prev_sb.push_back(Linear(0.0, c));
} else {
prev_sb[0][1] = c;
}
if (cur_sb.empty()) {
cur_sb = SBasis(Linear(c, 0.0));
cur_sb.push_back(Linear(c, 0.0));
} else {
cur_sb[0][0] = c;
}
163,164 → 129,4
}
return result;
}
 
std::vector<Geom::Piecewise<Geom::D2<Geom::SBasis> > >
split_at_discontinuities (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwsbin, double tol)
{
using namespace Geom;
std::vector<Piecewise<D2<SBasis> > > ret;
unsigned piece_start = 0;
for (unsigned i=0; i<pwsbin.segs.size(); i++){
if (i==(pwsbin.segs.size()-1) || L2(pwsbin.segs[i].at1()- pwsbin.segs[i+1].at0()) > tol){
Piecewise<D2<SBasis> > piece;
piece.cuts.push_back(pwsbin.cuts[piece_start]);
for (unsigned j = piece_start; j<i+1; j++){
piece.segs.push_back(pwsbin.segs[j]);
piece.cuts.push_back(pwsbin.cuts[j+1]);
}
ret.push_back(piece);
piece_start = i+1;
}
}
return ret;
}
 
static void set_first_point(Piecewise<D2<SBasis> > &f, Point a){
if ( f.empty() ){
f.concat(Piecewise<D2<SBasis> >(D2<SBasis>(Linear(a[X]),Linear(a[Y]))));
return;
}
for (unsigned dim=0; dim<2; dim++){
if (f.segs.front()[dim].size() == 0){
f.segs.front()[dim] = SBasis(Linear(a[dim],0));
}else{
f.segs.front()[dim][0][0] = a[dim];
}
}
}
static void set_last_point(Piecewise<D2<SBasis> > &f, Point a){
if ( f.empty() ){
f.concat(Piecewise<D2<SBasis> >(D2<SBasis>(Linear(a[X]),Linear(a[Y]))));
return;
}
for (unsigned dim=0; dim<2; dim++){
if (f.segs.back()[dim].size() == 0){
f.segs.back()[dim] = SBasis(Linear(0,a[dim]));
}else{
f.segs.back()[dim][0][1] = a[dim];
}
}
}
 
std::vector<Piecewise<D2<SBasis> > > fuse_nearby_ends(std::vector<Piecewise<D2<SBasis> > > const &f, double tol){
 
if ( f.size()==0 ) return f;
std::vector<Piecewise<D2<SBasis> > > result;
std::vector<std::vector<unsigned> > pre_result;
for (unsigned i=0; i<f.size(); i++){
bool inserted = false;
Point a = f[i].firstValue();
Point b = f[i].lastValue();
for (unsigned j=0; j<pre_result.size(); j++){
Point aj = f.at(pre_result[j].back()).lastValue();
Point bj = f.at(pre_result[j].front()).firstValue();
if ( L2(a-aj) < tol ) {
pre_result[j].push_back(i);
inserted = true;
break;
}
if ( L2(b-bj) < tol ) {
pre_result[j].insert(pre_result[j].begin(),i);
inserted = true;
break;
}
}
if (!inserted) {
pre_result.push_back(std::vector<unsigned>());
pre_result.back().push_back(i);
}
}
for (unsigned i=0; i<pre_result.size(); i++){
Piecewise<D2<SBasis> > comp;
for (unsigned j=0; j<pre_result[i].size(); j++){
Piecewise<D2<SBasis> > new_comp = f.at(pre_result[i][j]);
if ( j>0 ){
set_first_point( new_comp, comp.segs.back().at1() );
}
comp.concat(new_comp);
}
if ( L2(comp.firstValue()-comp.lastValue()) < tol ){
//TODO: check sizes!!!
set_last_point( comp, comp.segs.front().at0() );
}
result.push_back(comp);
}
return result;
return f;
}
 
/*
* Computes the intersection of two sets given as (ordered) union of intervals.
*/
static std::vector<Interval> intersect( std::vector<Interval> const &a, std::vector<Interval> const &b){
std::vector<Interval> result;
//TODO: use order!
for (unsigned i=0; i < a.size(); i++){
for (unsigned j=0; j < b.size(); j++){
OptInterval c( a[i] );
c &= b[j];
if ( c ) {
result.push_back( *c );
}
}
}
return result;
}
 
std::vector<Interval> level_set( D2<SBasis> const &f, Rect region){
std::vector<Rect> regions( 1, region );
return level_sets( f, regions ).front();
}
std::vector<Interval> level_set( D2<SBasis> const &f, Point p, double tol){
Rect region(p, p);
region.expandBy( tol );
return level_set( f, region );
}
std::vector<std::vector<Interval> > level_sets( D2<SBasis> const &f, std::vector<Rect> regions){
std::vector<Interval> regsX (regions.size(), Interval() );
std::vector<Interval> regsY (regions.size(), Interval() );
for ( unsigned i=0; i < regions.size(); i++ ){
regsX[i] = regions[i][X];
regsY[i] = regions[i][Y];
}
std::vector<std::vector<Interval> > x_in_regs = level_sets( f[X], regsX );
std::vector<std::vector<Interval> > y_in_regs = level_sets( f[Y], regsY );
std::vector<std::vector<Interval> >result(regions.size(), std::vector<Interval>() );
for (unsigned i=0; i<regions.size(); i++){
result[i] = intersect ( x_in_regs[i], y_in_regs[i] );
}
return result;
}
std::vector<std::vector<Interval> > level_sets( D2<SBasis> const &f, std::vector<Point> pts, double tol){
std::vector<Rect> regions( pts.size(), Rect() );
for (unsigned i=0; i<pts.size(); i++){
regions[i] = Rect( pts[i], pts[i] );
regions[i].expandBy( tol );
}
return level_sets( f, regions );
}
 
 
} // namespace Geom
 
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/geom.cpp
1,14 → 1,13
/**
* \file src/geom.cpp
* \brief Various geometrical calculations.
*/
 
#ifdef HAVE_CONFIG_H
# include <scconfig.h>
#endif
// #ifdef HAVE_CONFIG_H
// # include <config.h>
// #endif
#include "geom.h"
#include "point.h"
#include <algorithm>
#include "rect.h"
 
namespace Geom {
 
51,7 → 50,7
* x = (fb - ce)/(bd - ae) \endverbatim
*
* If the denominator (bd-ae) is 0 then the lines are parallel, if the
* numerators are 0 then the lines coincide.
* numerators are then 0 then the lines coincide.
*
* \todo Why not use existing but outcommented code below
* (HAVE_NEW_INTERSECTOR_CODE)?
84,6 → 83,7
 
 
 
 
/* ccw exists as a building block */
int
intersector_ccw(const Geom::Point& p0, const Geom::Point& p1,
110,24 → 110,6
}
}
 
/** Determine whether the line segment from p00 to p01 intersects the
infinite line passing through p10 and p11. This doesn't find the
point of intersection, use the line_intersect function above,
or the segment_intersection interface below.
 
\pre neither segment is zero-length; i.e. p00 != p01 and p10 != p11.
*/
bool
line_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;
 
return ((intersector_ccw(p00, p01, p10) * intersector_ccw(p00, p01, p11)) <= 0 );
}
 
 
/** 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.
134,9 → 116,9
 
\pre neither segment is zero-length; i.e. p00 != p01 and p10 != p11.
*/
bool
static bool
segment_intersectp(Geom::Point const &p00, Geom::Point const &p01,
Geom::Point const &p10, Geom::Point const &p11)
Geom::Point const &p10, Geom::Point const &p11)
{
if(p00 == p01) return false;
if(p10 == p11) return false;
143,34 → 125,14
 
/* true iff ( (the p1 segment straddles the p0 infinite line)
* and (the p0 segment straddles the p1 infinite line) ). */
return (line_segment_intersectp(p00, p01, p10, p11) &&
line_segment_intersectp(p10, p11, p00, p01));
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 a line segments intersects an (infinite) line.
 
If there is no intersection, then \a result remains unchanged.
 
\pre neither segment is zero-length; i.e. p00 != p01 and p10 != p11.
**/
IntersectorKind
line_segment_intersect(Geom::Point const &p00, Geom::Point const &p01,
Geom::Point const &p10, Geom::Point const &p11,
Geom::Point &result)
{
if(line_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.
179,8 → 141,8
**/
IntersectorKind
segment_intersect(Geom::Point const &p00, Geom::Point const &p01,
Geom::Point const &p10, Geom::Point const &p11,
Geom::Point &result)
Geom::Point const &p10, Geom::Point const &p11,
Geom::Point &result)
{
if(segment_intersectp(p00, p01, p10, p11)) {
Geom::Point n0 = (p01 - p00).ccw();
213,135 → 175,6
return line_intersection(n0, d0, n1, d1, result);
}
 
// this is used to compare points for std::sort below
static bool
is_less(Point const &A, Point const &B)
{
if (A[X] < B[X]) {
return true;
} else if (A[X] == B[X] && A[Y] < B[Y]) {
return true;
} else {
return false;
}
}
 
// TODO: this can doubtlessly be improved
static void
eliminate_duplicates_p(std::vector<Point> &pts)
{
unsigned int size = pts.size();
 
if (size < 2)
return;
 
if (size == 2) {
if (pts[0] == pts[1]) {
pts.pop_back();
}
} else {
std::sort(pts.begin(), pts.end(), &is_less);
if (size == 3) {
if (pts[0] == pts[1]) {
pts.erase(pts.begin());
} else if (pts[1] == pts[2]) {
pts.pop_back();
}
} else {
// we have size == 4
if (pts[2] == pts[3]) {
pts.pop_back();
}
if (pts[0] == pts[1]) {
pts.erase(pts.begin());
}
}
}
}
 
/** Determine whether \& where an (infinite) line intersects a rectangle.
*
* \a c0, \a c1 are diagonal corners of the rectangle and
* \a p1, \a p1 are distinct points on the line
*
* \return A list (possibly empty) of points of intersection. If two such points (say \a r0 and \a
* r1) then it is guaranteed that the order of \a r0, \a r1 along the line is the same as the that
* of \a c0, \a c1 (i.e., the vectors \a r1 - \a r0 and \a p1 - \a p0 point into the same
* direction).
*/
std::vector<Geom::Point>
rect_line_intersect(Geom::Point const &c0, Geom::Point const &c1,
Geom::Point const &p0, Geom::Point const &p1)
{
using namespace Geom;
 
std::vector<Point> results;
 
Point A(c0);
Point C(c1);
 
Point B(A[X], C[Y]);
Point D(C[X], A[Y]);
 
Point res;
 
if (line_segment_intersect(p0, p1, A, B, res) == intersects) {
results.push_back(res);
}
if (line_segment_intersect(p0, p1, B, C, res) == intersects) {
results.push_back(res);
}
if (line_segment_intersect(p0, p1, C, D, res) == intersects) {
results.push_back(res);
}
if (line_segment_intersect(p0, p1, D, A, res) == intersects) {
results.push_back(res);
}
 
eliminate_duplicates_p(results);
 
if (results.size() == 2) {
// sort the results so that the order is the same as that of p0 and p1
Point dir1 (results[1] - results[0]);
Point dir2 (p1 - p0);
if (dot(dir1, dir2) < 0) {
std::swap(results[0], results[1]);
}
}
 
return results;
}
 
/** Determine whether \& where an (infinite) line intersects a rectangle.
*
* \a c0, \a c1 are diagonal corners of the rectangle and
* \a p1, \a p1 are distinct points on the line
*
* \return A list (possibly empty) of points of intersection. If two such points (say \a r0 and \a
* r1) then it is guaranteed that the order of \a r0, \a r1 along the line is the same as the that
* of \a c0, \a c1 (i.e., the vectors \a r1 - \a r0 and \a p1 - \a p0 point into the same
* direction).
*/
boost::optional<LineSegment>
rect_line_intersect(Geom::Rect &r,
Geom::LineSegment ls)
{
std::vector<Point> results;
results = rect_line_intersect(r.min(), r.max(), ls[0], ls[1]);
if(results.size() == 2) {
return LineSegment(results[0], results[1]);
}
return boost::optional<LineSegment>();
}
 
boost::optional<LineSegment>
rect_line_intersect(Geom::Rect &r,
Geom::Line l)
{
return rect_line_intersect(r, l.segment(0, 1));
}
 
/**
* polyCentroid: Calculates the centroid (xCentroid, yCentroid) and area of a polygon, given its
* vertices (x[0], y[0]) ... (x[n-1], y[n-1]). It is assumed that the contour is closed, i.e., that
356,7 → 189,7
* for now we require the path to be a polyline and assume it is closed.
**/
 
int centroid(std::vector<Geom::Point> const &p, Geom::Point& centroid, double &area) {
int centroid(std::vector<Geom::Point> p, Geom::Point& centroid, double &area) {
const unsigned n = p.size();
if (n < 3)
return 1;
/trunk/Scribus/scribus/third_party/lib2geom/region.h
1,37 → 1,3
/**
* \file
* \brief \todo brief description
*
* Authors:
* ? <?@?.?>
*
* Copyright ?-? authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
*/
 
#ifndef __2GEOM_REGION_H
#define __2GEOM_REGION_H
 
48,14 → 14,14
friend Shape shape_boolean(bool rev, Shape const & a, Shape const & b, CrossingSet const & crs);
 
Path boundary;
mutable OptRect box;
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, OptRect const &b) : boundary(p), box(b) { fill = path_direction(p); }
Region(Path const &p, OptRect const &b, bool dir) : boundary(p), box(b), 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(); }
65,7 → 31,7
operator Path() const { return boundary; }
Rect boundsFast() const {
if(!box) box = boundary.boundsFast(); /// \todo this doesn't look right at all...
if(!box) box = boost::optional<Rect>(boundary.boundsFast());
return *box;
}
81,7 → 47,7
Region inverse() const { return Region(boundary.reverse(), box, !fill); }
Region operator*(Affine const &m) const;
Region operator*(Matrix const &m) const;
bool invariants() const;
};
117,14 → 83,3
}
 
#endif
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/poly.h
1,39 → 1,5
/**
* \file
* \brief \todo brief description
*
* Authors:
* ? <?@?.?>
*
* Copyright ?-? authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
*/
 
#ifndef LIB2GEOM_SEEN_POLY_H
#define LIB2GEOM_SEEN_POLY_H
#ifndef SEEN_POLY_H
#define SEEN_POLY_H
#include <assert.h>
#include <vector>
#include <iostream>
41,24 → 7,22
#include <complex>
#include "utils.h"
 
namespace Geom {
 
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 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]);
}
66,7 → 30,7
result.push_back((*this)[i]);
for(unsigned i = min_size; i < p.size(); i++)
result.push_back(p[i]);
// assert(result.size() == out_size);
assert(result.size() == out_size);
return result;
}
Poly operator-(const Poly& p) const {
74,7 → 38,7
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]);
}
89,7 → 53,7
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];
}
101,7 → 65,7
Poly result;
const unsigned out_size = size();
result.reserve(out_size);
 
for(unsigned i = 0; i < out_size; i++) {
result.push_back((*this)[i]);
}
111,7 → 75,7
Poly operator-() const {
Poly result;
result.resize(size());
 
for(unsigned i = 0; i < size(); i++) {
result[i] = -(*this)[i];
}
121,7 → 85,7
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);
}
128,20 → 92,33
assert(result.size() == out_size);
return result;
}
// equivalent to multiply by x^terms, negative terms are disallowed
Poly shifted(unsigned const terms) const {
// equivalent to multiply by x^terms, discard negative terms
Poly shifted(unsigned terms) const {
Poly result;
size_type const out_size = size() + terms;
// This was a no-op and breaks the build on x86_64, as it's trying
// to take maximum of 32-bit and 64-bit integers
//const unsigned out_size = std::max(unsigned(0), size()+terms);
const size_type out_size = size() + terms;
result.reserve(out_size);
 
result.resize(terms, 0.0);
result.insert(result.end(), this->begin(), this->end());
 
if(terms < 0) {
for(unsigned i = 0; i < out_size; i++) {
result.push_back((*this)[i-terms]);
}
} 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;
150,17 → 127,17
}
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 {
181,7 → 158,7
pd[i] *= cnst;
}
}
 
static Poly linear(double ax, double b) {
Poly p;
p.push_back(b);
225,16 → 202,13
out_file << " + ";
} else
out_file << in_poly[i];
 
}
}
return out_file;
}
 
} // namespace Geom
 
#endif //LIB2GEOM_SEEN_POLY_H
 
/*
Local Variables:
mode:c++
245,3 → 219,4
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
#endif
/trunk/Scribus/scribus/third_party/lib2geom/svg-path.cpp
28,26 → 28,16
*
*/
 
#include <sbasis-to-bezier.h>
#include <svg-path.h>
#include <exception.h>
#include "sbasis-to-bezier.h"
#include "svg-path.h"
 
namespace Geom {
 
void output(Curve const &curve, SVGPathSink &sink) {
std::vector<Point> pts;
sbasis_to_bezier(pts, curve.toSBasis(), 2); //TODO: use something better!
std::vector<Point> pts = sbasis_to_bezier(curve.toSBasis(), 2); //TODO: use something better!
sink.curveTo(pts[0], pts[1], pts[2]);
}
 
void output(HLineSegment const &curve, SVGPathSink &sink) {
sink.hlineTo(curve.finalPoint()[X]);
}
 
void output(VLineSegment const &curve, SVGPathSink &sink) {
sink.vlineTo(curve.finalPoint()[Y]);
}
 
void output(LineSegment const &curve, SVGPathSink &sink) {
sink.lineTo(curve[1]);
}
61,9 → 51,7
}
 
void output(SVGEllipticalArc const &curve, SVGPathSink &sink) {
sink.arcTo( curve.ray(X), curve.ray(Y), curve.rotationAngle(),
curve.largeArc(), curve.sweep(),
curve.finalPoint() );
// FIXME
}
 
template <typename T>
82,8 → 70,6
 
Path::iterator iter;
for ( iter = path.begin() ; iter != path.end() ; ++iter ) {
output_as<HLineSegment>(*iter, sink) ||
output_as<VLineSegment>(*iter, sink) ||
output_as<LineSegment>(*iter, sink) ||
output_as<CubicBezier>(*iter, sink) ||
output_as<QuadraticBezier>(*iter, sink) ||
/trunk/Scribus/scribus/third_party/lib2geom/ord.h
1,36 → 1,3
/**
* \file
* \brief \todo brief description
*
* Authors:
* ? <?@?.?>
*
* Copyright ?-? authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
*/
 
#ifndef __2GEOM_ORD__
#define __2GEOM_ORD__
68,14 → 35,3
}
 
#endif
 
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/path.cpp
1,70 → 1,99
/*
* Path - Series of continuous curves
*
* Authors:
* MenTaLguY <mental@rydia.net>
* Marco Cecchetti <mrcekets at gmail.com>
*
* Copyright 2007-2008 authors
*
* This library is free software; you can redistribute it and/or
*
* 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
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*/
 
#include "path.h"
 
#include "ord.h"
 
namespace Geom {
 
#include <path.h>
#include <algorithm>
int CurveHelpers::root_winding(Curve const &c, Point p) {
std::vector<double> ts = c.roots(p[Y], Y);
 
if(ts.empty()) return 0;
 
using namespace Geom::PathInternal;
double const fudge = 0.01; //fudge factor used on first and last
 
namespace Geom
{
std::sort(ts.begin(), ts.end());
 
OptRect Path::boundsFast() const {
OptRect bounds;
if (empty()) return bounds;
bounds=front().boundsFast();
const_iterator iter = begin();
if ( iter != end() ) {
for ( ++iter; iter != end() ; ++iter ) {
bounds.unionWith(iter->boundsFast());
// 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;
}
 
OptRect Path::boundsExact() const {
OptRect bounds;
if (empty()) return bounds;
bounds=front().boundsExact();
const_iterator iter = begin();
if ( iter != end() ) {
for ( ++iter; iter != end() ; ++iter ) {
bounds.unionWith(iter->boundsExact());
}
Rect Path::boundsExact() const {
Rect bounds=front().boundsExact();
for ( const_iterator iter=++begin(); iter != end() ; ++iter ) {
bounds.unionWith(iter->boundsExact());
}
return bounds;
}
77,221 → 106,9
return ret;
}
 
Path &Path::operator*=(Affine const &m) {
unshare();
Sequence::iterator last = get_curves().end() - 1;
Sequence::iterator it;
Point prev;
for (it = get_curves().begin() ; it != last ; ++it) {
*it = boost::shared_ptr<Curve>((*it)->transformed(m));
if ( it != get_curves().begin() && (*it)->initialPoint() != prev ) {
THROW_CONTINUITYERROR();
}
prev = (*it)->finalPoint();
}
for ( int i = 0 ; i < 2 ; ++i ) {
final_->setPoint(i, (*final_)[i] * m);
}
if (get_curves().size() > 1) {
if ( front().initialPoint() != initialPoint() || back().finalPoint() != finalPoint() ) {
THROW_CONTINUITYERROR();
}
}
return *this;
}
 
std::vector<double>
Path::allNearestPoints(Point const& _point, double from, double to) const
{
if ( from > to ) std::swap(from, to);
const Path& _path = *this;
unsigned int sz = _path.size();
if ( _path.closed() ) ++sz;
if ( from < 0 || to > sz )
{
THROW_RANGEERROR("[from,to] interval out of bounds");
}
double sif, st = modf(from, &sif);
double eif, et = modf(to, &eif);
unsigned int si = static_cast<unsigned int>(sif);
unsigned int ei = static_cast<unsigned int>(eif);
if ( si == sz )
{
--si;
st = 1;
}
if ( ei == sz )
{
--ei;
et = 1;
}
if ( si == ei )
{
std::vector<double> all_nearest =
_path[si].allNearestPoints(_point, st, et);
for ( unsigned int i = 0; i < all_nearest.size(); ++i )
{
all_nearest[i] = si + all_nearest[i];
}
return all_nearest;
}
std::vector<double> all_t;
std::vector< std::vector<double> > all_np;
all_np.push_back( _path[si].allNearestPoints(_point, st) );
std::vector<unsigned int> ni;
ni.push_back(si);
double dsq;
double mindistsq
= distanceSq( _point, _path[si].pointAt( all_np.front().front() ) );
Rect bb(Geom::Point(0,0),Geom::Point(0,0));
for ( unsigned int i = si + 1; i < ei; ++i )
{
bb = (_path[i].boundsFast());
dsq = distanceSq(_point, bb);
if ( mindistsq < dsq ) continue;
all_t = _path[i].allNearestPoints(_point);
dsq = distanceSq( _point, _path[i].pointAt( all_t.front() ) );
if ( mindistsq > dsq )
{
all_np.clear();
all_np.push_back(all_t);
ni.clear();
ni.push_back(i);
mindistsq = dsq;
}
else if ( mindistsq == dsq )
{
all_np.push_back(all_t);
ni.push_back(i);
}
}
bb = (_path[ei].boundsFast());
dsq = distanceSq(_point, bb);
if ( mindistsq >= dsq )
{
all_t = _path[ei].allNearestPoints(_point, 0, et);
dsq = distanceSq( _point, _path[ei].pointAt( all_t.front() ) );
if ( mindistsq > dsq )
{
for ( unsigned int i = 0; i < all_t.size(); ++i )
{
all_t[i] = ei + all_t[i];
}
return all_t;
}
else if ( mindistsq == dsq )
{
all_np.push_back(all_t);
ni.push_back(ei);
}
}
std::vector<double> all_nearest;
for ( unsigned int i = 0; i < all_np.size(); ++i )
{
for ( unsigned int j = 0; j < all_np[i].size(); ++j )
{
all_nearest.push_back( ni[i] + all_np[i][j] );
}
}
all_nearest.erase(std::unique(all_nearest.begin(), all_nearest.end()),
all_nearest.end());
return all_nearest;
}
 
std::vector<double>
Path::nearestPointPerCurve(Point const& _point) const
{
//return a single nearest point for each curve in this path
std::vector<double> np;
for (const_iterator it = begin() ; it != end_default() ; ++it)
//for (std::vector<Path>::const_iterator it = _path.begin(); it != _path.end(), ++it){
{
np.push_back(it->nearestPoint(_point));
}
return np;
}
 
double Path::nearestPoint(Point const &_point, double from, double to, double *distance_squared) const
{
if ( from > to ) std::swap(from, to);
const Path& _path = *this;
unsigned int sz = _path.size();
if ( _path.closed() ) ++sz;
if ( from < 0 || to > sz )
{
THROW_RANGEERROR("[from,to] interval out of bounds");
}
double sif, st = modf(from, &sif);
double eif, et = modf(to, &eif);
unsigned int si = static_cast<unsigned int>(sif);
unsigned int ei = static_cast<unsigned int>(eif);
if(sz == 0) {// naked moveto
if (distance_squared != NULL)
*distance_squared = distanceSq(_point, _path.initialPoint());
return 0;
}
if ( si == sz )
{
--si;
st = 1;
}
if ( ei == sz )
{
--ei;
et = 1;
}
if ( si == ei )
{
double nearest = _path[si].nearestPoint(_point, st, et);
if (distance_squared != NULL)
*distance_squared = distanceSq(_point, _path[si].pointAt(nearest));
return si + nearest;
}
 
double t;
double nearest = _path[si].nearestPoint(_point, st);
unsigned int ni = si;
double dsq;
double mindistsq = distanceSq(_point, _path[si].pointAt(nearest));
Rect bb(Geom::Point(0,0),Geom::Point(0,0));
for ( unsigned int i = si + 1; i < ei; ++i )
{
bb = (_path[i].boundsFast());
dsq = distanceSq(_point, bb);
if ( mindistsq <= dsq ) continue;
t = _path[i].nearestPoint(_point);
dsq = distanceSq(_point, _path[i].pointAt(t));
if ( mindistsq > dsq )
{
nearest = t;
ni = i;
mindistsq = dsq;
}
}
bb = (_path[ei].boundsFast());
dsq = distanceSq(_point, bb);
if ( mindistsq > dsq )
{
t = _path[ei].nearestPoint(_point, 0, et);
dsq = distanceSq(_point, _path[ei].pointAt(t));
if ( mindistsq > dsq )
{
nearest = t;
ni = ei;
mindistsq = dsq;
}
}
 
if (distance_squared != NULL)
*distance_squared = mindistsq;
 
return ni + nearest;
}
 
//This assumes that you can't be perfect in your t-vals, and as such, tweaks the start
void Path::appendPortionTo(Path &ret, double from, double to) const {
if (!(from >= 0 && to >= 0)) {
THROW_RANGEERROR("from and to must be >=0 in Path::appendPortionTo");
}
assert(from >= 0 && to >= 0);
if(to == 0) to = size()+0.999999;
if(from == to) { return; }
double fi, ti;
300,7 → 117,7
const_iterator fromi = inc(begin(), (unsigned)fi);
if(fi == ti && from < to) {
Curve *v = fromi->portion(ff, tf);
ret.append(*v, STITCH_DISCONTINUOUS);
ret.append(*v);
delete v;
return;
}
308,81 → 125,76
if(ff != 1.) {
Curve *fromv = fromi->portion(ff, 1.);
//fromv->setInitial(ret.finalPoint());
ret.append(*fromv, STITCH_DISCONTINUOUS);
ret.append(*fromv);
delete fromv;
}
if(from >= to) {
const_iterator ender = end();
if(ender->initialPoint() == ender->finalPoint()) ender++;
ret.insert(ret.end(), ++fromi, ender, STITCH_DISCONTINUOUS);
ret.insert(ret.end(), begin(), toi, STITCH_DISCONTINUOUS);
ret.insert(ret.end(), ++fromi, ender);
ret.insert(ret.end(), begin(), toi);
} else {
ret.insert(ret.end(), ++fromi, toi, STITCH_DISCONTINUOUS);
ret.insert(ret.end(), ++fromi, toi);
}
Curve *tov = toi->portion(0., tf);
ret.append(*tov, STITCH_DISCONTINUOUS);
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)
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
get_curves().erase(first_replaced, last_replaced);
get_curves().insert(first_replaced, first, last);
curves_.erase(first_replaced, last_replaced);
curves_.insert(first_replaced, first, last);
}
 
if ( get_curves().front().get() != final_ ) {
if ( curves_.front() != final_ ) {
final_->setPoint(0, back().finalPoint());
final_->setPoint(1, front().initialPoint());
}
}
 
void Path::do_append(Curve *c) {
boost::shared_ptr<Curve> curve(c);
if ( get_curves().front().get() == final_ ) {
void Path::do_append(Curve *curve) {
if ( curves_.front() == final_ ) {
final_->setPoint(1, curve->initialPoint());
} else {
if (curve->initialPoint() != finalPoint()) {
THROW_CONTINUITYERROR();
}
}
get_curves().insert(get_curves().end()-1, curve);
curves_.insert(curves_.end()-1, curve);
final_->setPoint(0, curve->finalPoint());
}
 
void Path::stitch(Sequence::iterator first_replaced,
Sequence::iterator last_replaced,
Sequence &source)
{
if (!source.empty()) {
if ( first_replaced != get_curves().begin() ) {
if ( (*first_replaced)->initialPoint() != source.front()->initialPoint() ) {
Curve *stitch = new StitchSegment((*first_replaced)->initialPoint(),
source.front()->initialPoint());
source.insert(source.begin(), boost::shared_ptr<Curve>(stitch));
}
}
if ( last_replaced != (get_curves().end()-1) ) {
if ( (*last_replaced)->finalPoint() != source.back()->finalPoint() ) {
Curve *stitch = new StitchSegment(source.back()->finalPoint(),
(*last_replaced)->finalPoint());
source.insert(source.end(), boost::shared_ptr<Curve>(stitch));
}
}
} else if ( first_replaced != last_replaced && first_replaced != get_curves().begin() && last_replaced != get_curves().end()-1) {
if ( (*first_replaced)->initialPoint() != (*(last_replaced-1))->finalPoint() ) {
Curve *stitch = new StitchSegment((*(last_replaced-1))->finalPoint(),
(*first_replaced)->initialPoint());
source.insert(source.begin(), boost::shared_ptr<Curve>(stitch));
}
void Path::delete_range(Sequence::iterator first, Sequence::iterator last) {
for ( Sequence::iterator iter=first ; iter != last ; ++iter ) {
delete *iter;
}
}
 
392,32 → 204,55
Sequence::iterator last)
{
if ( first != last ) {
if ( first_replaced != get_curves().begin() ) {
if ( (*first_replaced)->initialPoint() != (*first)->initialPoint() ) {
THROW_CONTINUITYERROR();
if ( first_replaced != curves_.begin() ) {
if ( !are_near( (*first_replaced)->initialPoint(), (*first)->initialPoint(), eps ) ) {
throwContinuityError(0);
}
}
if ( last_replaced != (get_curves().end()-1) ) {
if ( (*(last_replaced-1))->finalPoint() != (*(last-1))->finalPoint() ) {
THROW_CONTINUITYERROR();
if ( last_replaced != (curves_.end()-1) ) {
if ( !are_near( (*(last_replaced-1))->finalPoint(), (*(last-1))->finalPoint(), eps ) ) {
throwContinuityError(0);
}
}
} else if ( first_replaced != last_replaced && first_replaced != get_curves().begin() && last_replaced != get_curves().end()-1) {
if ( (*first_replaced)->initialPoint() != (*(last_replaced-1))->finalPoint() ) {
THROW_CONTINUITYERROR();
} else if ( first_replaced != last_replaced && first_replaced != curves_.begin() && last_replaced != curves_.end()-1) {
if ( !are_near((*first_replaced)->initialPoint(), (*(last_replaced-1))->finalPoint(), eps ) ) {
throwContinuityError(0);
}
}
}
 
} // end namespace Geom
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++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
c-file-offsets:((innamespace . 0)(substatement-open . 0))
indent-tabs-mode:nil
c-brace-offset:0
fill-column:99
End:
vim: filetype=cpp:expandtab:shiftwidth=2:tabstop=8:softtabstop=2 :
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
/trunk/Scribus/scribus/third_party/lib2geom/CMakeLists.txt
18,41 → 18,12
SET(2GEOM_SRC
svg-path.h
svg-path.cpp
#svg-path-parser.h
#svg-path-parser.cpp
ord.h
nearest-point.cpp
nearest-point.h
bezier-clipping.cpp
bezier-curve.cpp
bezier-curve.h
circle.cpp
circle.h
conicsec.h
conicsec.cpp
conic_section_clipper.cpp
conic_section_clipper.h
conic_section_clipper_cr.h
conic_section_clipper_impl.h
curve.h
curve.cpp
curves.h
ellipse.cpp
ellipse.h
elliptical-arc.cpp
elliptical-arc.h
hvlinesegment.h
line.cpp
line.h
ray.h
sbasis-curve.h
path.cpp
path.h
path-intersection.cpp
path-intersection.h
pathvector.cpp
pathvector.h
forward.h
svg-elliptical-arc.h
shape.cpp
shape.h
region.cpp
61,18 → 32,16
crossing.cpp
sweep.cpp
sweep.h
toposweep.cpp
toposweep.h
poly.cpp
poly.h
poly-dk-solve.cpp
poly-dk-solve.h
poly-laguerre-solve.cpp
poly-laguerre-solve.h
quadtree.cpp
quadtree.h
redblacktree.cpp
redblacktree.h
rtree.cpp
rtree.h
affine.cpp
affine.h
matrix.cpp
matrix.h
transforms.cpp
transforms.h
point.h
85,12 → 54,10
rect.h
piecewise.h
piecewise.cpp
sbasis-of.h
sbasis.cpp
sbasis.h
sbasis-2d.h
sbasis-2d.cpp
sbasisN.h
sbasis-geometric.cpp
sbasis-geometric.h
sbasis-math.h
103,13 → 70,8
bezier-to-sbasis.h
basic-intersection.h
basic-intersection.cpp
recursive-bezier-intersection.cpp
intersection-by-smashing.h
intersection-by-smashing.cpp
geom.cpp
geom.h
math-utils.h
utils.cpp
utils.h
exception.h
angle.h
124,9 → 86,7
solve-bezier-one-d.cpp
solve-bezier-parametric.cpp
solver.h
svg-elliptical-arc.cpp
svg-elliptical-arc.h
numeric/matrix.cpp
sturm.h
scribushelper.h
scribushelper.cpp
)
/trunk/Scribus/scribus/third_party/lib2geom/crossing.h
1,38 → 1,3
/**
* \file
* \brief \todo brief description
*
* Authors:
* Michael Sloane <?@?.?>
* Marco <?@?.?>
*
* Copyright 2006-2008 authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
*/
 
#ifndef __GEOM_CROSSING_H
#define __GEOM_CROSSING_H
 
39,7 → 4,6
#include <vector>
#include "rect.h"
#include "sweep.h"
#include <boost/optional/optional.hpp>
 
namespace Geom {
 
60,10 → 24,7
bool onIx(unsigned ix) const { return a == ix || b == ix; }
};
 
typedef boost::optional<Crossing> OptCrossing;
 
 
/*
struct Edge {
unsigned node, path;
double time;
88,6 → 49,7
}
};
 
typedef std::vector<Crossing> Crossings;
 
typedef std::vector<CrossingNode> CrossingGraph;
 
99,7 → 61,6
 
class Path;