/** * \file * \brief Some two-dimensional SBasis operations *//* * Authors: * MenTaLguy * Jean-François Barraud * Johan Engelen * * Copyright 2007-2012 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. * */ #include <2geom/d2.h> #include <2geom/piecewise.h> namespace Geom { SBasis L2(D2 const & a, unsigned k) { return sqrt(dot(a, a), k); } D2 multiply(Linear const & a, D2 const & b) { return D2(multiply(a, b[X]), multiply(a, b[Y])); } D2 multiply(SBasis const & a, D2 const & b) { return D2(multiply(a, b[X]), multiply(a, b[Y])); } D2 truncate(D2 const & a, unsigned terms) { return D2(truncate(a[X], terms), truncate(a[Y], terms)); } unsigned sbasis_size(D2 const & a) { return std::max((unsigned) a[0].size(), (unsigned) a[1].size()); } //TODO: Is this sensical? shouldn't it be like pythagorean or something? double tail_error(D2 const & a, unsigned tail) { return std::max(a[0].tailError(tail), a[1].tailError(tail)); } Piecewise > sectionize(D2 > const &a) { Piecewise x = partition(a[0], a[1].cuts), y = partition(a[1], a[0].cuts); assert(x.size() == y.size()); Piecewise > ret; for(unsigned i = 0; i < x.size(); i++) ret.push_seg(D2(x[i], y[i])); ret.cuts.insert(ret.cuts.end(), x.cuts.begin(), x.cuts.end()); return ret; } D2 > make_cuts_independent(Piecewise > const &a) { D2 > ret; for(unsigned d = 0; d < 2; d++) { for(unsigned i = 0; i < a.size(); i++) ret[d].push_seg(a[i][d]); ret[d].cuts.insert(ret[d].cuts.end(), a.cuts.begin(), a.cuts.end()); } return ret; } Piecewise > rot90(Piecewise > const &M){ Piecewise > result; if (M.empty()) return M; result.push_cut(M.cuts[0]); for (unsigned i=0; i dot(Piecewise > const &a, Piecewise > const &b) { Piecewise result; if (a.empty() || b.empty()) return result; Piecewise > aa = partition(a,b.cuts); Piecewise > bb = partition(b,a.cuts); result.push_cut(aa.cuts.front()); for (unsigned i=0; i dot(Piecewise > const &a, Point const &b) { Piecewise 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 cross(Piecewise > const &a, Piecewise > const &b){ Piecewise result; if (a.empty() || b.empty()) return result; Piecewise > aa = partition(a,b.cuts); Piecewise > bb = partition(b,a.cuts); result.push_cut(aa.cuts.front()); for (unsigned i=0; i > operator*(Piecewise > const &a, Affine const &m) { Piecewise > result; if(a.empty()) return result; result.push_cut(a.cuts[0]); for (unsigned i = 0; i < a.size(); i++) { result.push(a[i] * m, a.cuts[i+1]); } return result; } //if tol>0, only force continuity where the jump is smaller than tol. Piecewise > force_continuity(Piecewise > const &f, double tol, bool closed) { if (f.size()==0) return f; Piecewise > result=f; unsigned cur = (closed)? 0:1; unsigned prev = (closed)? f.size()-1:0; while(cur > > split_at_discontinuities (Geom::Piecewise > const & pwsbin, double tol) { using namespace Geom; std::vector > > ret; unsigned piece_start = 0; for (unsigned i=0; i tol){ Piecewise > piece; piece.cuts.push_back(pwsbin.cuts[piece_start]); for (unsigned j = piece_start; j const & a, Coord t, unsigned n) { std::vector derivs = a.valueAndDerivatives(t, n); for (unsigned deriv_n = 1; deriv_n < derivs.size(); deriv_n++) { Coord length = derivs[deriv_n].length(); if ( ! are_near(length, 0) ) { // length of derivative is non-zero, so return unit vector return derivs[deriv_n] / length; } } return Point (0,0); } static void set_first_point(Piecewise > &f, Point const &a){ if ( f.empty() ){ f.concat(Piecewise >(D2(SBasis(Linear(a[X])), SBasis(Linear(a[Y]))))); return; } for (unsigned dim=0; dim<2; dim++){ f.segs.front()[dim][0][0] = a[dim]; } } static void set_last_point(Piecewise > &f, Point const &a){ if ( f.empty() ){ f.concat(Piecewise >(D2(SBasis(Linear(a[X])), SBasis(Linear(a[Y]))))); return; } for (unsigned dim=0; dim<2; dim++){ f.segs.back()[dim][0][1] = a[dim]; } } std::vector > > fuse_nearby_ends(std::vector > > const &f, double tol){ if ( f.empty()) return f; std::vector > > result; std::vector > pre_result; for (unsigned i=0; i > comp; for (unsigned j=0; j > new_comp = f.at(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; } /* * Computes the intersection of two sets given as (ordered) union of intervals. */ static std::vector intersect( std::vector const &a, std::vector const &b){ std::vector result; //TODO: use order! for (auto i : a){ for (auto j : b){ OptInterval c( i ); c &= j; if ( c ) { result.push_back( *c ); } } } return result; } std::vector level_set( D2 const &f, Rect region){ std::vector regions( 1, region ); return level_sets( f, regions ).front(); } std::vector level_set( D2 const &f, Point p, double tol){ Rect region(p, p); region.expandBy( tol ); return level_set( f, region ); } std::vector > level_sets( D2 const &f, std::vector regions){ std::vector regsX (regions.size(), Interval() ); std::vector regsY (regions.size(), Interval() ); for ( unsigned i=0; i < regions.size(); i++ ){ regsX[i] = regions[i][X]; regsY[i] = regions[i][Y]; } std::vector > x_in_regs = level_sets( f[X], regsX ); std::vector > y_in_regs = level_sets( f[Y], regsY ); std::vector >result(regions.size(), std::vector() ); for (unsigned i=0; i > level_sets( D2 const &f, std::vector pts, double tol){ std::vector regions( pts.size(), Rect() ); for (unsigned i=0; i