1 /*
2 * sbasis.cpp - S-power basis function class + supporting classes
3 *
4 * Authors:
5 * Nathan Hurst <njh@mail.csse.monash.edu.au>
6 * Michael Sloan <mgsloan@gmail.com>
7 *
8 * Copyright (C) 2006-2007 authors
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it either under the terms of the GNU Lesser General Public
12 * License version 2.1 as published by the Free Software Foundation
13 * (the "LGPL") or, at your option, under the terms of the Mozilla
14 * Public License Version 1.1 (the "MPL"). If you do not alter this
15 * notice, a recipient may use your version of this file under either
16 * the MPL or the LGPL.
17 *
18 * You should have received a copy of the LGPL along with this library
19 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * You should have received a copy of the MPL along with this library
22 * in the file COPYING-MPL-1.1
23 *
24 * The contents of this file are subject to the Mozilla Public License
25 * Version 1.1 (the "License"); you may not use this file except in
26 * compliance with the License. You may obtain a copy of the License at
27 * http://www.mozilla.org/MPL/
28 *
29 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
30 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
31 * the specific language governing rights and limitations.
32 */
33
34 #include <cmath>
35
36 #include <2geom/sbasis.h>
37 #include <2geom/math-utils.h>
38
39 namespace Geom {
40
41 #ifndef M_PI
42 # define M_PI 3.14159265358979323846
43 #endif
44
45 /** bound the error from term truncation
46 \param tail first term to chop
47 \returns the largest possible error this truncation could give
48 */
tailError(unsigned tail) const49 double SBasis::tailError(unsigned tail) const {
50 Interval bs = *bounds_fast(*this, tail);
51 return std::max(fabs(bs.min()),fabs(bs.max()));
52 }
53
54 /** test all coefficients are finite
55 */
isFinite() const56 bool SBasis::isFinite() const {
57 for(unsigned i = 0; i < size(); i++) {
58 if(!(*this)[i].isFinite())
59 return false;
60 }
61 return true;
62 }
63
64 /** Compute the value and the first n derivatives
65 \param t position to evaluate
66 \param n number of derivatives (not counting value)
67 \returns a vector with the value and the n derivative evaluations
68
69 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.
70 */
valueAndDerivatives(double t,unsigned n) const71 std::vector<double> SBasis::valueAndDerivatives(double t, unsigned n) const {
72 std::vector<double> ret(n+1);
73 ret[0] = valueAt(t);
74 SBasis tmp = *this;
75 for(unsigned i = 1; i < n+1; i++) {
76 tmp.derive();
77 ret[i] = tmp.valueAt(t);
78 }
79 return ret;
80 }
81
82
83 /** Compute the pointwise sum of a and b (Exact)
84 \param a,b sbasis functions
85 \returns sbasis equal to a+b
86
87 */
operator +(const SBasis & a,const SBasis & b)88 SBasis operator+(const SBasis& a, const SBasis& b) {
89 const unsigned out_size = std::max(a.size(), b.size());
90 const unsigned min_size = std::min(a.size(), b.size());
91 SBasis result(out_size, Linear());
92
93 for(unsigned i = 0; i < min_size; i++) {
94 result[i] = a[i] + b[i];
95 }
96 for(unsigned i = min_size; i < a.size(); i++)
97 result[i] = a[i];
98 for(unsigned i = min_size; i < b.size(); i++)
99 result[i] = b[i];
100
101 assert(result.size() == out_size);
102 return result;
103 }
104
105 /** Compute the pointwise difference of a and b (Exact)
106 \param a,b sbasis functions
107 \returns sbasis equal to a-b
108
109 */
operator -(const SBasis & a,const SBasis & b)110 SBasis operator-(const SBasis& a, const SBasis& b) {
111 const unsigned out_size = std::max(a.size(), b.size());
112 const unsigned min_size = std::min(a.size(), b.size());
113 SBasis result(out_size, Linear());
114
115 for(unsigned i = 0; i < min_size; i++) {
116 result[i] = a[i] - b[i];
117 }
118 for(unsigned i = min_size; i < a.size(); i++)
119 result[i] = a[i];
120 for(unsigned i = min_size; i < b.size(); i++)
121 result[i] = -b[i];
122
123 assert(result.size() == out_size);
124 return result;
125 }
126
127 /** Compute the pointwise sum of a and b and store in a (Exact)
128 \param a,b sbasis functions
129 \returns sbasis equal to a+b
130
131 */
operator +=(SBasis & a,const SBasis & b)132 SBasis& operator+=(SBasis& a, const SBasis& b) {
133 const unsigned out_size = std::max(a.size(), b.size());
134 const unsigned min_size = std::min(a.size(), b.size());
135 a.resize(out_size);
136
137 for(unsigned i = 0; i < min_size; i++)
138 a[i] += b[i];
139 for(unsigned i = min_size; i < b.size(); i++)
140 a[i] = b[i];
141
142 assert(a.size() == out_size);
143 return a;
144 }
145
146 /** Compute the pointwise difference of a and b and store in a (Exact)
147 \param a,b sbasis functions
148 \returns sbasis equal to a-b
149
150 */
operator -=(SBasis & a,const SBasis & b)151 SBasis& operator-=(SBasis& a, const SBasis& b) {
152 const unsigned out_size = std::max(a.size(), b.size());
153 const unsigned min_size = std::min(a.size(), b.size());
154 a.resize(out_size);
155
156 for(unsigned i = 0; i < min_size; i++)
157 a[i] -= b[i];
158 for(unsigned i = min_size; i < b.size(); i++)
159 a[i] = -b[i];
160
161 assert(a.size() == out_size);
162 return a;
163 }
164
165 /** Compute the pointwise product of a and b (Exact)
166 \param a,b sbasis functions
167 \returns sbasis equal to a*b
168
169 */
operator *(SBasis const & a,double k)170 SBasis operator*(SBasis const &a, double k) {
171 SBasis c(a.size(), Linear());
172 for(unsigned i = 0; i < a.size(); i++)
173 c[i] = a[i] * k;
174 return c;
175 }
176
177 /** Compute the pointwise product of a and b and store the value in a (Exact)
178 \param a,b sbasis functions
179 \returns sbasis equal to a*b
180
181 */
operator *=(SBasis & a,double b)182 SBasis& operator*=(SBasis& a, double b) {
183 if (a.isZero()) return a;
184 if (b == 0)
185 a.clear();
186 else
187 for(auto & i : a)
188 i *= b;
189 return a;
190 }
191
192 /** multiply a by x^sh in place (Exact)
193 \param a sbasis function
194 \param sh power
195 \returns a
196
197 */
shift(SBasis const & a,int sh)198 SBasis shift(SBasis const &a, int sh) {
199 size_t n = a.size()+sh;
200 SBasis c(n, Linear());
201 size_t m = std::max(0, sh);
202
203 for(int i = 0; i < sh; i++)
204 c[i] = Linear(0,0);
205 for(size_t i = m, j = std::max(0,-sh); i < n; i++, j++)
206 c[i] = a[j];
207 return c;
208 }
209
210 /** multiply a by x^sh (Exact)
211 \param a linear function
212 \param sh power
213 \returns a* x^sh
214
215 */
shift(Linear const & a,int sh)216 SBasis shift(Linear const &a, int sh) {
217 size_t n = 1+sh;
218 SBasis c(n, Linear());
219
220 for(int i = 0; i < sh; i++)
221 c[i] = Linear(0,0);
222 if(sh >= 0)
223 c[sh] = a;
224 return c;
225 }
226
227 #if 0
228 SBasis multiply(SBasis const &a, SBasis const &b) {
229 // c = {a0*b0 - shift(1, a.Tri*b.Tri), a1*b1 - shift(1, a.Tri*b.Tri)}
230
231 // shift(1, a.Tri*b.Tri)
232 SBasis c(a.size() + b.size(), Linear(0,0));
233 if(a.isZero() || b.isZero())
234 return c;
235 for(unsigned j = 0; j < b.size(); j++) {
236 for(unsigned i = j; i < a.size()+j; i++) {
237 double tri = b[j].tri()*a[i-j].tri();
238 c[i+1/*shift*/] += Linear(-tri);
239 }
240 }
241 for(unsigned j = 0; j < b.size(); j++) {
242 for(unsigned i = j; i < a.size()+j; i++) {
243 for(unsigned dim = 0; dim < 2; dim++)
244 c[i][dim] += b[j][dim]*a[i-j][dim];
245 }
246 }
247 c.normalize();
248 //assert(!(0 == c.back()[0] && 0 == c.back()[1]));
249 return c;
250 }
251 #else
252
253 /** Compute the pointwise product of a and b adding c (Exact)
254 \param a,b,c sbasis functions
255 \returns sbasis equal to a*b+c
256
257 The added term is almost free
258 */
multiply_add(SBasis const & a,SBasis const & b,SBasis c)259 SBasis multiply_add(SBasis const &a, SBasis const &b, SBasis c) {
260 if(a.isZero() || b.isZero())
261 return c;
262 c.resize(a.size() + b.size(), Linear(0,0));
263 for(unsigned j = 0; j < b.size(); j++) {
264 for(unsigned i = j; i < a.size()+j; i++) {
265 double tri = b[j].tri()*a[i-j].tri();
266 c[i+1/*shift*/] += Linear(-tri);
267 }
268 }
269 for(unsigned j = 0; j < b.size(); j++) {
270 for(unsigned i = j; i < a.size()+j; i++) {
271 for(unsigned dim = 0; dim < 2; dim++)
272 c[i][dim] += b[j][dim]*a[i-j][dim];
273 }
274 }
275 c.normalize();
276 //assert(!(0 == c.back()[0] && 0 == c.back()[1]));
277 return c;
278 }
279
280 /** Compute the pointwise product of a and b (Exact)
281 \param a,b sbasis functions
282 \returns sbasis equal to a*b
283
284 */
multiply(SBasis const & a,SBasis const & b)285 SBasis multiply(SBasis const &a, SBasis const &b) {
286 if(a.isZero() || b.isZero()) {
287 SBasis c(1, Linear(0,0));
288 return c;
289 }
290 SBasis c(a.size() + b.size(), Linear(0,0));
291 return multiply_add(a, b, c);
292 }
293 #endif
294 /** Compute the integral of a (Exact)
295 \param a sbasis functions
296 \returns sbasis integral(a)
297
298 */
integral(SBasis const & c)299 SBasis integral(SBasis const &c) {
300 SBasis a;
301 a.resize(c.size() + 1, Linear(0,0));
302 a[0] = Linear(0,0);
303
304 for(unsigned k = 1; k < c.size() + 1; k++) {
305 double ahat = -c[k-1].tri()/(2*k);
306 a[k][0] = a[k][1] = ahat;
307 }
308 double aTri = 0;
309 for(int k = c.size()-1; k >= 0; k--) {
310 aTri = (c[k].hat() + (k+1)*aTri/2)/(2*k+1);
311 a[k][0] -= aTri/2;
312 a[k][1] += aTri/2;
313 }
314 a.normalize();
315 return a;
316 }
317
318 /** Compute the derivative of a (Exact)
319 \param a sbasis functions
320 \returns sbasis da/dt
321
322 */
derivative(SBasis const & a)323 SBasis derivative(SBasis const &a) {
324 SBasis c;
325 c.resize(a.size(), Linear(0,0));
326 if(a.isZero())
327 return c;
328
329 for(unsigned k = 0; k < a.size()-1; k++) {
330 double d = (2*k+1)*(a[k][1] - a[k][0]);
331
332 c[k][0] = d + (k+1)*a[k+1][0];
333 c[k][1] = d - (k+1)*a[k+1][1];
334 }
335 int k = a.size()-1;
336 double d = (2*k+1)*(a[k][1] - a[k][0]);
337 if (d == 0 && k > 0) {
338 c.pop_back();
339 } else {
340 c[k][0] = d;
341 c[k][1] = d;
342 }
343
344 return c;
345 }
346
347 /** Compute the derivative of this inplace (Exact)
348
349 */
derive()350 void SBasis::derive() { // in place version
351 if(isZero()) return;
352 for(unsigned k = 0; k < size()-1; k++) {
353 double d = (2*k+1)*((*this)[k][1] - (*this)[k][0]);
354
355 (*this)[k][0] = d + (k+1)*(*this)[k+1][0];
356 (*this)[k][1] = d - (k+1)*(*this)[k+1][1];
357 }
358 int k = size()-1;
359 double d = (2*k+1)*((*this)[k][1] - (*this)[k][0]);
360 if (d == 0 && k > 0) {
361 pop_back();
362 } else {
363 (*this)[k][0] = d;
364 (*this)[k][1] = d;
365 }
366 }
367
368 /** Compute the sqrt of a
369 \param a sbasis functions
370 \returns sbasis \f[ \sqrt{a} \f]
371
372 It is recommended to use the piecewise version unless you have good reason.
373 TODO: convert int k to unsigned k, and remove cast
374 */
sqrt(SBasis const & a,int k)375 SBasis sqrt(SBasis const &a, int k) {
376 SBasis c;
377 if(a.isZero() || k == 0)
378 return c;
379 c.resize(k, Linear(0,0));
380 c[0] = Linear(std::sqrt(a[0][0]), std::sqrt(a[0][1]));
381 SBasis r = a - multiply(c, c); // remainder
382
383 for(unsigned i = 1; i <= (unsigned)k && i<r.size(); i++) {
384 Linear ci(r[i][0]/(2*c[0][0]), r[i][1]/(2*c[0][1]));
385 SBasis cisi = shift(ci, i);
386 r -= multiply(shift((c*2 + cisi), i), SBasis(ci));
387 r.truncate(k+1);
388 c += cisi;
389 if(r.tailError(i) == 0) // if exact
390 break;
391 }
392
393 return c;
394 }
395
396 /** Compute the recpirocal of a
397 \param a sbasis functions
398 \returns sbasis 1/a
399
400 It is recommended to use the piecewise version unless you have good reason.
401 */
reciprocal(Linear const & a,int k)402 SBasis reciprocal(Linear const &a, int k) {
403 SBasis c;
404 assert(!a.isZero());
405 c.resize(k, Linear(0,0));
406 double r_s0 = (a.tri()*a.tri())/(-a[0]*a[1]);
407 double r_s0k = 1;
408 for(unsigned i = 0; i < (unsigned)k; i++) {
409 c[i] = Linear(r_s0k/a[0], r_s0k/a[1]);
410 r_s0k *= r_s0;
411 }
412 return c;
413 }
414
415 /** Compute a / b to k terms
416 \param a,b sbasis functions
417 \returns sbasis a/b
418
419 It is recommended to use the piecewise version unless you have good reason.
420 */
divide(SBasis const & a,SBasis const & b,int k)421 SBasis divide(SBasis const &a, SBasis const &b, int k) {
422 SBasis c;
423 assert(!a.isZero());
424 SBasis r = a; // remainder
425
426 k++;
427 r.resize(k, Linear(0,0));
428 c.resize(k, Linear(0,0));
429
430 for(unsigned i = 0; i < (unsigned)k; i++) {
431 Linear ci(r[i][0]/b[0][0], r[i][1]/b[0][1]); //H0
432 c[i] += ci;
433 r -= shift(multiply(ci,b), i);
434 r.truncate(k+1);
435 if(r.tailError(i) == 0) // if exact
436 break;
437 }
438
439 return c;
440 }
441
442 /** Compute a composed with b
443 \param a,b sbasis functions
444 \returns sbasis a(b(t))
445
446 return a0 + s(a1 + s(a2 +... where s = (1-u)u; ak =(1 - u)a^0_k + ua^1_k
447 */
compose(SBasis const & a,SBasis const & b)448 SBasis compose(SBasis const &a, SBasis const &b) {
449 SBasis s = multiply((SBasis(Linear(1,1))-b), b);
450 SBasis r;
451
452 for(int i = a.size()-1; i >= 0; i--) {
453 r = multiply_add(r, s, SBasis(Linear(a[i][0])) - b*a[i][0] + b*a[i][1]);
454 }
455 return r;
456 }
457
458 /** Compute a composed with b to k terms
459 \param a,b sbasis functions
460 \returns sbasis a(b(t))
461
462 return a0 + s(a1 + s(a2 +... where s = (1-u)u; ak =(1 - u)a^0_k + ua^1_k
463 */
compose(SBasis const & a,SBasis const & b,unsigned k)464 SBasis compose(SBasis const &a, SBasis const &b, unsigned k) {
465 SBasis s = multiply((SBasis(Linear(1,1))-b), b);
466 SBasis r;
467
468 for(int i = a.size()-1; i >= 0; i--) {
469 r = multiply_add(r, s, SBasis(Linear(a[i][0])) - b*a[i][0] + b*a[i][1]);
470 }
471 r.truncate(k);
472 return r;
473 }
474
portion(const SBasis & t,double from,double to)475 SBasis portion(const SBasis &t, double from, double to) {
476 double fv = t.valueAt(from);
477 double tv = t.valueAt(to);
478 SBasis ret = compose(t, Linear(from, to));
479 ret.at0() = fv;
480 ret.at1() = tv;
481 return ret;
482 }
483
484 /*
485 Inversion algorithm. The notation is certainly very misleading. The
486 pseudocode should say:
487
488 c(v) := 0
489 r(u) := r_0(u) := u
490 for i:=0 to k do
491 c_i(v) := H_0(r_i(u)/(t_1)^i; u)
492 c(v) := c(v) + c_i(v)*t^i
493 r(u) := r(u) ? c_i(u)*(t(u))^i
494 endfor
495 */
496
497 //#define DEBUG_INVERSION 1
498
499 /** find the function a^-1 such that a^-1 composed with a to k terms is the identity function
500 \param a sbasis function
501 \returns sbasis a^-1 s.t. a^-1(a(t)) = 1
502
503 The function must have 'unit range'("a00 = 0 and a01 = 1") and be monotonic.
504 */
inverse(SBasis a,int k)505 SBasis inverse(SBasis a, int k) {
506 assert(a.size() > 0);
507 double a0 = a[0][0];
508 if(a0 != 0) {
509 a -= a0;
510 }
511 double a1 = a[0][1];
512 assert(a1 != 0); // not invertable.
513
514 if(a1 != 1) {
515 a /= a1;
516 }
517 SBasis c(k, Linear()); // c(v) := 0
518 if(a.size() >= 2 && k == 2) {
519 c[0] = Linear(0,1);
520 Linear t1(1+a[1][0], 1-a[1][1]); // t_1
521 c[1] = Linear(-a[1][0]/t1[0], -a[1][1]/t1[1]);
522 } else if(a.size() >= 2) { // non linear
523 SBasis r = Linear(0,1); // r(u) := r_0(u) := u
524 Linear t1(1./(1+a[1][0]), 1./(1-a[1][1])); // 1./t_1
525 Linear one(1,1);
526 Linear t1i = one; // t_1^0
527 SBasis one_minus_a = SBasis(one) - a;
528 SBasis t = multiply(one_minus_a, a); // t(u)
529 SBasis ti(one); // t(u)^0
530 #ifdef DEBUG_INVERSION
531 std::cout << "a=" << a << std::endl;
532 std::cout << "1-a=" << one_minus_a << std::endl;
533 std::cout << "t1=" << t1 << std::endl;
534 //assert(t1 == t[1]);
535 #endif
536
537 //c.resize(k+1, Linear(0,0));
538 for(unsigned i = 0; i < (unsigned)k; i++) { // for i:=0 to k do
539 #ifdef DEBUG_INVERSION
540 std::cout << "-------" << i << ": ---------" <<std::endl;
541 std::cout << "r=" << r << std::endl
542 << "c=" << c << std::endl
543 << "ti=" << ti << std::endl
544 << std::endl;
545 #endif
546 if(r.size() <= i) // ensure enough space in the remainder, probably not needed
547 r.resize(i+1, Linear(0,0));
548 Linear ci(r[i][0]*t1i[0], r[i][1]*t1i[1]); // c_i(v) := H_0(r_i(u)/(t_1)^i; u)
549 #ifdef DEBUG_INVERSION
550 std::cout << "t1i=" << t1i << std::endl;
551 std::cout << "ci=" << ci << std::endl;
552 #endif
553 for(int dim = 0; dim < 2; dim++) // t1^-i *= 1./t1
554 t1i[dim] *= t1[dim];
555 c[i] = ci; // c(v) := c(v) + c_i(v)*t^i
556 // change from v to u parameterisation
557 SBasis civ = one_minus_a*ci[0] + a*ci[1];
558 // r(u) := r(u) - c_i(u)*(t(u))^i
559 // We can truncate this to the number of final terms, as no following terms can
560 // contribute to the result.
561 r -= multiply(civ,ti);
562 r.truncate(k);
563 if(r.tailError(i) == 0)
564 break; // yay!
565 ti = multiply(ti,t);
566 }
567 #ifdef DEBUG_INVERSION
568 std::cout << "##########################" << std::endl;
569 #endif
570 } else
571 c = Linear(0,1); // linear
572 c -= a0; // invert the offset
573 c /= a1; // invert the slope
574 return c;
575 }
576
577 /** Compute the sine of a to k terms
578 \param b linear function
579 \returns sbasis sin(a)
580
581 It is recommended to use the piecewise version unless you have good reason.
582 */
sin(Linear b,int k)583 SBasis sin(Linear b, int k) {
584 SBasis s(k+2, Linear());
585 s[0] = Linear(std::sin(b[0]), std::sin(b[1]));
586 double tr = s[0].tri();
587 double t2 = b.tri();
588 s[1] = Linear(std::cos(b[0])*t2 - tr, -std::cos(b[1])*t2 + tr);
589
590 t2 *= t2;
591 for(int i = 0; i < k; i++) {
592 Linear bo(4*(i+1)*s[i+1][0] - 2*s[i+1][1],
593 -2*s[i+1][0] + 4*(i+1)*s[i+1][1]);
594 bo -= s[i]*(t2/(i+1));
595
596
597 s[i+2] = bo/double(i+2);
598 }
599
600 return s;
601 }
602
603 /** Compute the cosine of a
604 \param b linear function
605 \returns sbasis cos(a)
606
607 It is recommended to use the piecewise version unless you have good reason.
608 */
cos(Linear bo,int k)609 SBasis cos(Linear bo, int k) {
610 return sin(Linear(bo[0] + M_PI/2,
611 bo[1] + M_PI/2),
612 k);
613 }
614
615 /** compute fog^-1.
616 \param f,g sbasis functions
617 \returns sbasis f(g^-1(t)).
618
619 ("zero" = double comparison threshold. *!*we might divide by "zero"*!*)
620 TODO: compute order according to tol?
621 TODO: requires g(0)=0 & g(1)=1 atm... adaptation to other cases should be obvious!
622 */
compose_inverse(SBasis const & f,SBasis const & g,unsigned order,double zero)623 SBasis compose_inverse(SBasis const &f, SBasis const &g, unsigned order, double zero){
624 SBasis result(order, Linear(0.)); //result
625 SBasis r=f; //remainder
626 SBasis Pk=Linear(1)-g,Qk=g,sg=Pk*Qk;
627 Pk.truncate(order);
628 Qk.truncate(order);
629 Pk.resize(order,Linear(0.));
630 Qk.resize(order,Linear(0.));
631 r.resize(order,Linear(0.));
632
633 int vs = valuation(sg,zero);
634 if (vs == 0) { // to prevent infinite loop
635 return result;
636 }
637
638 for (unsigned k=0; k<order; k+=vs){
639 double p10 = Pk.at(k)[0];// we have to solve the linear system:
640 double p01 = Pk.at(k)[1];//
641 double q10 = Qk.at(k)[0];// p10*a + q10*b = r10
642 double q01 = Qk.at(k)[1];// &
643 double r10 = r.at(k)[0];// p01*a + q01*b = r01
644 double r01 = r.at(k)[1];//
645 double a,b;
646 double det = p10*q01-p01*q10;
647
648 //TODO: handle det~0!!
649 if (fabs(det)<zero){
650 a=b=0;
651 }else{
652 a=( q01*r10-q10*r01)/det;
653 b=(-p01*r10+p10*r01)/det;
654 }
655 result[k] = Linear(a,b);
656 r=r-Pk*a-Qk*b;
657
658 Pk=Pk*sg;
659 Qk=Qk*sg;
660
661 Pk.resize(order,Linear(0.)); // truncates if too high order, expands with zeros if too low
662 Qk.resize(order,Linear(0.));
663 r.resize(order,Linear(0.));
664
665 }
666 result.normalize();
667 return result;
668 }
669
670 }
671
672 /*
673 Local Variables:
674 mode:c++
675 c-file-style:"stroustrup"
676 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
677 indent-tabs-mode:nil
678 fill-column:99
679 End:
680 */
681 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
682