OpenWalnut  1.5.0dev
WTuringTextureCreator.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV-Leipzig and CNCF-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #include <algorithm>
26 #include <iostream>
27 #include <memory>
28 #include <vector>
29 
30 #include <boost/random.hpp>
31 #include <core/common/exceptions/WPreconditionNotMet.h>
32 
33 #include "WTuringTextureCreator.h"
34 
36  : m_numIterations( 100 ),
37  m_spotIrregularity( 0.1 ),
38  m_spotSize( 0.1 )
39 {
40  WPrecond( numThreads > 0, "" );
41 
42  for( std::size_t k = 0; k < numThreads; ++k )
43  {
44  m_threads.push_back( std::shared_ptr< TextureThread >( new TextureThread( k, numThreads ) ) );
45  }
46 }
47 
49 {
50 }
51 
53 {
54  WPrecond( iter > 0, "Invalid number of iterations!" );
55 
56  m_numIterations = iter;
57 }
58 
60 {
61  WPrecond( irr >= 0.0f && irr <= 1.0f, "Spot irregularity must be in [0,1]!" );
62 
63  m_spotIrregularity = irr;
64 }
65 
67 {
68  WPrecond( size >= 0.0f && size <= 1.0f, "Spot size must be in [0,1]!" );
69 
70  m_spotSize = size;
71 }
72 
73 osg::ref_ptr< WGETexture3D > WTuringTextureCreator::create( std::size_t sizeX, std::size_t sizeY, std::size_t sizeZ )
74 {
75  // some constants, maybe change to parameters
76  float const spotFactor = ( 0.02f + 0.58f * ( 1.0f - m_spotSize ) ) / 15.0f;
77  float const d1 = 0.125f;
78  float const d2 = 0.03125f;
79  float const speed = 1.0f;
80 
81  std::vector< float > concentration1( sizeX * sizeY * sizeZ, 4.0f );
82  std::vector< float > concentration2( sizeX * sizeY * sizeZ, 4.0f );
83  std::vector< float > delta1( sizeX * sizeY * sizeZ, 0.0f );
84  std::vector< float > delta2( sizeX * sizeY * sizeZ, 0.0f );
85  std::vector< float > noise( sizeX * sizeY * sizeZ );
86 
87  boost::mt19937 generator( std::time( 0 ) );
88 
89  float noiseRange = 0.1f + 4.9f * m_spotIrregularity;
90 
91  boost::uniform_real< float > dist( 12.0f - noiseRange, 12.0f + noiseRange );
92  boost::variate_generator< boost::mt19937&, boost::uniform_real< float > > rand( generator, dist );
93 
94  // initialize noise
95  for( std::size_t k = 0; k < sizeX * sizeY * sizeZ; ++k )
96  {
97  noise[ k ] = rand();
98  }
99 
100  // iterate
101  for( std::size_t iter = 0; iter < m_numIterations; ++iter )
102  {
103  std::cout << "iteration: " << iter << std::endl;
104 
105  // step one: calculate change in concentration across the volume
106  for( std::size_t k = 0; k < m_threads.size(); ++k )
107  {
108  m_threads[ k ]->setTextureSize( sizeX, sizeY, sizeZ );
109  m_threads[ k ]->setSpotFactor( spotFactor );
110  m_threads[ k ]->setDiffusionConstants( d1, d2 );
111  m_threads[ k ]->setBufferPointers( &concentration1, &concentration2, &noise, &delta1, &delta2 );
112  m_threads[ k ]->run();
113  }
114 
115  for( std::size_t k = 0; k < m_threads.size(); ++k )
116  {
117  m_threads[ k ]->wait();
118  }
119 
120  // applying the change in concentration is not too costly
121  for( std::size_t k = 0; k < sizeX * sizeY * sizeZ; ++k )
122  {
123  concentration1[ k ] += speed * delta1[ k ];
124  concentration2[ k ] += speed * delta2[ k ];
125  }
126  }
127 
128  // allocate new osg::Image for the texture data
129  osg::ref_ptr< osg::Image > img = new osg::Image;
130  img->allocateImage( sizeX, sizeY, sizeZ, GL_LUMINANCE, GL_UNSIGNED_BYTE );
131 
132  // find min and max
133  float c1min = *std::min_element( concentration1.begin(), concentration1.end() );
134  float c1max = *std::max_element( concentration1.begin(), concentration1.end() );
135 
136  // copy to image
137  for( std::size_t k = 0; k < sizeX * sizeY * sizeZ; ++k )
138  {
139  img->data()[ k ] = 255.0f * ( concentration1[ k ] - c1min ) / ( c1max - c1min );
140  }
141 
142  return osg::ref_ptr< WGETexture< osg::Texture3D > >( new WGETexture< osg::Texture3D >( img ) );
143 }
144 
145 WTuringTextureCreator::TextureThread::TextureThread( std::size_t id, std::size_t max )
146  : WThreadedRunner(),
147  m_id( id ),
148  m_maxThreads( max ),
149  m_sizeX( 2 ),
150  m_sizeY( 2 ),
151  m_sizeZ( 2 ),
152  m_spotFactor( 0.5 ),
153  m_diffusionConstant1( 0.5 ),
154  m_diffusionConstant2( 0.5 )
155 {
156 }
157 
159 {
160 }
161 
163 {
164  WPrecond( d1 >= 0.0 && d1 <= 1.0, "" );
165  WPrecond( d2 >= 0.0 && d2 <= 1.0, "" );
166 
167  m_diffusionConstant1 = d1;
168  m_diffusionConstant2 = d2;
169 }
170 
172 {
173  WPrecond( spotFactor > 0.0, "" );
174 
175  m_spotFactor = spotFactor;
176 }
177 
178 void WTuringTextureCreator::TextureThread::setTextureSize( std::size_t sizeX, std::size_t sizeY, std::size_t sizeZ )
179 {
180  WPrecond( sizeX > 0, "" );
181  WPrecond( sizeY > 0, "" );
182  WPrecond( sizeZ > 0, "" );
183 
184  m_sizeX = sizeX;
185  m_sizeY = sizeY;
186  m_sizeZ = sizeZ;
187 }
188 
190 {
191  WPrecond( m_concentration1 != 0, "Invalid pointer!" );
192  WPrecond( m_concentration2 != 0, "Invalid pointer!" );
193  WPrecond( m_noise != 0, "Invalid pointer!" );
194  WPrecond( m_delta1 != 0, "Invalid pointer!" );
195  WPrecond( m_delta2 != 0, "Invalid pointer!" );
196 
197  std::size_t const numVoxels = m_sizeX * m_sizeY * m_sizeZ;
198 
199  std::size_t start = m_id * ( numVoxels / m_maxThreads );
200  std::size_t end = ( m_id + 1 ) * ( numVoxels / m_maxThreads );
201 
202  if( m_id == m_maxThreads - 1 )
203  {
204  end = numVoxels;
205  }
206 
207  for( std::size_t idx = start; idx < end; ++idx )
208  {
209  std::size_t i = idx % m_sizeX;
210  std::size_t j = ( idx / m_sizeX ) % m_sizeY;
211  std::size_t k = ( idx / m_sizeX ) / m_sizeY;
212 
213  std::size_t iNext = ( i + 1 ) % m_sizeX;
214  std::size_t iPrev = ( i + m_sizeX - 1 ) % m_sizeX;
215 
216  std::size_t jNext = ( j + 1 ) % m_sizeY;
217  std::size_t jPrev = ( j + m_sizeY - 1 ) % m_sizeY;
218 
219  std::size_t kNext = ( k + 1 ) % m_sizeZ;
220  std::size_t kPrev = ( k + m_sizeZ - 1 ) % m_sizeZ;
221 
222  // estimate change in concentrations using 3d laplace filter
223  float dc1 = 0.0;
224  dc1 += ( *m_concentration1 )[ iPrev + j * m_sizeX + k * m_sizeX * m_sizeY ];
225  dc1 += ( *m_concentration1 )[ iNext + j * m_sizeX + k * m_sizeX * m_sizeY ];
226  dc1 += ( *m_concentration1 )[ i + jPrev * m_sizeX + k * m_sizeX * m_sizeY ];
227  dc1 += ( *m_concentration1 )[ i + jNext * m_sizeX + k * m_sizeX * m_sizeY ];
228  dc1 += ( *m_concentration1 )[ i + j * m_sizeX + kPrev * m_sizeX * m_sizeY ];
229  dc1 += ( *m_concentration1 )[ i + j * m_sizeX + kNext * m_sizeX * m_sizeY ];
230  dc1 -= 6.0f * ( *m_concentration1 )[ idx ];
231 
232  float dc2 = 0.0;
233  dc2 += ( *m_concentration2 )[ iPrev + j * m_sizeX + k * m_sizeX * m_sizeY ];
234  dc2 += ( *m_concentration2 )[ iNext + j * m_sizeX + k * m_sizeX * m_sizeY ];
235  dc2 += ( *m_concentration2 )[ i + jPrev * m_sizeX + k * m_sizeX * m_sizeY ];
236  dc2 += ( *m_concentration2 )[ i + jNext * m_sizeX + k * m_sizeX * m_sizeY ];
237  dc2 += ( *m_concentration2 )[ i + j * m_sizeX + kPrev * m_sizeX * m_sizeY ];
238  dc2 += ( *m_concentration2 )[ i + j * m_sizeX + kNext * m_sizeX * m_sizeY ];
239  dc2 -= 6.0f * ( *m_concentration2 )[ idx ];
240 
241  // diffusion
242  ( *m_delta1 )[ idx ] = m_spotFactor * ( 16.0f - ( *m_concentration1 )[ idx ] * ( *m_concentration2 )[ idx ] ) + m_diffusionConstant1 * dc1;
243  ( *m_delta2 )[ idx ] = m_spotFactor *
244  ( ( *m_concentration1 )[ idx ] * ( *m_concentration2 )[ idx ]
245  - ( *m_concentration2 )[ idx ] - ( *m_noise )[ idx ] )
246  + m_diffusionConstant2 * dc2;
247  }
248 }
249 
250 void WTuringTextureCreator::TextureThread::setBufferPointers( std::vector< float > const* concentration1,
251  std::vector< float > const* concentration2,
252  std::vector< float > const* noise,
253  std::vector< float >* delta1,
254  std::vector< float >* delta2 )
255 {
256  WPrecond( concentration1 != 0, "Invalid pointer!" );
257  WPrecond( concentration2 != 0, "Invalid pointer!" );
258  WPrecond( noise != 0, "Invalid pointer!" );
259  WPrecond( delta1 != 0, "Invalid pointer!" );
260  WPrecond( delta2 != 0, "Invalid pointer!" );
261 
262  m_concentration1 = concentration1;
263  m_concentration2 = concentration2;
264  m_noise = noise;
265  m_delta1 = delta1;
266  m_delta2 = delta2;
267 }
This calls serves a simple purpose: have a texture and its scaling information together which allows ...
Definition: WGETexture.h:53
Base class for all classes needing to be executed in a separate thread.
The thread calculating the Turing concentration diffusion in a given range.
TextureThread(std::size_t id, std::size_t max)
Create a calculation thread.
void setDiffusionConstants(float d1, float d2)
Diffusion constants according to Turing Reaction Diffusion algorithm.
virtual void threadMain()
The actual thread function running the algorithm.
void setBufferPointers(std::vector< float > const *concentration1, std::vector< float > const *concentration2, std::vector< float > const *noise, std::vector< float > *delta1, std::vector< float > *delta2)
Define the memory to work in.
void setTextureSize(std::size_t sizeX, std::size_t sizeY, std::size_t sizeZ)
Target texture size.
void setSpotFactor(float spotFactor)
The factor influencing size and shape of a spot.
WTuringTextureCreator(std::size_t numThreads=boost::thread::hardware_concurrency())
Constructor.
void setSpotIrregularity(float irr)
The irregularity of the spots.
void setNumIterations(std::size_t iter)
The number of iterations to use for calculating the texture.
std::vector< std::shared_ptr< TextureThread > > m_threads
The thread pool.
float m_numIterations
Number of iterations.
void setSpotSize(float size)
Define the size of the spots inside the texture.
float m_spotIrregularity
Spot irregularity.
osg::ref_ptr< WGETexture3D > create(std::size_t sizeX, std::size_t sizeY, std::size_t sizeZ)
Create the Turing noise texture of arbitrary size.