From 35a96bde514a8897f6f0fcc41c5833bf63df2e2a Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 18:29:01 +0200 Subject: Adding upstream version 1.0.2. Signed-off-by: Daniel Baumann --- src/2geom/d2.h | 564 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 564 insertions(+) create mode 100644 src/2geom/d2.h (limited to 'src/2geom/d2.h') diff --git a/src/2geom/d2.h b/src/2geom/d2.h new file mode 100644 index 0000000..45f036b --- /dev/null +++ b/src/2geom/d2.h @@ -0,0 +1,564 @@ +/** + * \file + * \brief Lifts one dimensional objects into 2D + *//* + * Authors: + * Michael Sloan + * Krzysztof KosiƄski + * + * Copyright 2007-2015 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, output to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + */ + +#ifndef LIB2GEOM_SEEN_D2_H +#define LIB2GEOM_SEEN_D2_H + +#include +#include +#include +#include <2geom/point.h> +#include <2geom/interval.h> +#include <2geom/affine.h> +#include <2geom/rect.h> +#include <2geom/concepts.h> + +namespace Geom { +/** + * @brief Adaptor that creates 2D functions from 1D ones. + * @ingroup Fragments + */ +template +class D2 +{ +private: + T f[2]; + +public: + typedef T D1Value; + typedef T &D1Reference; + typedef T const &D1ConstReference; + + D2() {f[X] = f[Y] = T();} + explicit D2(Point const &a) { + f[X] = T(a[X]); f[Y] = T(a[Y]); + } + + D2(T const &a, T const &b) { + f[X] = a; + f[Y] = b; + } + + template + D2(Iter first, Iter last) { + typedef typename std::iterator_traits::value_type V; + typedef typename boost::transform_iterator, Iter> XIter; + typedef typename boost::transform_iterator, Iter> YIter; + + XIter xfirst(first, GetAxis()), xlast(last, GetAxis()); + f[X] = T(xfirst, xlast); + YIter yfirst(first, GetAxis()), ylast(last, GetAxis()); + f[Y] = T(yfirst, ylast); + } + + D2(std::vector const &vec) { + typedef Point V; + typedef std::vector::const_iterator Iter; + typedef boost::transform_iterator, Iter> XIter; + typedef boost::transform_iterator, Iter> YIter; + + XIter xfirst(vec.begin(), GetAxis()), xlast(vec.end(), GetAxis()); + f[X] = T(xfirst, xlast); + YIter yfirst(vec.begin(), GetAxis()), ylast(vec.end(), GetAxis()); + f[Y] = T(yfirst, ylast); + } + + //TODO: ask MenTaLguY about operator= as seen in Point + + T& operator[](unsigned i) { return f[i]; } + T const & operator[](unsigned i) const { return f[i]; } + Point point(unsigned i) const { + Point ret(f[X][i], f[Y][i]); + return ret; + } + + //IMPL: FragmentConcept + typedef Point output_type; + bool isZero(double eps=EPSILON) const { + BOOST_CONCEPT_ASSERT((FragmentConcept)); + return f[X].isZero(eps) && f[Y].isZero(eps); + } + bool isConstant(double eps=EPSILON) const { + BOOST_CONCEPT_ASSERT((FragmentConcept)); + return f[X].isConstant(eps) && f[Y].isConstant(eps); + } + bool isFinite() const { + BOOST_CONCEPT_ASSERT((FragmentConcept)); + return f[X].isFinite() && f[Y].isFinite(); + } + Point at0() const { + BOOST_CONCEPT_ASSERT((FragmentConcept)); + return Point(f[X].at0(), f[Y].at0()); + } + Point at1() const { + BOOST_CONCEPT_ASSERT((FragmentConcept)); + return Point(f[X].at1(), f[Y].at1()); + } + Point pointAt(double t) const { + BOOST_CONCEPT_ASSERT((FragmentConcept)); + return (*this)(t); + } + Point valueAt(double t) const { + // TODO: remove this alias + BOOST_CONCEPT_ASSERT((FragmentConcept)); + return (*this)(t); + } + std::vector valueAndDerivatives(double t, unsigned n) const { + BOOST_CONCEPT_ASSERT((FragmentConcept)); + std::vector x = f[X].valueAndDerivatives(t, n), + y = f[Y].valueAndDerivatives(t, n); // always returns a vector of size n+1 + std::vector res(n+1); + for(unsigned i = 0; i <= n; i++) { + res[i] = Point(x[i], y[i]); + } + return res; + } + D2 toSBasis() const { + BOOST_CONCEPT_ASSERT((FragmentConcept)); + return D2(f[X].toSBasis(), f[Y].toSBasis()); + } + + Point operator()(double t) const; + Point operator()(double x, double y) const; +}; +template +inline D2 reverse(const D2 &a) { + BOOST_CONCEPT_ASSERT((FragmentConcept)); + return D2(reverse(a[X]), reverse(a[Y])); +} + +template +inline D2 portion(const D2 &a, Coord f, Coord t) { + BOOST_CONCEPT_ASSERT((FragmentConcept)); + return D2(portion(a[X], f, t), portion(a[Y], f, t)); +} + +template +inline D2 portion(const D2 &a, Interval i) { + BOOST_CONCEPT_ASSERT((FragmentConcept)); + return D2(portion(a[X], i), portion(a[Y], i)); +} + +//IMPL: EqualityComparableConcept +template +inline bool +operator==(D2 const &a, D2 const &b) { + BOOST_CONCEPT_ASSERT((EqualityComparableConcept)); + return a[0]==b[0] && a[1]==b[1]; +} +template +inline bool +operator!=(D2 const &a, D2 const &b) { + BOOST_CONCEPT_ASSERT((EqualityComparableConcept)); + return a[0]!=b[0] || a[1]!=b[1]; +} + +//IMPL: NearConcept +template +inline bool +are_near(D2 const &a, D2 const &b, double tol) { + BOOST_CONCEPT_ASSERT((NearConcept)); + return are_near(a[0], b[0], tol) && are_near(a[1], b[1], tol); +} + +//IMPL: AddableConcept +template +inline D2 +operator+(D2 const &a, D2 const &b) { + BOOST_CONCEPT_ASSERT((AddableConcept)); + + D2 r; + for(unsigned i = 0; i < 2; i++) + r[i] = a[i] + b[i]; + return r; +} +template +inline D2 +operator-(D2 const &a, D2 const &b) { + BOOST_CONCEPT_ASSERT((AddableConcept)); + + D2 r; + for(unsigned i = 0; i < 2; i++) + r[i] = a[i] - b[i]; + return r; +} +template +inline D2 +operator+=(D2 &a, D2 const &b) { + BOOST_CONCEPT_ASSERT((AddableConcept)); + + for(unsigned i = 0; i < 2; i++) + a[i] += b[i]; + return a; +} +template +inline D2 +operator-=(D2 &a, D2 const & b) { + BOOST_CONCEPT_ASSERT((AddableConcept)); + + for(unsigned i = 0; i < 2; i++) + a[i] -= b[i]; + return a; +} + +//IMPL: ScalableConcept +template +inline D2 +operator-(D2 const & a) { + BOOST_CONCEPT_ASSERT((ScalableConcept)); + D2 r; + for(unsigned i = 0; i < 2; i++) + r[i] = -a[i]; + return r; +} +template +inline D2 +operator*(D2 const & a, Point const & b) { + BOOST_CONCEPT_ASSERT((ScalableConcept)); + + D2 r; + for(unsigned i = 0; i < 2; i++) + r[i] = a[i] * b[i]; + return r; +} +template +inline D2 +operator/(D2 const & a, Point const & b) { + BOOST_CONCEPT_ASSERT((ScalableConcept)); + //TODO: b==0? + D2 r; + for(unsigned i = 0; i < 2; i++) + r[i] = a[i] / b[i]; + return r; +} +template +inline D2 +operator*=(D2 &a, Point const & b) { + BOOST_CONCEPT_ASSERT((ScalableConcept)); + + for(unsigned i = 0; i < 2; i++) + a[i] *= b[i]; + return a; +} +template +inline D2 +operator/=(D2 &a, Point const & b) { + BOOST_CONCEPT_ASSERT((ScalableConcept)); + //TODO: b==0? + for(unsigned i = 0; i < 2; i++) + a[i] /= b[i]; + return a; +} + +template +inline D2 operator*(D2 const & a, double b) { return D2(a[0]*b, a[1]*b); } +template +inline D2 operator*=(D2 & a, double b) { a[0] *= b; a[1] *= b; return a; } +template +inline D2 operator/(D2 const & a, double b) { return D2(a[0]/b, a[1]/b); } +template +inline D2 operator/=(D2 & a, double b) { a[0] /= b; a[1] /= b; return a; } + +template +D2 operator*(D2 const &v, Affine const &m) { + BOOST_CONCEPT_ASSERT((AddableConcept)); + BOOST_CONCEPT_ASSERT((ScalableConcept)); + D2 ret; + for(unsigned i = 0; i < 2; i++) + ret[i] = v[X] * m[i] + v[Y] * m[i + 2] + m[i + 4]; + return ret; +} + +//IMPL: MultiplicableConcept +template +inline D2 +operator*(D2 const & a, T const & b) { + BOOST_CONCEPT_ASSERT((MultiplicableConcept)); + D2 ret; + for(unsigned i = 0; i < 2; i++) + ret[i] = a[i] * b; + return ret; +} + +//IMPL: + +//IMPL: OffsetableConcept +template +inline D2 +operator+(D2 const & a, Point b) { + BOOST_CONCEPT_ASSERT((OffsetableConcept)); + D2 r; + for(unsigned i = 0; i < 2; i++) + r[i] = a[i] + b[i]; + return r; +} +template +inline D2 +operator-(D2 const & a, Point b) { + BOOST_CONCEPT_ASSERT((OffsetableConcept)); + D2 r; + for(unsigned i = 0; i < 2; i++) + r[i] = a[i] - b[i]; + return r; +} +template +inline D2 +operator+=(D2 & a, Point b) { + BOOST_CONCEPT_ASSERT((OffsetableConcept)); + for(unsigned i = 0; i < 2; i++) + a[i] += b[i]; + return a; +} +template +inline D2 +operator-=(D2 & a, Point b) { + BOOST_CONCEPT_ASSERT((OffsetableConcept)); + for(unsigned i = 0; i < 2; i++) + a[i] -= b[i]; + return a; +} + +template +inline T +dot(D2 const & a, D2 const & b) { + BOOST_CONCEPT_ASSERT((AddableConcept)); + BOOST_CONCEPT_ASSERT((MultiplicableConcept)); + + T r; + for(unsigned i = 0; i < 2; i++) + r += a[i] * b[i]; + return r; +} + +/** @brief Calculates the 'dot product' or 'inner product' of \c a and \c b + * @return \f$a \bullet b = a_X b_X + a_Y b_Y\f$. + * @relates D2 */ +template +inline T +dot(D2 const & a, Point const & b) { + BOOST_CONCEPT_ASSERT((AddableConcept)); + BOOST_CONCEPT_ASSERT((ScalableConcept)); + + T r; + for(unsigned i = 0; i < 2; i++) { + r += a[i] * b[i]; + } + return r; +} + +/** @brief Calculates the 'cross product' or 'outer product' of \c a and \c b + * @return \f$a \times b = a_Y b_X - a_X b_Y\f$. + * @relates D2 */ +template +inline T +cross(D2 const & a, D2 const & b) { + BOOST_CONCEPT_ASSERT((ScalableConcept)); + BOOST_CONCEPT_ASSERT((MultiplicableConcept)); + + return a[1] * b[0] - a[0] * b[1]; +} + + +//equivalent to cw/ccw, for use in situations where rotation direction doesn't matter. +template +inline D2 +rot90(D2 const & a) { + BOOST_CONCEPT_ASSERT((ScalableConcept)); + return D2(-a[Y], a[X]); +} + +//TODO: concepterize the following functions +template +inline D2 +compose(D2 const & a, T const & b) { + D2 r; + for(unsigned i = 0; i < 2; i++) + r[i] = compose(a[i],b); + return r; +} + +template +inline D2 +compose_each(D2 const & a, D2 const & b) { + D2 r; + for(unsigned i = 0; i < 2; i++) + r[i] = compose(a[i],b[i]); + return r; +} + +template +inline D2 +compose_each(T const & a, D2 const & b) { + D2 r; + for(unsigned i = 0; i < 2; i++) + r[i] = compose(a,b[i]); + return r; +} + + +template +inline Point +D2::operator()(double t) const { + Point p; + for(unsigned i = 0; i < 2; i++) + p[i] = (*this)[i](t); + return p; +} + +//TODO: we might want to have this take a Point as the parameter. +template +inline Point +D2::operator()(double x, double y) const { + Point p; + for(unsigned i = 0; i < 2; i++) + p[i] = (*this)[i](x, y); + return p; +} + + +template +D2 derivative(D2 const & a) { + return D2(derivative(a[X]), derivative(a[Y])); +} +template +D2 integral(D2 const & a) { + return D2(integral(a[X]), integral(a[Y])); +} + +/** A function to print out the Point. It just prints out the coords + on the given output stream */ +template +inline std::ostream &operator<< (std::ostream &out_file, const Geom::D2 &in_d2) { + out_file << "X: " << in_d2[X] << " Y: " << in_d2[Y]; + return out_file; +} + +//Some D2 Fragment implementation which requires rect: +template +OptRect bounds_fast(const D2 &a) { + BOOST_CONCEPT_ASSERT((FragmentConcept)); + return OptRect(bounds_fast(a[X]), bounds_fast(a[Y])); +} +template +OptRect bounds_exact(const D2 &a) { + BOOST_CONCEPT_ASSERT((FragmentConcept)); + return OptRect(bounds_exact(a[X]), bounds_exact(a[Y])); +} +template +OptRect bounds_local(const D2 &a, const OptInterval &t) { + BOOST_CONCEPT_ASSERT((FragmentConcept)); + return OptRect(bounds_local(a[X], t), bounds_local(a[Y], t)); +} + + + +// SBasis-specific declarations + +inline D2 compose(D2 const & a, SBasis const & b) { + return D2(compose(a[X], b), compose(a[Y], b)); +} + +SBasis L2(D2 const & a, unsigned k); +double L2(D2 const & a); + +D2 multiply(Linear const & a, D2 const & b); +inline D2 operator*(Linear const & a, D2 const & b) { return multiply(a, b); } +D2 multiply(SBasis const & a, D2 const & b); +inline D2 operator*(SBasis const & a, D2 const & b) { return multiply(a, b); } +D2 truncate(D2 const & a, unsigned terms); + +unsigned sbasis_size(D2 const & a); +double tail_error(D2 const & a, unsigned tail); + +//Piecewise > specific declarations + +Piecewise > sectionize(D2 > const &a); +D2 > make_cuts_independent(Piecewise > const &a); +Piecewise > rot90(Piecewise > const &a); +Piecewise dot(Piecewise > const &a, Piecewise > const &b); +Piecewise dot(Piecewise > const &a, Point const &b); +Piecewise cross(Piecewise > const &a, Piecewise > const &b); + +Piecewise > operator*(Piecewise > const &a, Affine const &m); + +Piecewise > force_continuity(Piecewise > const &f, double tol=0, bool closed=false); + +std::vector > > fuse_nearby_ends(std::vector > > const &f, double tol=0); + +std::vector > > split_at_discontinuities (Geom::Piecewise > const & pwsbin, double tol = .0001); + +Point unitTangentAt(D2 const & a, Coord t, unsigned n = 3); + +//bounds specializations with order +inline OptRect bounds_fast(D2 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 OptRect bounds_local(D2 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; +} + +std::vector level_set( D2 const &f, Rect region); +std::vector level_set( D2 const &f, Point p, double tol); +std::vector > level_sets( D2 const &f, std::vector regions); +std::vector > level_sets( D2 const &f, std::vector pts, double tol); + + +} // 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:fileencoding=utf-8:textwidth=99 : -- cgit v1.2.3