GCC Code Coverage Report


Directory: ./
File: src/2geom/piecewise.cpp
Date: 2024-03-18 17:01:34
Exec Total Coverage
Lines: 38 147 25.9%
Functions: 3 12 25.0%
Branches: 33 284 11.6%

Line Branch Exec Source
1 /*
2 * piecewise.cpp - Piecewise function class
3 *
4 * Copyright 2007 Michael Sloan <mgsloan@gmail.com>
5 * Copyright 2007 JF Barraud
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it either under the terms of the GNU Lesser General Public
9 * License version 2.1 as published by the Free Software Foundation
10 * (the "LGPL") or, at your option, under the terms of the Mozilla
11 * Public License Version 1.1 (the "MPL"). If you do not alter this
12 * notice, a recipient may use your version of this file under either
13 * the MPL or the LGPL.
14 *
15 * You should have received a copy of the LGPL along with this library
16 * in the file COPYING-LGPL-2.1; if not, output to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * You should have received a copy of the MPL along with this library
19 * in the file COPYING-MPL-1.1
20 *
21 * The contents of this file are subject to the Mozilla Public License
22 * Version 1.1 (the "License"); you may not use this file except in
23 * compliance with the License. You may obtain a copy of the License at
24 * http://www.mozilla.org/MPL/
25 *
26 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28 * the specific language governing rights and limitations.
29 *
30 */
31
32 #include <2geom/piecewise.h>
33 #include <iterator>
34 #include <map>
35
36 namespace Geom {
37
38 Piecewise<SBasis> divide(Piecewise<SBasis> const &a, Piecewise<SBasis> const &b, unsigned k) {
39 Piecewise<SBasis> pa = partition(a, b.cuts), pb = partition(b, a.cuts);
40 Piecewise<SBasis> ret = Piecewise<SBasis>();
41 assert(pa.size() == pb.size());
42 ret.cuts = pa.cuts;
43 for (unsigned i = 0; i < pa.size(); i++)
44 ret.push_seg(divide(pa[i], pb[i], k));
45 return ret;
46 }
47
48 Piecewise<SBasis>
49 divide(Piecewise<SBasis> const &a, Piecewise<SBasis> const &b, double tol, unsigned k, double zero) {
50 Piecewise<SBasis> pa = partition(a, b.cuts), pb = partition(b, a.cuts);
51 Piecewise<SBasis> ret = Piecewise<SBasis>();
52 assert(pa.size() == pb.size());
53 for (unsigned i = 0; i < pa.size(); i++){
54 Piecewise<SBasis> divi = divide(pa[i], pb[i], tol, k, zero);
55 divi.setDomain(Interval(pa.cuts[i],pa.cuts[i+1]));
56 ret.concat(divi);
57 }
58 return ret;
59 }
60 Piecewise<SBasis> divide(Piecewise<SBasis> const &a, SBasis const &b, double tol, unsigned k, double zero){
61 return divide(a,Piecewise<SBasis>(b),tol,k,zero);
62 }
63 Piecewise<SBasis> divide(SBasis const &a, Piecewise<SBasis> const &b, double tol, unsigned k, double zero){
64 return divide(Piecewise<SBasis>(a),b,tol,k,zero);
65 }
66 Piecewise<SBasis> divide(SBasis const &a, SBasis const &b, double tol, unsigned k, double zero) {
67 if (b.tailError(0)<2*zero){
68 //TODO: have a better look at sgn(b).
69 double sgn= (b(.5)<0.)?-1.:1;
70 return Piecewise<SBasis>(Linear(sgn/zero)*a);
71 }
72
73 if (fabs(b.at0())>zero && fabs(b.at1())>zero ){
74 SBasis c,r=a;
75 //TODO: what is a good relative tol? atm, c=a/b +/- (tol/a)%...
76
77 k+=1;
78 r.resize(k, Linear(0,0));
79 c.resize(k, Linear(0,0));
80
81 //assert(b.at0()!=0 && b.at1()!=0);
82 for (unsigned i=0; i<k; i++){
83 Linear ci = Linear(r[i][0]/b[0][0],r[i][1]/b[0][1]);
84 c[i]=ci;
85 r-=shift(ci*b,i);
86 }
87
88 if (r.tailError(k)<tol) return Piecewise<SBasis>(c);
89 }
90
91 Piecewise<SBasis> c0,c1;
92 c0 = divide(compose(a,Linear(0.,.5)),compose(b,Linear(0.,.5)),tol,k);
93 c1 = divide(compose(a,Linear(.5,1.)),compose(b,Linear(.5,1.)),tol,k);
94 c0.setDomain(Interval(0.,.5));
95 c1.setDomain(Interval(.5,1.));
96 c0.concat(c1);
97 return c0;
98 }
99
100
101 //-- compose(pw<T>,SBasis) ---------------
102 /*
103 the purpose of the following functions is only to reduce the code in piecewise.h
104 TODO: use a vector<pairs<double,unsigned> > instead of a map<double,unsigned>.
105 */
106
107 24000 std::map<double,unsigned> compose_pullback(std::vector<double> const &values, SBasis const &g){
108 24000 std::map<double,unsigned> result;
109
110
1/2
✓ Branch 2 taken 24000 times.
✗ Branch 3 not taken.
24000 std::vector<std::vector<double> > roots = multi_roots(g, values);
111
2/2
✓ Branch 1 taken 912000 times.
✓ Branch 2 taken 24000 times.
936000 for(unsigned i=0; i<roots.size(); i++){
112
2/2
✓ Branch 2 taken 18000 times.
✓ Branch 3 taken 912000 times.
930000 for(unsigned j=0; j<roots[i].size();j++){
113
1/2
✓ Branch 3 taken 18000 times.
✗ Branch 4 not taken.
18000 result[roots[i][j]]=i;
114 }
115 }
116 // Also map 0 and 1 to the first value above(or =) g(0) and g(1).
117
2/4
✓ Branch 2 taken 24000 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 24000 times.
✗ Branch 6 not taken.
24000 if(result.count(0.)==0){
118 24000 unsigned i=0;
119
5/6
✓ Branch 1 taken 781800 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 757800 times.
✓ Branch 6 taken 24000 times.
✓ Branch 7 taken 757800 times.
✓ Branch 8 taken 24000 times.
781800 while (i<values.size()&&(g.at0()>values[i])) i++;
120
1/2
✓ Branch 2 taken 24000 times.
✗ Branch 3 not taken.
24000 result[0.]=i;
121 }
122
2/4
✓ Branch 2 taken 24000 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 24000 times.
✗ Branch 6 not taken.
24000 if(result.count(1.)==0){
123 24000 unsigned i=0;
124
5/6
✓ Branch 1 taken 780000 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 756000 times.
✓ Branch 6 taken 24000 times.
✓ Branch 7 taken 756000 times.
✓ Branch 8 taken 24000 times.
780000 while (i<values.size()&&(g.at1()>values[i])) i++;
125
1/2
✓ Branch 2 taken 24000 times.
✗ Branch 3 not taken.
24000 result[1.]=i;
126 }
127 48000 return(result);
128 24000 }
129
130 42000 int compose_findSegIdx(std::map<double,unsigned>::iterator const &cut,
131 std::map<double,unsigned>::iterator const &next,
132 std::vector<double> const &levels,
133 SBasis const &g){
134 42000 double t0=(*cut).first;
135 42000 unsigned idx0=(*cut).second;
136 42000 double t1=(*next).first;
137 42000 unsigned idx1=(*next).second;
138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42000 times.
42000 assert(t0<t1);
139 int idx; //idx of the relevant f.segs
140
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 42000 times.
42000 if (std::max(idx0,idx1)==levels.size()){ //g([t0,t1]) is above the top level,
141 idx=levels.size()-1;
142
2/2
✓ Branch 0 taken 13800 times.
✓ Branch 1 taken 28200 times.
42000 } else if (idx0 != idx1){ //g([t0,t1]) crosses from level idx0 to idx1,
143 13800 idx=std::min(idx0,idx1);
144
2/2
✓ Branch 2 taken 27000 times.
✓ Branch 3 taken 1200 times.
28200 } else if(g((t0+t1)/2) < levels[idx0]) { //g([t0,t1]) is a 'U' under level idx0,
145 27000 idx=idx0-1;
146
1/2
✓ Branch 2 taken 1200 times.
✗ Branch 3 not taken.
1200 } else if(g((t0+t1)/2) > levels[idx0]) { //g([t0,t1]) is a 'bump' over level idx0,
147 1200 idx=idx0;
148 } else { //g([t0,t1]) is contained in level idx0!...
149 idx = (idx0==levels.size())? idx0-1:idx0;
150 }
151
152 //move idx back from levels f.cuts
153 42000 idx+=1;
154 42000 return idx;
155 }
156
157
158 Piecewise<SBasis> pw_compose_inverse(SBasis const &f, SBasis const &g, unsigned order, double zero){
159 Piecewise<SBasis> result;
160
161 assert( f.size()>0 && g.size()>0);
162 SBasis g01 = g;
163 bool flip = ( g01.at0() > g01.at1() );
164
165 //OptInterval g_range = bounds_exact(g);
166 OptInterval g_range( Interval( g.at0(), g.at1() ));
167
168 g01 -= g_range->min();
169 g01 /= g_range->extent();
170 if ( flip ){
171 g01 *= -1.;
172 g01 += 1.;
173 }
174 #if 1
175 assert( std::abs( g01.at0() - 0. ) < zero );
176 assert( std::abs( g01.at1() - 1. ) < zero );
177 //g[0][0] = 0.;
178 //g[0][1] = 1.;
179 #endif
180
181 SBasis foginv = compose_inverse( f, g01, order, zero );
182 SBasis err = compose( foginv, g01) - f;
183
184 if ( err.tailError(0) < zero ){
185 result = Piecewise<SBasis> (foginv);
186 }else{
187 SBasis g_portion = portion( g01, Interval(0.,.5) );
188 SBasis f_portion = portion( f, Interval(0.,.5) );
189 result = pw_compose_inverse(f_portion, g_portion, order, zero);
190
191 g_portion = portion( g01, Interval(.5, 1.) );
192 f_portion = portion( f, Interval(.5, 1.) );
193 Piecewise<SBasis> result_next;
194 result_next = pw_compose_inverse(f_portion, g_portion, order, zero);
195 result.concat( result_next );
196 }
197 if (flip) {
198 result = reverse(result);
199 }
200 result.setDomain(*g_range);
201 return result;
202 }
203
204
205 9600 std::vector<double> roots(Piecewise<SBasis> const &f){
206 9600 std::vector<double> result;
207
2/2
✓ Branch 1 taken 9600 times.
✓ Branch 2 taken 9600 times.
19200 for (unsigned i=0; i<f.size(); i++){
208
1/2
✓ Branch 3 taken 9600 times.
✗ Branch 4 not taken.
9600 std::vector<double> rts=roots(f.segs[i]);
209
210
1/2
✗ Branch 7 not taken.
✓ Branch 8 taken 9600 times.
9600 for (double rt : rts){
211 result.push_back(f.mapToDomain(rt, i));
212 }
213 9600 }
214 9600 return result;
215 }
216
217 std::vector<std::vector<double> > multi_roots(Piecewise<SBasis> const &f, std::vector<double> const &values) {
218 std::vector<std::vector<double> > result(values.size());
219 for (unsigned i=0; i<f.size(); i++) {
220 std::vector<std::vector<double> > rts = multi_roots(f.segs[i], values);
221 for(unsigned j=0; j<rts.size(); j++) {
222 for(unsigned r=0; r<rts[j].size(); r++){
223 result[j].push_back(f.mapToDomain(rts[j][r], i));
224 }
225 }
226 }
227 return result;
228 }
229
230
231 std::vector<Interval> level_set(Piecewise<SBasis> const &f, Interval const &level, double tol){
232 std::vector<Interval> result;
233 for (unsigned i=0; i<f.size(); i++){
234 std::vector<Interval> resulti = level_set( f[i], level, 0., 1., tol);
235 for (unsigned j=0; j<resulti.size(); j++){
236 double a = f.cuts[i] + resulti[j].min() * ( f.cuts[i+1] - f.cuts[i] );
237 double b = f.cuts[i] + resulti[j].max() * ( f.cuts[i+1] - f.cuts[i] );
238 Interval domj( a, b );
239 //Interval domj( f.mapToDomain(resulti[j].min(), i ), f.mapToDomain(resulti[j].max(), i ) );
240
241 if ( j==0 && !result.empty() && result.back().intersects(domj) ){
242 result.back().unionWith(domj);
243 }else{
244 result.push_back(domj);
245 }
246 }
247 }
248 return result;
249 }
250 std::vector<Interval> level_set(Piecewise<SBasis> const &f, double v, double vtol, double tol){
251 Interval level ( v-vtol, v+vtol );
252 return level_set( f, level, tol);
253 }
254
255
256 }
257 /*
258 Local Variables:
259 mode:c++
260 c-file-style:"stroustrup"
261 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
262 indent-tabs-mode:nil
263 fill-column:99
264 End:
265 */
266 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
267