vspline 1.1.0
Generic C++11 Code for Uniform B-Splines
mandelbrot.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 2017 - 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 mandelbrot.cc
33///
34/// \brief calculate an image of a section of the mandelbrot set
35///
36/// to demonstrate that vspline's transform routines don't have to use
37/// b-splines at all, here's a simple example creating a functor
38/// to perform the iteration leading to the mandelbrot set, together
39/// with a vspline::domain adapting the coordinates and another
40/// functor to do the 'colorization'. The three functors are chained
41/// and fed to vspline::transform() to yield the image.
42///
43/// compile with:
44///
45/// ./examples.sh mandelbrot.cc
46///
47/// ./hwy_mandelbrot_clang++ -2 -1 1 1
48///
49/// ( -2 , -1 ) being lower left and ( 1 , 1 ) upper right
50///
51/// the result will be written to 'mandelbrot.tif'
52
53#include <iostream>
54#include <vspline/vspline.h>
55
56#include <vigra/stdimage.hxx>
57#include <vigra/imageinfo.hxx>
58#include <vigra/impex.hxx>
59
60// we want a colour image
61typedef vigra::RGBValue<double,0,1,2> pixel_type;
62
63// coordinate_type has a 2D coordinate
64typedef vigra::TinyVector < double , 2 > coordinate_type ;
65
70
71// target_type is a 2D array of pixels
72typedef vigra::MultiArray < 2 , pixel_type > target_type ;
73
75: public vspline::unary_functor < coordinate_type , int >
76{
77 typedef typename vspline::unary_functor
79
80 using base_type::vsize ;
81
82 const int max_iterations = 255 ;
83 const double threshold = 1000.0 ;
84
85 // the single-value evaluation recognizably uses the well-known
86 // iteration formula
87
88 void eval ( const coordinate_type & c , int & m ) const
89 {
90 std::complex < double > cc ( c[0] , c[1] ) ;
91 std::complex < double > z ( 0.0 , 0.0 ) ;
92
93 for ( m = 0 ; m < max_iterations ; m++ )
94 {
95 z = z * z + cc ;
96 if ( std::abs ( z ) > threshold )
97 break ;
98 }
99 }
100
101 // the vector code is a bit more involved, since the vectorized type
102 // for a std::complex<double> is a vigra::TinyVector of two SIMD types,
103 // and we implement the complex maths 'manually':
104
105 void eval ( const crd_v & c , int_v & m ) const
106 {
107 // state of the iteration
108 crd_v z { 0.0f , 0.0f } ;
109 // iteration count
110 m = 0.0f ;
111
112 for ( int i = 0 ; i < max_iterations ; i++ )
113 {
114 // z = z * z ; using complex maths
115 compo_v rr = z[0] * z[0] ;
116 compo_v ii = z[1] * z[1] ;
117 compo_v ri = z[0] * z[1] ;
118 z[0] = rr - ii ;
119 z[1] = 2.0f * ri ;
120
121 // create a mask for those values which haven't exceeded the
122 // theshold yet
123
124 rr += ii ;
125 auto mm = ( rr < threshold * threshold ) ;
126
127 // if the mask is empty, all values have exceeded the threshold
128 // and we end the iteration
129
130 if ( none_of ( mm ) )
131 break ;
132
133 // now we add 'c', the coordinate
134 z += c ;
135
136 // and increase the iteration count for all values which haven't
137 // exceeded the threshold
138 m ( mm ) = ( m + 1 ) ;
139 }
140 }
141
142// #endif
143
144} ;
145
147: public vspline::unary_functor < int , pixel_type , VSZ >
148{
149 // to 'colorize' we produce black-and-white from the incoming
150 // value's LSB
151
152 template < class IN , class OUT >
153 void eval ( const IN & c , OUT & result ) const
154 {
155 result = 255 * ( c & 1 ) ;
156 // for a bit more colour, try
157 // result = OUT( 255 * ( c & 1 ) , 127 * ( c & 2 ) , 63 * ( c & 4 ) ) ;
158 } ;
159} ;
160
161int main ( int argc , char * argv[] )
162{
163 // get the extent of the section to show
164 if ( argc < 5 )
165 {
166 std::cerr << "please pass x0, y0, x1 and y1 on the command line" << std::endl ;
167 std::cerr << "typical invocation: mandelbrot -2 -1 1 1" << std::endl ;
168 exit ( -1 ) ;
169 }
170
171 double x0 = atof ( argv[1] ) ;
172 double y0 = atof ( argv[2] ) ;
173 double x1 = atof ( argv[3] ) ;
174 double y1 = atof ( argv[4] ) ;
175
176 // this is where the result should go - we produce a 4K image:
177
178 target_type target ( vigra::Shape2 ( 3840 , 2160 ) ) ;
179
180 // the domain maps the image coordinates to the coordinates of the
181 // section we want to display. The mapped coordinates, now in the range
182 // of ((x0,y0), (x1,y1)), are fed to the functor calculating the result
183 // of the iteration, and it's results are fed to a 'colorize' object
184 // which translates the iteration depth values to a pixel value.
185
186 auto f = vspline::domain < coordinate_type , VSZ >
187 ( coordinate_type ( 0 , 0 ) ,
188 coordinate_type ( 3839 , 2159 ) ,
189 coordinate_type ( x0 , y0 ) ,
190 coordinate_type ( x1 , y1 ) )
192 + colorize() ;
193
194 // the combined functor is passed to transform(), which uses it for
195 // every coordinate pair in 'target' and deposits the result at the
196 // corresponding location.
197
198 vspline::transform ( f , target ) ;
199
200 // store the result with vigra impex
201
202 vigra::ImageExportInfo imageInfo ( "mandelbrot.tif" );
203
204 std::cout << "storing the target image as 'mandelbrot.tif'" << std::endl ;
205
206 vigra::exportImage ( target ,
207 imageInfo
208 .setPixelType("UINT8")
209 .setCompression("100")
210 .setForcedRangeMapping ( 0 , 255 , 0 , 255 ) ) ;
211}
vigra::TinyVector< float, 2 > coordinate_type
Definition: ca_correct.cc:107
vigra::MultiArray< 2, pixel_type > target_type
Definition: ca_correct.cc:115
vigra::RGBValue< double, 0, 1, 2 > pixel_type
Definition: mandelbrot.cc:61
int main(int argc, char *argv[])
Definition: mandelbrot.cc:161
vspline::vector_traits< int, VSZ >::type int_v
Definition: mandelbrot.cc:69
vspline::vector_traits< double >::type compo_v
Definition: mandelbrot.cc:67
vigra::TinyVector< double, 2 > coordinate_type
Definition: mandelbrot.cc:64
vspline::vector_traits< coordinate_type >::type crd_v
Definition: mandelbrot.cc:66
const int VSZ
Definition: mandelbrot.cc:68
vigra::MultiArray< 2, pixel_type > target_type
Definition: mandelbrot.cc:72
bool none_of(const mchunk_t< D, N > &arg)
void transform(const unary_functor_type &functor, const vigra::MultiArrayView< dimension, typename unary_functor_type::in_type > &input, vigra::MultiArrayView< dimension, typename unary_functor_type::out_type > &output, int njobs=vspline::default_njobs, vspline::atomic< bool > *p_cancel=0)
implementation of two-array transform using wielding::coupled_wield.
Definition: transform.h:211
void eval(const IN &c, OUT &result) const
Definition: mandelbrot.cc:153
const double threshold
Definition: mandelbrot.cc:83
const int max_iterations
Definition: mandelbrot.cc:82
void eval(const crd_v &c, int_v &m) const
Definition: mandelbrot.cc:105
vspline::unary_functor< coordinate_type, int > base_type
Definition: mandelbrot.cc:78
void eval(const coordinate_type &c, int &m) const
Definition: mandelbrot.cc:88
class unary_functor provides a functor object which offers a system of types for concrete unary funct...
with the definition of 'simd_traits', we can proceed to implement 'vector_traits': struct vector_trai...
Definition: vector.h:344
includes all headers from vspline (most of them indirectly)