otbGlImageActor.cxx 37.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$


  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.


     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
Julien Michel's avatar
INIT  
Julien Michel committed
18
19
20
#include "otbGlImageActor.h"
#include "otbViewSettings.h"
#include "otbMath.h"
21
22
23
#ifdef _WIN32
#include <windows.h>
#endif
24
#include <GL/glew.h>
25

26
#include "otbStandardShader.h"
Julien Michel's avatar
INIT  
Julien Michel committed
27

28
29
30
#include "itkListSample.h"
#include "otbListSampleToHistogramListGenerator.h"

Julien Michel's avatar
INIT  
Julien Michel committed
31
32
33
34
35
36
37
38
39
40
41
namespace otb
{

GlImageActor::GlImageActor()
  : m_TileSize(256),
    m_FileName(),
    m_FileReader(),
    m_LoadedTiles(),
    m_RedIdx(1),
    m_GreenIdx(2),
    m_BlueIdx(3),
42
43
44
    m_CurrentResolution(1),
    m_AvailableResolutions(),
    m_Origin(),
45
    m_Spacing(),
46
    m_NumberOfComponents(0),
47
    m_ImageSettings( ImageSettings::New() ),
48
    m_Shader(),
49
50
    m_ViewportToImageTransform(),
    m_ImageToViewportTransform(),
51
    m_ViewportForwardRotationTransform(RigidTransformType::New()),
52
    m_ViewportBackwardRotationTransform(RigidTransformType::New()),
53
    m_ResolutionAlgorithm(ResolutionAlgorithm::Nearest),
54
    m_SoftwareRendering(false)
Julien Michel's avatar
INIT  
Julien Michel committed
55
56
{}

57
58
59
60
61
62
63
64
65
66
67
GlImageActor
::~GlImageActor()
{
  // Release OpenGL texture names.
  for( TileVectorType::iterator it( m_LoadedTiles.begin() );
       it!=m_LoadedTiles.end();
       ++it )
    UnloadTile( *it );

  m_LoadedTiles.clear();
}
Julien Michel's avatar
INIT  
Julien Michel committed
68

69
70
71
72
73
74
75
76
77
78
79
void
GlImageActor
::CreateShader()
{
  StandardShader::Pointer shader( StandardShader::New() );

  shader->SetImageSettings( m_ImageSettings );

  m_Shader = shader;
}

Julien Michel's avatar
INIT  
Julien Michel committed
80
81
const GlImageActor::PointType & GlImageActor::GetOrigin() const
{
82
  return m_Origin;
Julien Michel's avatar
INIT  
Julien Michel committed
83
84
}

85
86
87
const GeoInterface::Spacing2 &
GlImageActor
::GetSpacing() const
Julien Michel's avatar
INIT  
Julien Michel committed
88
{
89
  return m_Spacing;
Julien Michel's avatar
INIT  
Julien Michel committed
90
91
92
93
94
95
96
97
98
99
100
101
}

std::string GlImageActor::GetWkt() const
{
  return m_FileReader->GetOutput()->GetProjectionRef();
}

GlImageActor::ImageKeywordlistType GlImageActor::GetKwl() const
{
  return m_FileReader->GetOutput()->GetImageKeywordlist();
}

102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123

bool
GlImageActor
::HasKwl() const
{
  return true;
}


bool
GlImageActor
::GetKwl( ImageKeywordlist & kwl ) const
{
  assert( !m_FileReader.IsNull() );
  assert( m_FileReader->GetOutput()!=NULL );

  kwl = m_FileReader->GetOutput()->GetImageKeywordlist();

  return true;
}


124
125
126
127
128
129
GlImageActor::MetaDataDictionaryType & GlImageActor::GetMetaDataDictionary() const
{
  return m_FileReader->GetOutput()->GetMetaDataDictionary();
}


Julien Michel's avatar
INIT  
Julien Michel committed
130
131
void GlImageActor::Initialize(const std::string & filename)
{
132
133
134
  // std::cout
  //   << std::hex << this << "::Initialize( '" << filename << "' )" << std::endl;

Julien Michel's avatar
INIT  
Julien Michel committed
135
136
137
138
139
140
141
142
  // First, clean up any previous data
  this->ClearLoadedTiles();

  m_FileName = filename;

  m_FileReader = ReaderType::New();
  m_FileReader->SetFileName(m_FileName);
  m_FileReader->UpdateOutputInformation();
143

144
145
  m_LargestRegion = m_FileReader->GetOutput()->GetLargestPossibleRegion();

Julien Michel's avatar
Julien Michel committed
146
147
148
149
150
151
152
  if(m_FileReader->GetOutput()->GetNumberOfComponentsPerPixel() < 3)
    {
    m_RedIdx = 1;
    m_GreenIdx = 1;
    m_BlueIdx = 1;
    }

153
154
  m_Origin = m_FileReader->GetOutput()->GetOrigin();
  m_Spacing = m_FileReader->GetOutput()->GetSpacing();
155
  m_NumberOfComponents = m_FileReader->GetOutput()->GetNumberOfComponentsPerPixel();
156

157
158
  unsigned int ovrCount = m_FileReader->GetOverviewsCount();

159
  // std::cout << "overview-count: " << ovrCount << std::endl;
160

161
162
  assert( ovrCount>0 );

163
164
165
166
167
168
169
170
171
172
173
174
  // {
  // typedef std::vector< std::string > StringVector;

  // StringVector info(
  //   m_FileReader->GetOverviewsInfo()
  // );

  // for( StringVector::const_iterator it( info.begin() );
  //      it!=info.end();
  //      ++it )
  //   std::cout << *it << std::endl;
  // }
175

176
177
  m_AvailableResolutions.clear();

178
179
  for( unsigned int i=0; i<ovrCount; ++i )
    m_AvailableResolutions.push_back( i );
180
181
182

  m_CurrentResolution = m_AvailableResolutions.front();

183
184
185
  // Update transforms once data is read
  UpdateTransforms();

186
  // std::cout<<"Number of resolutions in file: "<<m_AvailableResolutions.size()<<std::endl;
Julien Michel's avatar
INIT  
Julien Michel committed
187
188
}

Stéphane Albert's avatar
Stéphane Albert committed
189

Julien Michel's avatar
INIT  
Julien Michel committed
190
191
192
193
void GlImageActor::GetExtent(double & ulx, double & uly, double & lrx, double & lry) const
{
  RegionType largest = m_FileReader->GetOutput()->GetLargestPossibleRegion();

194
195
  const_cast< GlImageActor * >( this )->UpdateTransforms();

Julien Michel's avatar
INIT  
Julien Michel committed
196
197
198
199
200
  ImageRegionToViewportExtent(largest,ulx,uly,lrx,lry);
}

void GlImageActor::ProcessViewSettings()
{
201
202
203
  // Is there anything to do ?
  ViewSettings::ConstPointer settings = this->GetSettings();

204
205
206
207
208
209
210
211
  RigidTransformType::ParametersType rigidParameters(5);
  rigidParameters.Fill(0);
  rigidParameters[0]=settings->GetRotationAngle();
  rigidParameters[1]=settings->GetRotationCenter()[0];
  rigidParameters[2]=settings->GetRotationCenter()[1];

  m_ViewportForwardRotationTransform->SetParameters(rigidParameters);

212
213
214
215
216
217
218
219
220
  rigidParameters[0]=-settings->GetRotationAngle();
  
  m_ViewportBackwardRotationTransform->SetParameters(rigidParameters);
  
  UpdateTransforms();
  
  for (TileVectorType::iterator it = m_LoadedTiles.begin();
       it!=m_LoadedTiles.end();
       ++it)
Julien Michel's avatar
INIT  
Julien Michel committed
221
    {
222
223
224
    // Do not rotate here, handled by opengl
    this->ImageRegionToViewportQuad(it->m_ImageRegion,it->m_UL,it->m_UR,it->m_LL,it->m_LR,false);
    }
Julien Michel's avatar
INIT  
Julien Michel committed
225
226
227
228
}

void GlImageActor::UpdateData()
{
229
230
231
  // Update resolution needed
  UpdateResolution();

Julien Michel's avatar
INIT  
Julien Michel committed
232
233
234
235
  // First, clean existing tiles
  CleanLoadedTiles();

  // Retrieve settings
Stéphane Albert's avatar
Stéphane Albert committed
236
  ViewSettings::ConstPointer settings = GetSettings();
Julien Michel's avatar
INIT  
Julien Michel committed
237

238
  RegionType largest( m_FileReader->GetOutput()->GetLargestPossibleRegion() );
Julien Michel's avatar
INIT  
Julien Michel committed
239
240
241
242
243
 
  double ulx, uly, lrx, lry;

  settings->GetViewportExtent(ulx,uly,lrx,lry);

Julien Michel's avatar
Julien Michel committed
244
  // std::cout<<"Viewport extent: "<<ulx<<", "<<uly<<" - "<<lrx<<", "<<lry<<std::endl;
Julien Michel's avatar
INIT  
Julien Michel committed
245
246
247

  RegionType requested;

Stéphane Albert's avatar
Stéphane Albert committed
248
  ViewportExtentToImageRegion(ulx,uly,lrx,lry,requested);
Julien Michel's avatar
INIT  
Julien Michel committed
249

250
  if( !requested.Crop( largest ) )
251
    return;
Julien Michel's avatar
INIT  
Julien Michel committed
252
253
254
255
256
 
  // Now we have the requested part of image, we need to find the
  // corresponding tiles

  // First compute needed tiles
257
258
259
  unsigned int nbTilesX = vcl_ceil(static_cast<double>(requested.GetIndex()[0] + requested.GetSize()[0])/m_TileSize) -vcl_floor(static_cast<double>(requested.GetIndex()[0])/m_TileSize);
  unsigned int nbTilesY = vcl_ceil(static_cast<double>(requested.GetIndex()[1] + requested.GetSize()[1])/m_TileSize) -vcl_floor(static_cast<double>(requested.GetIndex()[1])/m_TileSize);
  //unsigned int nbTilesY = vcl_ceil(static_cast<double>(requested.GetSize()[1])/m_TileSize);
Julien Michel's avatar
INIT  
Julien Michel committed
260
261
  unsigned int tileStartX = m_TileSize*(requested.GetIndex()[0]/m_TileSize);
  unsigned int tileStartY = m_TileSize*(requested.GetIndex()[1]/m_TileSize);
262
  
Julien Michel's avatar
INIT  
Julien Michel committed
263
264
  SizeType tileSize;
  tileSize.Fill(m_TileSize);
265
266
  Tile newTile;
  
Julien Michel's avatar
INIT  
Julien Michel committed
267
268
269
270
   for(unsigned int i = 0; i < nbTilesX; ++i)
    {
    for(unsigned int j = 0; j<nbTilesY; ++j)
      {
271
      
Julien Michel's avatar
INIT  
Julien Michel committed
272
273
274
275
276
277
278
279
      newTile.m_TextureId = 0;

      IndexType tileIndex;
      tileIndex[0] = static_cast<unsigned int>(tileStartX+i*m_TileSize);
      tileIndex[1] = static_cast<unsigned int>(tileStartY+j*m_TileSize);
      
      newTile.m_ImageRegion.SetSize(tileSize);
      newTile.m_ImageRegion.SetIndex(tileIndex);
Stéphane Albert's avatar
Stéphane Albert committed
280

281
      newTile.m_ImageRegion.Crop( largest );
Julien Michel's avatar
INIT  
Julien Michel committed
282

283
      ImageRegionToViewportQuad(newTile.m_ImageRegion,newTile.m_UL,newTile.m_UR,newTile.m_LL,newTile.m_LR,false);
Julien Michel's avatar
INIT  
Julien Michel committed
284
285
286
287

      newTile.m_RedIdx = m_RedIdx;
      newTile.m_GreenIdx = m_GreenIdx;
      newTile.m_BlueIdx = m_BlueIdx;
288
      newTile.m_Resolution = m_CurrentResolution;
289
      newTile.m_TileSize = m_TileSize;
Julien Michel's avatar
INIT  
Julien Michel committed
290
291
292
293
294
295
296

      if(!TileAlreadyLoaded(newTile))
        {
        LoadTile(newTile);
        }
      }
    }
297

Julien Michel's avatar
INIT  
Julien Michel committed
298
299
300
301
302
303
304
305
306
307
}

bool GlImageActor::TileAlreadyLoaded(const Tile& tile)
{
    for(TileVectorType::iterator it = m_LoadedTiles.begin();
      it!=m_LoadedTiles.end();
      ++it)
    {
    if(it->m_ImageRegion == tile.m_ImageRegion)
      {
308
309
310
311
      return (tile.m_Resolution ==  it->m_Resolution
              && tile.m_RedIdx == it->m_RedIdx
              && tile.m_GreenIdx == it->m_GreenIdx
              && tile.m_BlueIdx == it->m_BlueIdx);
Julien Michel's avatar
INIT  
Julien Michel committed
312
313
314
315
316
317
318
319
      }
    }

  return false;
}

void GlImageActor::Render()
{
320
321
322
323
324
  // std::cout
  //   << "otb::GlImageActor@" << std::hex << this << std::dec << std::endl
  //   << "\tresolution: " << m_ResolutionAlgorithm << std::endl
  //   << "\tpixel: " << m_SoftwareRendering << std::endl
  //   << "\ttile: " << m_TileSize << std::endl;
325

Stéphane Albert's avatar
Stéphane Albert committed
326
  if( !m_SoftwareRendering && !m_Shader.IsNull() )
Julien Michel's avatar
INIT  
Julien Michel committed
327
    {
328
    // std::cout << "\tGLSL" << std::endl;
329

330
331
    m_Shader->LoadShader();
    m_Shader->SetupShader();
Julien Michel's avatar
INIT  
Julien Michel committed
332
    }
333
334
  else
    {
335
    // std::cout << "\tOTB" << std::endl;
336

337
338
339
340
341
342
343
344
345
346
347
    for(TileVectorType::iterator it = m_LoadedTiles.begin();
        it != m_LoadedTiles.end(); ++it)
      {
      if(!it->m_RescaleFilter)
        {
        it->m_RescaleFilter = RescaleFilterType::New();
        it->m_RescaleFilter->AutomaticInputMinMaxComputationOff();
        it->m_RescaleFilter->SetInput(it->m_Image);
        }
      
      VectorImageType::PixelType mins(3),maxs(3),omins(3),omaxs(3);
348
349
      mins.Fill(0);
      maxs.Fill(255);
Julien Michel's avatar
Julien Michel committed
350
351
352

      bool useNoData(false);
      double noData(0.);
353

354
      assert( !m_ImageSettings.IsNull() );
355

356
357
358
359
360
361
362
      mins[ 0 ] = m_ImageSettings->GetMinRed();
      mins[ 1 ] = m_ImageSettings->GetMinGreen();
      mins[ 2 ] = m_ImageSettings->GetMinBlue();
    
      maxs[ 0 ] = m_ImageSettings->GetMaxRed();
      maxs[ 1 ] = m_ImageSettings->GetMaxGreen();
      maxs[ 2  ] = m_ImageSettings->GetMaxBlue();
Julien Michel's avatar
Julien Michel committed
363

364
365
366
367
368
369
370
371
372
      // MANTIS-1204
      // {
      double gamma = m_ImageSettings->GetGamma();

      gamma =
	gamma == 0.0
	? std::numeric_limits< double >::max()
	: 1.0 / gamma;
      // }
Julien Michel's avatar
Julien Michel committed
373

374
375
      if( m_ImageSettings->GetUseNoData() )
	noData = m_ImageSettings->GetNoData();
376
      
377
378
      omins.Fill( 0 );
      omaxs.Fill( 255 );
379
380
381
382
383
    
      it->m_RescaleFilter->SetInputMinimum(mins);
      it->m_RescaleFilter->SetInputMaximum(maxs);
      it->m_RescaleFilter->SetOutputMinimum(omins);
      it->m_RescaleFilter->SetOutputMaximum(omaxs);
384
      it->m_RescaleFilter->SetGamma(gamma);
385
386
387
388
389
      
      it->m_RescaleFilter->Update();


      itk::ImageRegionConstIterator<UCharVectorImageType> imIt(it->m_RescaleFilter->GetOutput(),it->m_RescaleFilter->GetOutput()->GetLargestPossibleRegion());
Julien Michel's avatar
Julien Michel committed
390
391
392
      itk::ImageRegionConstIterator<VectorImageType> inIt(it->m_Image,it->m_Image->GetLargestPossibleRegion());

      
393
394
395
396
397
      
      unsigned char * buffer = new unsigned char[4*it->m_RescaleFilter->GetOutput()->GetLargestPossibleRegion().GetNumberOfPixels()];
      
      unsigned int idx = 0;
      
Julien Michel's avatar
Julien Michel committed
398
      for(imIt.GoToBegin(),inIt.GoToBegin();!imIt.IsAtEnd()&&!inIt.IsAtEnd();++imIt,++inIt)
399
400
401
402
403
404
405
406
        {
        buffer[idx] = static_cast<unsigned char>(imIt.Get()[2]);
        ++idx;
        buffer[idx] = static_cast<unsigned char>(imIt.Get()[1]);
        ++idx;
        buffer[idx] = static_cast<unsigned char>(imIt.Get()[0]);
        ++idx;
        buffer[idx] = 255;
Julien Michel's avatar
Julien Michel committed
407
408
409
410
411
412

        if(useNoData && (inIt.Get()[0] == noData ||inIt.Get()[1] == noData ||inIt.Get()[2] == noData))
          {
          buffer[idx] = 0;
          }
        
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
        ++idx;
        }

      if(!it->m_TextureId)
        {
        glGenTextures(1, &(it->m_TextureId));
        }
      glBindTexture(GL_TEXTURE_2D, it->m_TextureId);
#if defined(GL_TEXTURE_BASE_LEVEL) && defined(GL_TEXTURE_MAX_LEVEL)
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
#endif
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
// #if defined(GL_CLAMP_TO_BORDER)      
//   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP_TO_BORDER);
//   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP_TO_BORDER);
// #elif defined (GL_CLAMP_TO_BORDER_EXT)
//   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP_TO_BORDER_EXT);
//   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP_TO_BORDER_EXT);
// #elif defined (GL_MIRRORED_REPEAT)
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_MIRRORED_REPEAT);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_MIRRORED_REPEAT);
// #endif
      glTexImage2D(
        GL_TEXTURE_2D, 0, GL_RGBA8,
        it->m_RescaleFilter->GetOutput()->GetLargestPossibleRegion().GetSize()[0],
        it->m_RescaleFilter->GetOutput()->GetLargestPossibleRegion().GetSize()[1], 
        0, GL_BGRA, GL_UNSIGNED_BYTE,
        buffer);

      it->m_Loaded = true;
      
      delete [] buffer;
      }
    }

451
452
453
  for(TileVectorType::iterator it = m_LoadedTiles.begin();
      it != m_LoadedTiles.end(); ++it)
    {
454
  
455
456
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
457
  
458
459
    glEnable(GL_TEXTURE_2D);  
    glBindTexture(GL_TEXTURE_2D,it->m_TextureId);
460
  
461
462
463
464
465
466
467
468
469
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);     
    if(m_CurrentResolution == 0)
      {
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
      }
    else
      {
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      }
470
  
471
472
    // Reset color before rendering
    glColor3d(1.0f,1.0f,1.0f);
473
  
474
475
476
477
478
479
    glBegin (GL_QUADS);
    glTexCoord2f (0.0, 1.0); glVertex2f(it->m_LL[0], it->m_LL[1]);
    glTexCoord2f (1.0, 1.0); glVertex2f(it->m_LR[0], it->m_LR[1]);
    glTexCoord2f (1.0, 0.0); glVertex2f(it->m_UR[0], it->m_UR[1]);
    glTexCoord2f (0.0, 0.0); glVertex2f(it->m_UL[0], it->m_UL[1]);
    glEnd ();
480
  
481
482
483
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_BLEND);
    }
484

485
  if( !m_SoftwareRendering && !m_Shader.IsNull() )
486
    {
487
    m_Shader->UnloadShader();
488
    }
Julien Michel's avatar
INIT  
Julien Michel committed
489
490
491
492
}

void GlImageActor::LoadTile(Tile& tile)
{
Stéphane Albert's avatar
Stéphane Albert committed
493
494
495
496
497
498
499
500
501
502
503
504
  // std::cout
  //   << std::hex << this
  //   << "::LoadTile(" << &tile << ")"
  //   << std::dec << std::endl;

  // std::cout
  //   << "[ " << tile.m_ImageRegion.GetIndex()[ 0 ]
  //   << ", " << tile.m_ImageRegion.GetIndex()[ 1 ]
  //   << " ]-[ " << tile.m_ImageRegion.GetSize()[ 0 ]
  //   << ", " << tile.m_ImageRegion.GetSize()[ 1 ]
  //   << "]"
  //   << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
505

Julien Michel's avatar
INIT  
Julien Michel committed
506
  ExtractROIFilterType::Pointer extract = ExtractROIFilterType::New();
Stéphane Albert's avatar
Stéphane Albert committed
507

Julien Michel's avatar
INIT  
Julien Michel committed
508
509
510
511
512
  extract->SetInput(m_FileReader->GetOutput());
  extract->SetExtractionRegion(tile.m_ImageRegion);
  extract->SetChannel(tile.m_RedIdx);
  extract->SetChannel(tile.m_GreenIdx);
  extract->SetChannel(tile.m_BlueIdx);
Stéphane Albert's avatar
Stéphane Albert committed
513

Stéphane Albert's avatar
Stéphane Albert committed
514
  // std::cout << "ExtractROIFilter::Update()...";
515
  extract->Update();
Stéphane Albert's avatar
Stéphane Albert committed
516
  // std::cout << "\tDONE\n";
517
518

  tile.m_Image = extract->GetOutput();
519
520

  if(!m_SoftwareRendering)
521
    {
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
    itk::ImageRegionConstIterator<VectorImageType> it(extract->GetOutput(),extract->GetOutput()->GetLargestPossibleRegion());
    
    float * buffer = new float[4*extract->GetOutput()->GetLargestPossibleRegion().GetNumberOfPixels()];
    
    unsigned int idx = 0;
    
    for(it.GoToBegin();!it.IsAtEnd();++it)
      {
      buffer[idx] = static_cast<float>(it.Get()[2]);
      ++idx;
      buffer[idx] = static_cast<float>(it.Get()[1]);
      ++idx;
      buffer[idx] = static_cast<float>(it.Get()[0]);
      ++idx;
      buffer[idx] = 255.;
      ++idx;
      }
    
    // Now load the texture
541
542
    assert( tile.m_TextureId==0 );

Stéphane Albert's avatar
Stéphane Albert committed
543
    glGenTextures( 1, &tile.m_TextureId );
544
545
546
547
548
549
550

    // Following assert is somtimes false on some OpenGL systems for
    // some unknown reason even though the glGenTexture() call has
    // succeeded.
    // assert( glGetError()==GL_NO_ERROR );

    assert( tile.m_TextureId!=0 );
Stéphane Albert's avatar
Stéphane Albert committed
551

Stéphane Albert's avatar
Stéphane Albert committed
552
    // std::cout << "Generated texture #" << tile.m_TextureId << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
553

554
    glBindTexture(GL_TEXTURE_2D, tile.m_TextureId);
Julien Michel's avatar
INIT  
Julien Michel committed
555
#if defined(GL_TEXTURE_BASE_LEVEL) && defined(GL_TEXTURE_MAX_LEVEL)
556
557
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
Julien Michel's avatar
INIT  
Julien Michel committed
558
#endif
559
    //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
560
561
562
563
564
565
566
// #if defined(GL_CLAMP_TO_BORDER)      
//   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP_TO_BORDER);
//   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP_TO_BORDER);
// #elif defined (GL_CLAMP_TO_BORDER_EXT)
//   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP_TO_BORDER_EXT);
//   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP_TO_BORDER_EXT);
// #elif defined (GL_MIRRORED_REPEAT)
567
568
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_MIRRORED_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_MIRRORED_REPEAT);
569
// #endif
570
571
572
573
574
575
576
577
578
579
580
581
582
583
    glTexImage2D(
      GL_TEXTURE_2D, 0, GL_RGB32F,
      extract->GetOutput()->GetLargestPossibleRegion().GetSize()[0],
      extract->GetOutput()->GetLargestPossibleRegion().GetSize()[1], 
      0, GL_BGRA, GL_FLOAT,
      buffer);
    
    tile.m_Loaded = true;
    
    delete [] buffer;
    }
    
    // And push to loaded texture
    m_LoadedTiles.push_back(tile);
Julien Michel's avatar
INIT  
Julien Michel committed
584
}
585
  
Julien Michel's avatar
INIT  
Julien Michel committed
586
587
void GlImageActor::UnloadTile(Tile& tile)
{
Stéphane Albert's avatar
Stéphane Albert committed
588
  // std::cout << std::hex << this << std::dec << "::UnloadTile()" << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
589
590

  if( tile.m_Loaded )
Julien Michel's avatar
INIT  
Julien Michel committed
591
    {
592
593
    assert( tile.m_TextureId>0 );

Stéphane Albert's avatar
Stéphane Albert committed
594
595
    glDeleteTextures( 1, &tile.m_TextureId );

Stéphane Albert's avatar
Stéphane Albert committed
596
    // std::cout << "Deleted texture #" << tile.m_TextureId << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
597

598
599
600
601
602
603
    tile.m_TextureId = 0;

    tile.m_Image = VectorImageType::Pointer();

    tile.m_RescaleFilter = RescaleFilterType::Pointer();

Julien Michel's avatar
INIT  
Julien Michel committed
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
    tile.m_Loaded = false;
    }
}

void GlImageActor::CleanLoadedTiles()
{
  TileVectorType newLoadedTiles;

  // Retrieve settings
  ViewSettings::ConstPointer settings = this->GetSettings();
    
  double ulx, uly, lrx, lry;

  settings->GetViewportExtent(ulx,uly,lrx,lry);
    
  RegionType requested;
  
  this->ViewportExtentToImageRegion(ulx,uly,lrx,lry,requested);

  for(TileVectorType::iterator it = m_LoadedTiles.begin();
  it!=m_LoadedTiles.end();++it)
    {
    RegionType tileRegion = it->m_ImageRegion;

    // Test if tileRegion intersects requested region
    if(!tileRegion.Crop(requested)
630
       || it->m_Resolution != m_CurrentResolution
Julien Michel's avatar
INIT  
Julien Michel committed
631
632
       || it->m_RedIdx != m_RedIdx
       || it->m_GreenIdx != m_GreenIdx
633
       || it->m_BlueIdx != m_BlueIdx
634
635
636
637
638
639
       // We need to compare with theoretical tile size as actual tile
       // size might be smaller at images borders
       || it->m_TileSize!=m_TileSize)
      {
       
      
Julien Michel's avatar
INIT  
Julien Michel committed
640
641
642
643
644
645
646
647
      // Tile will not be used anymore, unload it from GPU
      UnloadTile(*it);
      }
    else
      {
      newLoadedTiles.push_back(*it);
      }
    }
648

649
  // std::cout<<"GPU memory cleanup: removing "<<m_LoadedTiles.size() - newLoadedTiles.size() << " over "<<m_LoadedTiles.size() <<" tiles"<<std::endl;
650

Julien Michel's avatar
INIT  
Julien Michel committed
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
  m_LoadedTiles.swap(newLoadedTiles);


}

void GlImageActor::ClearLoadedTiles()
{
  for(TileVectorType::iterator it = m_LoadedTiles.begin();
      it!=m_LoadedTiles.end();++it)
    {
    UnloadTile(*it);
    }
  m_LoadedTiles.clear();
}

void GlImageActor::ImageRegionToViewportExtent(const RegionType& region, double & ulx, double & uly, double & lrx, double& lry) const
{
  PointType tul,tur,tll,tlr;
  
  ImageRegionToViewportQuad(region,tul,tur,tll,tlr);

  // TODO: Take into account origin/scaling/rotation here ?
  // TODO: Screen to image / image to screen transform calls here ?

  ulx = std::min(std::min(tul[0],tur[0]),std::min(tll[0],tlr[0]));
  uly = std::min(std::min(tul[1],tur[1]),std::min(tll[1],tlr[1]));
  lrx = std::max(std::max(tul[0],tur[0]),std::max(tll[0],tlr[0]));
  lry = std::max(std::max(tul[1],tur[1]),std::max(tll[1],tlr[1]));
}

681
void GlImageActor::ImageRegionToViewportQuad(const RegionType & region, PointType & ul, PointType & ur, PointType & ll, PointType & lr, bool rotate) const
Julien Michel's avatar
INIT  
Julien Michel committed
682
683
684
685
686
687
{
  // Retrieve settings
  ViewSettings::ConstPointer settings = this->GetSettings();
    
  itk::ContinuousIndex<double,2> cul,cur,cll,clr;
  
688
689
  cul[0] = region.GetIndex()[0];
  cul[1] = region.GetIndex()[1];
Julien Michel's avatar
INIT  
Julien Michel committed
690
  cur = cul;
691
  cur[0]+=region.GetSize()[0]-1;
Julien Michel's avatar
INIT  
Julien Michel committed
692
  cll = cul;
693
  cll[1]+=region.GetSize()[1]-1;
Julien Michel's avatar
INIT  
Julien Michel committed
694
  clr = cur;
695
  clr[1]+=region.GetSize()[1]-1;
Julien Michel's avatar
INIT  
Julien Michel committed
696
697
698
699
700
701
702

  PointType iul, iur,ill,ilr;

  m_FileReader->GetOutput()->TransformContinuousIndexToPhysicalPoint(cul,iul);
  m_FileReader->GetOutput()->TransformContinuousIndexToPhysicalPoint(cur,iur);
  m_FileReader->GetOutput()->TransformContinuousIndexToPhysicalPoint(cll,ill);
  m_FileReader->GetOutput()->TransformContinuousIndexToPhysicalPoint(clr,ilr);
703

704
705
706
707
708
709
710
711
712
713
  // Take into account that Origin refers to center of first pixel
  SpacingType spacing = m_FileReader->GetOutput()->GetSpacing();
  iul[0]-=0.5*spacing[0];
  iul[1]-=0.5*spacing[1];
  iur[0]+=0.5*spacing[0];
  iur[1]-=0.5*spacing[1];
  ill[0]-=0.5*spacing[0];
  ill[1]+=0.5*spacing[1];
  ilr[0]+=0.5*spacing[0];
  ilr[1]+=0.5*spacing[1];
714
  
715
716
717
718
  PointType pul = m_ImageToViewportTransform->TransformPoint(iul);
  PointType pur = m_ImageToViewportTransform->TransformPoint(iur);
  PointType pll = m_ImageToViewportTransform->TransformPoint(ill);
  PointType plr = m_ImageToViewportTransform->TransformPoint(ilr);
Julien Michel's avatar
INIT  
Julien Michel committed
719

720
721
722
723
724
725
726
727
  if(rotate)
    {
    pul = m_ViewportBackwardRotationTransform->TransformPoint(pul);
    pur = m_ViewportBackwardRotationTransform->TransformPoint(pur);
    pll = m_ViewportBackwardRotationTransform->TransformPoint(pll);
    plr = m_ViewportBackwardRotationTransform->TransformPoint(plr);
    }
  
Julien Michel's avatar
INIT  
Julien Michel committed
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
  ul[0] = pul[0];
  ul[1] = pul[1];
  ur[0] = pur[0];
  ur[1] = pur[1];
  ll[0] = pll[0];
  ll[1] = pll[1];
  lr[0] = plr[0];
  lr[1] = plr[1];
}

void GlImageActor::ViewportExtentToImageRegion(const double& ulx, const double & uly, const double & lrx, const double & lry, RegionType & region) const
{
  // Retrieve settings
  ViewSettings::ConstPointer settings = this->GetSettings();

  RegionType largest = m_FileReader->GetOutput()->GetLargestPossibleRegion();

  PointType ul,ur,ll,lr,tul,tur,tll,tlr;
  
  ul[0]=ulx;
  ul[1]=uly;
  ur[0]=lrx;
  ur[1]=uly;
  ll[0]=ulx;
  ll[1]=lry;
  lr[0]=lrx;
  lr[1]=lry;
  
756
757
758
759
  tul = m_ViewportToImageTransform->TransformPoint(m_ViewportForwardRotationTransform->TransformPoint(ul));
  tur = m_ViewportToImageTransform->TransformPoint(m_ViewportForwardRotationTransform->TransformPoint(ur));
  tll = m_ViewportToImageTransform->TransformPoint(m_ViewportForwardRotationTransform->TransformPoint(ll));
  tlr = m_ViewportToImageTransform->TransformPoint(m_ViewportForwardRotationTransform->TransformPoint(lr));
Julien Michel's avatar
INIT  
Julien Michel committed
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775

  itk::ContinuousIndex<double,2> cul,cur,cll,clr;

  m_FileReader->GetOutput()->TransformPhysicalPointToContinuousIndex(tul,cul);
  m_FileReader->GetOutput()->TransformPhysicalPointToContinuousIndex(tur,cur);
  m_FileReader->GetOutput()->TransformPhysicalPointToContinuousIndex(tll,cll);
  m_FileReader->GetOutput()->TransformPhysicalPointToContinuousIndex(tlr,clr);
  
  // TODO: Take into account origin/scaling/rotation here ?
  // TODO: Screen to image / image to screen transform calls here ?

  double iulx, iuly, ilrx, ilry;

  iulx = std::max(std::min(std::min(cul[0],cur[0]),std::min(cll[0],clr[0])),0.);
  iuly = std::max(std::min(std::min(cul[1],cur[1]),std::min(cll[1],clr[1])),0.);
  ilrx = std::min(std::max(std::max(cul[0],cur[0]),std::max(cll[0],clr[0])),static_cast<double>(largest.GetSize()[0]));
776
  ilry = std::min(std::max(std::max(cul[1],cur[1]),std::max(cll[1],clr[1])),static_cast<double>(largest.GetSize()[1])); 
Julien Michel's avatar
INIT  
Julien Michel committed
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
  // Now we have the requested part of image, we need to find the
  // corresponding tiles

  IndexType index;
  index[0] = static_cast<unsigned int>(iulx);
  index[1] = static_cast<unsigned int>(iuly);
 
  SizeType size;
  size[0] = static_cast<int>(ilrx-iulx);
  size[1] = static_cast<int>(ilry-iuly);
     
  region.SetSize(size);
  region.SetIndex(index);
  
  region.Crop(m_FileReader->GetOutput()->GetLargestPossibleRegion());
}

794
795
GlImageActor::PointType GlImageActor::ViewportToImageTransform(const PointType & in, bool physical) const
{
796
797
798
  PointType inRotated = m_ViewportForwardRotationTransform->TransformPoint(in);

  PointType imgPoint = m_ViewportToImageTransform->TransformPoint(inRotated);
799
800
801
802
803
804
805
806
807
808

  if(!physical)
    {
    imgPoint[0]=(imgPoint[0]-m_Origin[0])/m_Spacing[0];
    imgPoint[1]=(imgPoint[1]-m_Origin[1])/m_Spacing[1];
    }

  return imgPoint;
}

809
810
811
812
813
814
815
816
817
818
GlImageActor::PointType GlImageActor::ImageToViewportTransform(const PointType & in, bool physical) const
{
  PointType imgPoint = in;

  if(!physical)
    {
    imgPoint[0]=imgPoint[0]*m_Spacing[0]+m_Origin[0];
    imgPoint[1]=imgPoint[1]*m_Spacing[1]+m_Origin[1];
    }

819
820
821
822
  PointType out =  m_ImageToViewportTransform->TransformPoint(imgPoint);
  
  return m_ViewportBackwardRotationTransform->TransformPoint(out);

823
824
}

825
826
827
828
829

bool
GlImageActor
::GetPixelFromViewport( const PointType & in,
			PixelType & pixel ) const
830
{
831
832
833
834
835
  PointType p;
  IndexType i;

  return GetPixelFromViewport( in, pixel, p, i );
}
836

837

838
839
840
841
842
843
844
845
846
847
848
bool
GlImageActor
::GetPixelFromViewport( const PointType & ptView,
			PixelType & pixel,
			PointType & ptPhysical,
			IndexType & index ) const
{
  ptPhysical = ViewportToImageTransform( ptView );

  return GetPixel( ptPhysical, pixel, index );
}
849

850
851
852
853
854
855
856

bool
GlImageActor
::GetPixel( const PointType & physical,
	    PixelType & pixel,
	    IndexType & index ) const
{
Stéphane Albert's avatar
Stéphane Albert committed
857

Stéphane Albert's avatar
Stéphane Albert committed
858
  // std::cout << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
859

Stéphane Albert's avatar
Stéphane Albert committed
860
861
862
  // std::cout << "O: (" << m_Origin[ 0 ] << ", " << m_Origin[ 1 ] << ")";
  // std::cout << "\tS: (" << m_Spacing[ 1 ] << ", " << m_Spacing[ 1 ] << ")";
  // std::cout << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
863

Stéphane Albert's avatar
Stéphane Albert committed
864
865
  // std::cout << "P: (" << physical[ 0 ] << ", " << physical[ 1 ] << ")";
  // std::cout << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
866

867
  // First, we need to return index in full img (not in overviews)
Stéphane Albert's avatar
Stéphane Albert committed
868
#if 0
869
870
  index[ 0 ] = static_cast<unsigned int>((physical[0]-m_Origin[0])/m_Spacing[0]);
  index[ 1 ] = static_cast<unsigned int>((physical[1]-m_Origin[1])/m_Spacing[1]);
871

Stéphane Albert's avatar
Stéphane Albert committed
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
#else
  index[ 0 ] =
    static_cast< IndexType::IndexValueType >(
      ( physical[ 0 ] - m_Origin[ 0 ] ) / 
      m_Spacing[ 0 ]
    );

  index[ 1 ] =
    static_cast< IndexType::IndexValueType >(
      ( physical[ 1 ]-  m_Origin[ 1 ] ) /
      m_Spacing[ 1 ]
    );

#endif

Stéphane Albert's avatar
Stéphane Albert committed
887
888
889
890
891
892
893
894
  // std::cout << "I: (" << index[ 0 ] << ", " << index[ 1 ] << ")";
  // std::cout
  //   << "\tI: ("
  //   << ( ( physical[ 0 ] - m_Origin[ 0 ] ) / m_Spacing[ 0 ] )
  //   << ", "
  //   << ( ( physical[ 1 ] - m_Origin[ 1 ] ) / m_Spacing[ 1 ] )
  //   << ")";
  // std::cout << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
895

896
897
898
  // Then, we need to find the index in the currently loaded overview
  IndexType ovrIndex;
  m_FileReader->GetOutput()->TransformPhysicalPointToIndex( physical, ovrIndex );
899

Stéphane Albert's avatar
Stéphane Albert committed
900
901
  // std::cout << "O: (" << ovrIndex[ 0 ] << ", " << ovrIndex[ 1 ] << ")";
  // std::cout << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
902

903
  // And look it up in loaded tiles
904
905
906
907
  for (TileVectorType::const_iterator it = m_LoadedTiles.begin();
       it!=m_LoadedTiles.end();
       ++it)
    {
Stéphane Albert's avatar
Stéphane Albert committed
908
909
910
911
912
913
914
915
916
917
    // std::cout
    //   << "R: ("
    //   << it->m_ImageRegion.GetIndex()[ 0 ]
    //   << ", "
    //   << it->m_ImageRegion.GetIndex()[ 1 ]
    //   << ")-("
    //   << it->m_ImageRegion.GetSize()[ 0 ]
    //   << ", "
    //   << it->m_ImageRegion.GetSize()[ 1 ]
    //   << ")";
Stéphane Albert's avatar
Stéphane Albert committed
918

919
    if(it->m_ImageRegion.IsInside(ovrIndex))
920
      {
921
922
      IndexType idx;

923
924
      idx[ 0 ] = ovrIndex[ 0 ] - it->m_ImageRegion.GetIndex()[ 0 ];
      idx[ 1 ] = ovrIndex[ 1 ] - it->m_ImageRegion.GetIndex()[ 1 ];
925

Stéphane Albert's avatar
Stéphane Albert committed
926
      // std::cout << "\tIr: (" << idx[ 0 ] << ", " << idx[ 1 ] << ")";
Stéphane Albert's avatar
Stéphane Albert committed
927

928
929
      pixel = it->m_Image->GetPixel( idx );

930
931
      return true;
      }
Stéphane Albert's avatar
Stéphane Albert committed
932

Stéphane Albert's avatar
Stéphane Albert committed
933
    // std::cout << std::endl;
934
935
    }

936
  return false;
937
938
939
940
}



941
942
943
944
945
946
947
948
void GlImageActor::UpdateResolution()
{
  // Retrieve settings
  ViewSettings::ConstPointer settings = this->GetSettings();

  // Retrieve viewport spacing
  ViewSettings::SpacingType spacing = settings->GetSpacing();
  
949
950
  // 100 screen pixels
  PointType pointA, pointB, pointC;
951
952
953

  pointA  = settings->GetOrigin();
  pointB = pointA;
954
  pointC = pointA;
955
  
956
  pointB[0]+=100*spacing[0];
957
  pointC[1]+=100*spacing[1];
958
959

  // Transform the spacing vector
960
  pointA = m_ViewportForwardRotationTransform->TransformPoint(pointA);
961
  pointA = m_ViewportToImageTransform->TransformPoint(pointA);
962
  pointB = m_ViewportForwardRotationTransform->TransformPoint(pointB);
963
  pointB = m_ViewportToImageTransform->TransformPoint(pointB);
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
  pointC = m_ViewportForwardRotationTransform->TransformPoint(pointC);
  pointC = m_ViewportToImageTransform->TransformPoint(pointC);

  // Equivalence in image pixels
  pointA[0] = (pointA[0] - m_Origin[0])/m_Spacing[0];
  pointA[1] = (pointA[1] - m_Origin[1])/m_Spacing[1];
  pointB[0] = (pointB[0] - m_Origin[0])/m_Spacing[0];
  pointB[1] = (pointB[1] - m_Origin[1])/m_Spacing[1];
  pointC[0] = (pointC[0] - m_Origin[0])/m_Spacing[0];
  pointC[1] = (pointC[1] - m_Origin[1])/m_Spacing[1];

  double distAB = vcl_sqrt((pointA[0]-pointB[0])*(pointA[0]-pointB[0])+(pointA[1]-pointB[1])*(pointA[1]-pointB[1]));
  double distAC = vcl_sqrt((pointA[0]-pointC[0])*(pointA[0]-pointC[0])+(pointA[1]-pointC[1])*(pointA[1]-pointC[1]));
  
  double resolution = std::min(100/distAB,100/distAC);
979
980
981
982

  // std::cout << std::endl;
  // std::cout << "resolution: " << resolution << std::endl;

983
  // Arbitrary higher than any distance we will compute here
984
985
986
987
988
  double minDist = 50000.;
  m_CurrentResolution = 0;

  // OTB always include full resolution level in available resolutions.
  assert( !m_AvailableResolutions.empty() );
989

990
991
992
  // MANTIS-1179: resolution>1 <=> zooming in past 1:1 scale. So, cap
  // resolution to index 0.
  if( resolution<1.0 )
993
    {
994
    bool isFound = false;
995

996
997
998
    // Compute the diff and keep the index that minimize the distance
    for (ResolutionVectorType::iterator it = m_AvailableResolutions.begin();
	 it != m_AvailableResolutions.end(); ++it)
999
      {
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
      double diff = 1/((double)(1<<(*it))) - resolution;

      // std::cout << "diff: " << diff << std::endl;

      if( ( ( m_ResolutionAlgorithm == ResolutionAlgorithm::Nearest_Lower &&
	      diff <= 0 )
	    ||
	    ( m_ResolutionAlgorithm == ResolutionAlgorithm::Nearest_Upper &&
	      diff >= 0 )
	    ||
	    ( m_ResolutionAlgorithm == ResolutionAlgorithm::Nearest ) )
	  &&
	  vcl_abs(diff) < minDist )
	{
	isFound = true;

	minDist = vcl_abs(diff);
	m_CurrentResolution = std::distance(m_AvailableResolutions.begin(),it);

	// std::cout << "found: " << m_CurrentResolution << std::endl;
	}
      }

    // MANTIS-1147: Cap current-resolution.
    if( !isFound )
      {
      assert( m_AvailableResolutions.size() > 0 );
1027

1028
1029
1030
      m_CurrentResolution = m_AvailableResolutions.size() - 1;

      // std::cout << "not found: " << m_CurrentResolution << std::endl;
1031
1032
      }
    }
1033

1034
1035
1036
  std::ostringstream extFilename;
  extFilename<<m_FileName<<"?&resol="<<m_CurrentResolution;

Stéphane Albert's avatar
Stéphane Albert committed
1037
1038
1039
  // ReaderType::New() is forced because of warning message
  // 'Duplicated option detected: <option>. Using value <value>.'
  // output by otb::ExtendedFilenameHelper.
1040
1041
1042
  m_FileReader = ReaderType::New();
  m_FileReader->SetFileName(extFilename.str());
  m_FileReader->UpdateOutputInformation();
Stéphane Albert's avatar
Stéphane Albert committed
1043

Stéphane Albert's avatar
Stéphane Albert committed
1044
  // std::cout << "Switched to resolution: " << m_CurrentResolution << std::endl;
1045
1046
}

1047
1048
void GlImageActor::UpdateTransforms()
{
1049
1050
  // std::cout << std::hex << this << "::UpdateTransforms()" << std::endl;
  // std::cout << "{" << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
1051

1052
  // std::cout << "filename: " << m_FileName << std::endl;
1053

1054
1055
  if(m_FileName == "")
    {
1056
    // std::cout << "}" << std::endl;
1057
1058
1059
1060
1061
1062
    return;
    }

  // Retrieve settings
  ViewSettings::ConstPointer settings = this->GetSettings();

1063
1064
  bool hasChanged = false;

1065
1066
1067
1068
1069
  bool geometryChanged = settings->GetGeometryChanged();

  if( ( !settings->GetUseProjection() && geometryChanged ) ||
      m_ViewportToImageTransform.IsNull() ||
      m_ImageToViewportTransform.IsNull())
1070
    {
1071
1072
1073
    // std::cout
    //   << "otb::GlImageActor@" << std::hex << this
    //   << " Proj: OFF" << std::endl;
1074

1075
1076
    m_ViewportToImageTransform = RSTransformType::New();
    m_ImageToViewportTransform = RSTransformType::New();
1077
1078

    hasChanged = true;
1079
    }
Stéphane Albert's avatar
Stéphane Albert committed
1080

1081
1082
1083
  // std::cout
  //   << std::hex << this << std::dec
  //   << " geometry-changed: " << geometryChanged << std::endl;
1084

1085
1086
  // bool isEqualOrNot =
  //   m_ViewportToImageTransform->GetInputProjectionRef() != settings->GetWkt();
1087

1088
1089
1090
  // std::cout
  //   << std::hex << this << std::dec
  //   << " WKT-changed: " << isEqualOrNot << std::endl;
1091
1092

    geometryChanged = geometryChanged
1093
1094
1095
1096
1097
1098
  || (m_ViewportToImageTransform.IsNotNull() && m_ViewportToImageTransform->GetInputProjectionRef() != settings->GetWkt())
  || (m_ImageToViewportTransform.IsNotNull() && m_ImageToViewportTransform->GetOutputProjectionRef() != settings->GetWkt())
    || (m_ViewportToImageTransform.IsNotNull() && !(m_ViewportToImageTransform->GetInputKeywordList() == settings->GetKeywordList()))
        || (m_ImageToViewportTransform.IsNotNull() && !(m_ImageToViewportTransform->GetOutputKeywordList() == settings->GetKeywordList()));

  if(settings->GetUseProjection() && geometryChanged)
1099
    {
1100
1101
1102
    // std::cout
    //   << "otb::GlImageActor@" << std::hex << this << std::dec
    //   << " Proj: ON" << std::endl;
1103

1104
1105
    m_ViewportToImageTransform = RSTransformType::New();
    m_ImageToViewportTransform = RSTransformType::New();
Stéphane Albert's avatar
Stéphane Albert committed
1106

1107
1108
1109
1110
1111
1112
1113
1114
1115
    m_ViewportToImageTransform->SetInputProjectionRef(settings->GetWkt());
    m_ViewportToImageTransform->SetInputKeywordList(settings->GetKeywordList());
    m_ViewportToImageTransform->SetOutputProjectionRef(m_FileReader->GetOutput()->GetProjectionRef());
    m_ViewportToImageTransform->SetOutputKeywordList(m_FileReader->GetOutput()->GetImageKeywordlist());

    m_ImageToViewportTransform->SetOutputProjectionRef(settings->GetWkt());
    m_ImageToViewportTransform->SetOutputKeywordList(settings->GetKeywordList());
    m_ImageToViewportTransform->SetInputProjectionRef(m_FileReader->GetOutput()->GetProjectionRef());
    m_ImageToViewportTransform->SetInputKeywordList(m_FileReader->GetOutput()->GetImageKeywordlist());
1116
1117

    hasChanged = true;
1118
    }
Stéphane Albert's avatar
Stéphane Albert committed
1119

1120
1121
  if( hasChanged )
    {
1122
    // std::cout << std::hex << this << " -> InstanciateTransform()" << std::endl;
1123
1124
1125
1126

    m_ViewportToImageTransform->InstanciateTransform();
    m_ImageToViewportTransform->InstanciateTransform();
    }
Stéphane Albert's avatar
Stéphane Albert committed
1127

1128
  // std::cout << "}" << std::endl;
1129
}
1130

1131
1132
1133
1134
1135
1136
void GlImageActor::AutoColorAdjustment( double & minRed, double & maxRed,
					double & minGreen, double & maxGreen,
					double & minBlue, double & maxBlue,
					bool full,
					unsigned int refSize,
					double lcp, double hcp )
1137
1138
1139
1140
1141
{
  typedef itk::Statistics::ListSample<VectorImageType::PixelType> ListSampleType;
  typedef itk::Statistics::DenseFrequencyContainer2 DFContainerType;
  typedef ListSampleToHistogramListGenerator<ListSampleType, VectorImageType::InternalPixelType, DFContainerType> HistogramsGeneratorType;

1142
1143
  assert( refSize>0 );

1144
1145
1146
1147
1148
1149
1150
1151
1152
  ListSampleType::Pointer listSample = ListSampleType::New();
  listSample->SetMeasurementVectorSize(3);
  
  if(full)
    {
    // Retrieve the lowest resolution
    ReaderType::Pointer reader = ReaderType::New();
    std::ostringstream extFilename;

1153
    unsigned int nb_pixel_ref = refSize * refSize;
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193

    // Compute the diff and keep the index that minimize the distance
    unsigned int resol = 0;
    bool found = false;

    for (ResolutionVectorType::iterator it = m_AvailableResolutions.begin();
         it != m_AvailableResolutions.end() && !found; ++it,++resol)
      {
      unsigned int factor = 1<<(*it);
      unsigned int sizex = m_LargestRegion.GetSize()[0]/factor;
      unsigned int sizey = m_LargestRegion.GetSize()[1]/factor;

      unsigned int nb_pixel = sizex * sizey;
      if(nb_pixel<nb_pixel_ref)
        {
        found=true;
        break;
        }
      }

    // If no resolution can give less than nb_pixel_ref pixels, take
    // the lowest
    if(!found)
      {
      resol = m_AvailableResolutions.size()-1;
      }

    extFilename<<m_FileName<<"?&resol="<<m_AvailableResolutions[resol];
    reader->SetFileName(extFilename.str());

    ExtractROIFilterType::Pointer extract = ExtractROIFilterType::New();
    extract->SetInput(reader->GetOutput());
    extract->SetChannel(m_RedIdx);
    extract->SetChannel(m_GreenIdx);
    extract->SetChannel(m_BlueIdx);
    extract->Update();
    
    itk::ImageRegionConstIterator<VectorImageType> it(extract->GetOutput(),extract->GetOutput()->GetLargestPossibleRegion());
    for(it.GoToBegin();!it.IsAtEnd();++it)
      {
Julien Michel's avatar
Julien Michel committed
1194
1195
1196
1197
      bool nonan = true;

      for(unsigned int i = 0; i < it.Get().Size();++i)
        {
1198
        nonan = nonan && !vnl_math_isnan(it.Get()[i]);
Julien Michel's avatar
Julien Michel committed
1199
1200
1201
1202
1203
1204
        }

      if(nonan)
        {
        listSample->PushBack(it.Get());
        }
1205
1206
1207
1208
1209
1210
1211
      }
    }
  else
    {
    // Retrieve all tiles
    for(TileVectorType::iterator it = m_LoadedTiles.begin();it!=m_LoadedTiles.end();++it)
    {
1212
    itk::ImageRegionConstIterator<VectorImageType> imIt(it->m_Image,it->m_Image->GetLargestPossibleRegion());
1213
1214
    for(imIt.GoToBegin();!imIt.IsAtEnd();++imIt)
      {
Julien Michel's avatar
Julien Michel committed
1215
1216
1217
1218
      bool nonan = true;

      for(unsigned int i = 0; i < imIt.Get().Size();++i)
        {
1219
        nonan = nonan && !vnl_math_isnan(imIt.Get()[i]);
Julien Michel's avatar
Julien Michel committed
1220
1221
1222
1223
1224
1225
        }

      if(nonan)
        {
        listSample->PushBack(imIt.Get());
        }
1226
1227
1228
1229
1230
      }
    }
    }

    // Compute the histogram
1231
    HistogramsGeneratorType::Pointer histogramsGenerator = HistogramsGeneratorType::New();
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
    histogramsGenerator->SetListSample(listSample);
    histogramsGenerator->SetNumberOfBins(255);
    histogramsGenerator->NoDataFlagOn();
    histogramsGenerator->Update();

    minRed   = histogramsGenerator->GetOutput()->GetNthElement(0)->Quantile(0,lcp);
    maxRed   = histogramsGenerator->GetOutput()->GetNthElement(0)->Quantile(0,1-hcp);
    minGreen = histogramsGenerator->GetOutput()->GetNthElement(1)->Quantile(0,lcp);
    maxGreen = histogramsGenerator->GetOutput()->GetNthElement(1)->Quantile(0,1-hcp);
    minBlue =  histogramsGenerator->GetOutput()->GetNthElement(2)->Quantile(0,lcp);
    maxBlue =  histogramsGenerator->GetOutput()->GetNthElement(2)->Quantile(0,1-hcp);   
}
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263


bool
GlImageActor
::TransformFromViewport( Point2d & out,
                         const Point2d & in,
                         bool isPhysical ) const
{
  out = ViewportToImageTransform( in, isPhysical );

  return true;
}


bool
GlImageActor
::TransformToViewport( Point2d & out,
                       const Point2d & in,
                       bool isPhysical ) const
{
1264
  out = ViewportToImageTransform( in, isPhysical );
1265
1266
1267
1268
1269
1270

  return true;
}


} // End of namespace 'otb'.