vspline 1.1.0
Generic C++11 Code for Uniform B-Splines
splinus.cc
Go to the documentation of this file.
1/************************************************************************/
2/* */
3/* vspline - a set of generic tools for creation and evaluation */
4/* of uniform b-splines */
5/* */
6/* Copyright 2015 - 2023 by Kay F. Jahnke */
7/* */
8/* Permission is hereby granted, free of charge, to any person */
9/* obtaining a copy of this software and associated documentation */
10/* files (the "Software"), to deal in the Software without */
11/* restriction, including without limitation the rights to use, */
12/* copy, modify, merge, publish, distribute, sublicense, and/or */
13/* sell copies of the Software, and to permit persons to whom the */
14/* Software is furnished to do so, subject to the following */
15/* conditions: */
16/* */
17/* The above copyright notice and this permission notice shall be */
18/* included in all copies or substantial portions of the */
19/* Software. */
20/* */
21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
23/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
24/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
25/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
26/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
27/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
28/* OTHER DEALINGS IN THE SOFTWARE. */
29/* */
30/************************************************************************/
31
32/// \file splinus.cc
33///
34/// \brief compare a periodic b-spline with a sine
35///
36/// This is a simple example using a periodic b-spline
37/// over just two values: 1 and -1. This spline is used to approximate
38/// a sine function. You pass the spline's desired degree on the command
39/// line. Next you enter a number (interpreted as degrees) and the program
40/// will output the sine and the 'splinus' of the given angle.
41/// As you can see when playing with higher degrees, the higher the spline's
42/// degree, the closer the match with the sine. So apart from serving as a
43/// very simple demonstration of using a 1D periodic b-spline, it teaches us
44/// that a periodic b-spline can approximate a sine.
45/// To show off, we use long double as the spline's data type.
46/// This program also shows a bit of functional programming magic, putting
47/// together the 'splinus' functor from several of vspline's functional
48/// bulding blocks.
49///
50/// compile with: clang++ -pthread -O3 -std=c++11 splinus.cc -o splinus
51
52#include <iostream>
53#include <assert.h>
54#include <vspline/vspline.h>
55
56int main ( int argc , char * argv[] )
57{
58 if ( argc < 2 )
59 {
60 std::cerr << "please pass the spline degree on the command line"
61 << std::endl ;
62 exit ( 1 ) ;
63 }
64
65 int degree = std::atoi ( argv[1] ) ;
66
67 if ( degree < 4 )
68 {
69 std::cout << "rising degree to 4, the minimum for this program" << std::endl ;
70 degree = 4 ;
71 }
72
73 assert ( degree >= 4 && degree <= vspline_constants::max_degree ) ;
74
75 // create the bspline object
76
78
79 spline_type bsp ( 2 , // two values
80 degree , // degree as per command line
81 vspline::PERIODIC , // periodic boundary conditions
82 0.0 ) ; // no tolerance
83
84 // the bspline object's 'core' is a MultiArrayView to the knot point
85 // data, which we set one by one for this simple example:
86
87 bsp.core[0] = 1.0L ;
88 bsp.core[1] = -1.0L ;
89
90 // now we prefilter the data
91
92 bsp.prefilter() ;
93
94 // we build 'splinus' as a functional construct. Inside the brace,
95 // we 'chain' several vspline::unary_functors:
96 // - a 'domain' which scales and shifts input to the spline's range.
97 // with the 'incoming' range of [ 90 , 450 ] and the spline's
98 // range of [ 0 , 2 ], the translation of incoming coordinates is:
99 // x' = 0 + 2 * ( x - 90 ) / ( 450 - 90 )
100 // - a 'safe' evaluator for the spline. since the spline has been
101 // built with PERIODIC boundary conditions, this evaluator will
102 // map incoming coordinates into the first period, [0,2].
103
104 auto splinus =
105 ( vspline::domain ( 90.0L , 450.0L , bsp )
106 + vspline::make_safe_evaluator < spline_type , long double > ( bsp ) ) ;
107
108 // alternatively we can use this construct. This will work just about
109 // the same, but has a potential flaw: If arithmetic imprecision should
110 // land the output of the periodic gate just slightly below 90.0, the
111 // domain may produce a value just below 0.0, resulting in a slightly
112 // out-of-bounds access. So the construct above is preferable.
113 // Just to demonstrate that vspline::grok also produces an object that
114 // can be used with function call syntax, we use vspline::grok here.
115 // Note how 'grokking' the chain of functors produces a simply typed
116 // object, rather than the complexly typed result of the chaining
117 // operation inside the brace:
118
121 ( vspline::periodic ( 90.0L , 450.0L )
122 + vspline::domain ( 90.0L , 450.0L , bsp )
124
125 // we throw derivatives in the mix. If our spline models a sine,
126 // it's derivatives should model the sine's derivatives, cos etc.
127 // note how this is obscured by the higher 'steepness' of the spline,
128 // which is over [ 0 , 2 ] , not [ 0 , 2 * pi ]. Hence the derivatives
129 // come out amplified with a power of pi, which we compensate for.
130
131 vigra::TinyVector < int , 1 > derivative ;
132 derivative[0] = 1 ;
133 vspline::evaluator < long double , long double > evd1 ( bsp , derivative ) ;
134 derivative[0] = 2 ;
135 vspline::evaluator < long double , long double > evd2 ( bsp , derivative ) ;
136 derivative[0] = 3 ;
137 vspline::evaluator < long double , long double > evd3 ( bsp , derivative ) ;
138
139 auto splinus_d1
140 = ( vspline::domain ( 90.0L , 450.0L , bsp )
141 + vspline::periodic ( 0.0L , 2.0L )
142 + evd1 ) ;
143
144 auto splinus_d2
145 = ( vspline::domain ( 90.0L , 450.0L , bsp )
146 + vspline::periodic ( 0.0L , 2.0L )
147 + evd2 ) ;
148
149 auto splinus_d3
150 = ( vspline::domain ( 90.0L , 450.0L , bsp )
151 + vspline::periodic ( 0.0L , 2.0L )
152 + evd3 ) ;
153
154 // now we let the user enter arbitrary angles, calculate the sine
155 // and the 'splinus' and print the result and difference:
156
157 while ( std::cin.good() )
158 {
159 std::cout << " angle in degrees > " ;
160 long double x ;
161 std::cin >> x ; // get an angle
162
163 if ( std::cin.eof() )
164 {
165 std::cout << std::endl ;
166 break ;
167 }
168
169 long double xs = x * M_PI / 180.0L ; // note: sin() uses radians
170
171 // finally we can produce both results. Note how we can use periodic_ev,
172 // the combination of gate and evaluator, like an ordinary function.
173
174 std::cout << "sin(" << x << ") = "
175 << sin ( xs ) << std::endl
176 << "cos(" << x << ") = "
177 << cos ( xs ) << std::endl
178 << "splinus(" << x << ") = "
179 << splinus ( x ) << std::endl
180 << "splinus2(" << x << ") = "
181 << splinus2 ( x ) << std::endl
182 << "difference sin/splinus: "
183 << sin ( xs ) - splinus ( x ) << std::endl
184 << "difference sin/splinus2: "
185 << sin ( xs ) - splinus2 ( x ) << std::endl
186 << "difference splinus/splinus2: "
187 << splinus2 ( x ) - splinus ( x ) << std::endl
188 << "derivatives: " << splinus_d1 ( x ) / M_PI
189 << " " << splinus_d2 ( x ) / ( M_PI * M_PI )
190 << " " << splinus_d3 ( x ) / ( M_PI * M_PI * M_PI ) << std::endl ;
191
192 }
193}
vspline::bspline< pixel_type, 2 > spline_type
Definition: ca_correct.cc:111
class evaluator encodes evaluation of a spline-like object. This is a generalization of b-spline eval...
Definition: eval.h:1718
vspline::domain_type< coordinate_type, _vsize > domain(const coordinate_type &in_low, const coordinate_type &in_high, const coordinate_type &out_low, const coordinate_type &out_high)
factory function to create a domain_type type object from the desired lower and upper fix point for i...
Definition: domain.h:366
vspline::periodic_gate< rc_type, _vsize > periodic(rc_type lower, rc_type upper)
factory function to create a periodic_gate type functor given a lower and upper limit for the allowed...
Definition: map.h:449
vspline::grok_type< typename grokkee_type::in_type, typename grokkee_type::out_type, grokkee_type::vsize > grok(const grokkee_type &grokkee)
grok() is the corresponding factory function, wrapping grokkee in a vspline::grok_type.
@ PERIODIC
Definition: common.h:73
int main(int argc, char *argv[])
Definition: splinus.cc:56
class bspline now builds on class bspline_base, adding coefficient storage, while bspline_base provid...
Definition: bspline.h:499
view_type core
Definition: bspline.h:566
void prefilter(vspline::xlf_type boost=vspline::xlf_type(1), int njobs=vspline::default_njobs)
prefilter converts the knot point data in the 'core' area into b-spline coefficients....
Definition: bspline.h:815
class grok_type is a helper class wrapping a vspline::unary_functor so that it's type becomes opaque ...
includes all headers from vspline (most of them indirectly)