otbOGRDataSourceWrapper.cxx 24.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Luc Hermitte's avatar
Luc Hermitte committed
20 21 22 23 24


#include "otbOGRDataSourceWrapper.h"
// standard includes
#include <cassert>
25
#include <numeric>
26 27
#include <algorithm>
#include <clocale> // toupper
Luc Hermitte's avatar
Luc Hermitte committed
28
#include <boost/bind.hpp>
29
#include <boost/foreach.hpp>
30 31
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
Luc Hermitte's avatar
Luc Hermitte committed
32 33 34
// ITK includes
#include "itkMacro.h" // itkExceptionMacro
#include "itkExceptionObject.h"
35
#include "itksys/SystemTools.hxx"
Luc Hermitte's avatar
Luc Hermitte committed
36 37
// OTB includes
#include "otbOGRDriversInit.h"
38
#include "otbSystem.h"
Luc Hermitte's avatar
Luc Hermitte committed
39 40 41 42 43
// OGR includes

/*===========================================================================*/
/*=======================[ construction/destruction ]========================*/
/*===========================================================================*/
44

Luc Hermitte's avatar
Luc Hermitte committed
45 46
bool otb::ogr::DataSource::Clear()
{
47
  Reset(ITK_NULLPTR);
Luc Hermitte's avatar
Luc Hermitte committed
48 49 50
  return true;
}

51
void otb::ogr::DataSource::Reset(otb::ogr::version_proxy::GDALDatasetType * source)
Luc Hermitte's avatar
Luc Hermitte committed
52 53 54
{
  if (m_DataSource) {
    // OGR makes a pointless check for non-nullity in
55
    // GDALDataset::DestroyDataSource (pointless because "delete 0" is
Luc Hermitte's avatar
Luc Hermitte committed
56
    // perfectly valid -> it's a no-op)
57
    ogr::version_proxy::Close(m_DataSource); // void, noexcept
Luc Hermitte's avatar
Luc Hermitte committed
58 59 60 61
  }
  m_DataSource = source;
}

62
namespace  { // Anonymous namespace
Luc Hermitte's avatar
Luc Hermitte committed
63 64 65 66
/**\ingroup GeometryInternals
 * \brief Type for associating filename extension with OGR driver names.
 * \since OTB v 3.14.0
 */
67 68 69 70 71 72 73 74 75
struct ExtensionDriverAssociation
  {
  char const* extension;
  char const* driverName;
  bool Matches(std::string const& ext) const
    {
    return ext == extension;
    }
  };
Luc Hermitte's avatar
Luc Hermitte committed
76 77 78 79
/**\ingroup GeometryInternals
 * \brief Associative table of filename extension -> OGR driver names.
 * \since OTB v 3.14.0
 */
80 81
const ExtensionDriverAssociation k_ExtensionDriverMap[] =
  {
82 83 84
    {".SHP", "ESRI Shapefile"},
    {".TAB", "MapInfo File"},
    {".GML", "GML"},
85
    {".GMT", "OGR_GMT"},
86 87 88
    {".GPX", "GPX"},
    {".SQLITE", "SQLite"},
    {".KML", "KML"},
89
  };
Luc Hermitte's avatar
Luc Hermitte committed
90 91 92 93 94 95 96 97
/**\ingroup GeometryInternals
 * \brief Returns the OGR driver name associated to a filename.
 * \since OTB v 3.14.0
 * \note Relies on the driver name associated to the filename extension in \c
 * k_ExtensionDriverMap.
 * \note As a special case, filenames starting with "PG:" are bound to
 * "PostgreSQL".
 */
98 99 100 101 102 103 104
char const* DeduceDriverName(std::string filename)
  {
  std::transform(filename.begin(), filename.end(), filename.begin(), (int (*)(int))toupper);
  if (0 == strncmp(filename.c_str(), "PG:", 3))
    {
    return "PostgreSQL";
    }
105
  const std::string extension = itksys::SystemTools::GetFilenameLastExtension(filename);
106 107 108 109 110 111
  ExtensionDriverAssociation const* whichIt =
    std::find_if(
      boost::begin(k_ExtensionDriverMap), boost::end(k_ExtensionDriverMap),
      boost::bind(&ExtensionDriverAssociation::Matches, _1, extension));
  if (whichIt ==  boost::end(k_ExtensionDriverMap))
    {
112
    return ITK_NULLPTR; // nothing found
113 114 115 116 117 118
    }
  return whichIt->driverName;
  }
} // Anonymous namespace


Luc Hermitte's avatar
Luc Hermitte committed
119
otb::ogr::DataSource::DataSource()
120
: m_DataSource(ITK_NULLPTR),
121
  m_LayerOptions() , 
122
  m_OpenMode(Modes::Update_LayerUpdate),
123
  m_FirstModifiableLayerID(0)
Luc Hermitte's avatar
Luc Hermitte committed
124 125 126
{
  Drivers::Init();

127 128
  ogr::version_proxy::GDALDriverType * d = 
    ogr::version_proxy::GetDriverByName("Memory");
Luc Hermitte's avatar
Luc Hermitte committed
129
  assert(d && "OGR Memory driver not found");
130
  m_DataSource = ogr::version_proxy::Create(d,"in-memory");
Luc Hermitte's avatar
Luc Hermitte committed
131
  if (!m_DataSource) {
132 133
    itkExceptionMacro(<< "Failed to create OGRMemDataSource: " 
                      << CPLGetLastErrorMsg());
Luc Hermitte's avatar
Luc Hermitte committed
134 135 136
  }
}

137 138 139 140 141 142 143
otb::ogr::DataSource::DataSource( 
    otb::ogr::version_proxy::GDALDatasetType * source ,
    Modes::type mode ,
    std::vector< std::string > options /*NULL*/ )
: m_DataSource(source) ,
  m_LayerOptions(options) ,
  m_OpenMode(mode) ,
144
  m_FirstModifiableLayerID(0)
Luc Hermitte's avatar
Luc Hermitte committed
145
{
146
  m_FirstModifiableLayerID = GetLayersCount();
Luc Hermitte's avatar
Luc Hermitte committed
147 148
}

149
otb::ogr::DataSource::Pointer otb::ogr::DataSource::OpenDataSource(std::string const& datasourceName, Modes::type mode)
150
{
151 152 153
  FileNameHelperType::Pointer fileNameHelper = FileNameHelperType::New();
  fileNameHelper->SetExtendedFileName( datasourceName.c_str() );
  std::string simpleFileName = fileNameHelper->GetSimpleFileName();
154 155

  bool update = (mode != Modes::Read);
156 157 158
  ogr::version_proxy::GDALDatasetType * source = 
    ogr::version_proxy::Open( simpleFileName.c_str() ,
                              !update ,
159
                              fileNameHelper->GetGDALOpenOptions() );
160 161 162 163 164 165
  if (!source)
    {
    // In read mode, this is a failure
    // In write mode (Overwrite and Update), create the data source transparently
    if (mode == Modes::Read)
      {
166
      itkGenericExceptionMacro(<< "Failed to open GDALDataset file "
167
        << simpleFileName<<" : " << CPLGetLastErrorMsg());
168 169 170
      }

    // Hand made factory based on file extension.
171
    char const* driverName = DeduceDriverName(simpleFileName);
172 173
    if (!driverName)
      {
174 175
      itkGenericExceptionMacro(<< "No OGR driver known to OTB to create and "
        "handle a DataSource named <"
176
        <<simpleFileName<<">.");
177 178
      }

179 180
    ogr::version_proxy::GDALDriverType * d = 
      ogr::version_proxy::GetDriverByName(  driverName  );
181 182 183

    if(!d)
      {
184 185
      itkGenericExceptionMacro(<< "Could not create OGR driver " << driverName 
        << ", check your OGR configuration for available drivers." );
186 187
      }

188 189 190
    source = ogr::version_proxy::Create( 
                  d ,
                  simpleFileName.c_str() ,
191
                  fileNameHelper->GetGDALCreationOptions() );
192
    if (!source) {
193
      itkGenericExceptionMacro(<< "Failed to create GDALDataset <"
194
        << simpleFileName << "> (driver name: <" << driverName 
195
        <<">: " << CPLGetLastErrorMsg());
196 197
    }
    }
198
  return otb::ogr::DataSource::New( source , mode , fileNameHelper->GetGDALLayerOptions() );
199 200 201 202
}

void DeleteDataSource(std::string const& datasourceName)
{
203 204 205 206 207 208
  otb::OGRExtendedFilenameToOptions::Pointer fileNameHelper = 
    otb::OGRExtendedFilenameToOptions::New();
  fileNameHelper->SetExtendedFileName( datasourceName.c_str() );
  std::string simpleFileName = fileNameHelper->GetSimpleFileName();

  bool ret = otb::ogr::version_proxy::Delete(simpleFileName.c_str());
209
  if (!ret)
210
    {
211
    itkGenericExceptionMacro(<< "Deletion of data source " << simpleFileName
212 213
                             << " failed: " << CPLGetLastErrorMsg());
    }
214 215
}

Luc Hermitte's avatar
Luc Hermitte committed
216
otb::ogr::DataSource::Pointer
217
otb::ogr::DataSource::New(std::string const& datasourceName, Modes::type mode)
Luc Hermitte's avatar
Luc Hermitte committed
218
{
219 220 221 222
  FileNameHelperType::Pointer fileNameHelper = FileNameHelperType::New();
  fileNameHelper->SetExtendedFileName( datasourceName.c_str() );
  std::string simpleFileName = fileNameHelper->GetSimpleFileName();

Julien Malik's avatar
Julien Malik committed
223 224
  if (mode < Modes::Read || mode >= Modes::MAX__)
    {
225
    itkGenericExceptionMacro(<< "Wrong mode when opening " << simpleFileName );
Julien Malik's avatar
Julien Malik committed
226 227
    }

Luc Hermitte's avatar
Luc Hermitte committed
228
  Drivers::Init();
229
  ogr::version_proxy::GDALDatasetType * ds = 
230
    ogr::version_proxy::Open( simpleFileName.c_str() , true );
231

232
  bool ds_exists = (ds!=ITK_NULLPTR);
233 234

  ogr::version_proxy::Close(ds);
235

236 237

  if (ds_exists && mode == Modes::Overwrite)
238 239 240 241 242
    {
    DeleteDataSource(datasourceName);
    }

  return OpenDataSource(datasourceName, mode);
Luc Hermitte's avatar
Luc Hermitte committed
243 244
}

OTB Bot's avatar
STYLE  
OTB Bot committed
245
/*static*/
Luc Hermitte's avatar
Luc Hermitte committed
246
otb::ogr::DataSource::Pointer
247
otb::ogr::DataSource::New(otb::ogr::version_proxy::GDALDatasetType * source , Modes::type mode , std::vector< std::string > layerOptions )
Luc Hermitte's avatar
Luc Hermitte committed
248
{
249
  Pointer res = new DataSource( source , mode , layerOptions );
250
  res->UnRegister();
Luc Hermitte's avatar
Luc Hermitte committed
251 252 253 254 255 256 257 258 259 260 261
  return res;
}

/*virtual*/  otb::ogr::DataSource::~DataSource()
{
  Clear();
}

/*===========================================================================*/
/*================================[ layers ]=================================*/
/*===========================================================================*/
262 263
otb::ogr::DataSource::const_iterator otb::ogr::DataSource::cbegin() const
{
264
  return const_iterator(*this, 0);
265 266 267 268
}

otb::ogr::DataSource::const_iterator otb::ogr::DataSource::cend() const
{
269
  return const_iterator(*this, GetLayersCount());
270 271 272 273 274 275 276 277 278 279 280 281
}

otb::ogr::DataSource::iterator otb::ogr::DataSource::begin()
{
  return iterator(*this, 0);
}

otb::ogr::DataSource::iterator otb::ogr::DataSource::end()
{
  return iterator(*this, GetLayersCount());
}

282
otb::ogr::Layer otb::ogr::DataSource::CreateLayer(
OTB Bot's avatar
STYLE  
OTB Bot committed
283 284 285
  std::string const& name,
  OGRSpatialReference * poSpatialRef/* = NULL */,
  OGRwkbGeometryType eGType/* = wkbUnknown */,
286
  std::vector<std::string> const& papszOptions/* = NULL */)
287 288
{
  assert(m_DataSource && "Datasource not initialized");
289

290 291 292 293 294
  // In read mode, try to return an existing layer.
  // and throw if not found
  if (m_OpenMode == Modes::Read)
    {
    otb::ogr::Layer l = GetLayerChecked(name); // will throw if not existing
295 296
    itkGenericOutputMacro(<< "Requesting layer creation in read-only "
                             "GDALDataset. Returning the existing layer");
297 298 299 300 301 302
    return l;
    }

  // Other mode : Check if the layer already exists.
  otb::ogr::Layer layer = GetLayer(name); // won't throw on failure

303 304 305 306 307 308
  FileNameHelperType::Pointer layerOptionHelper = 
    FileNameHelperType::GetGDALLayerOptionsHelper( m_LayerOptions );
  layerOptionHelper->AddGDALLayerOptions( papszOptions );
  std::vector<std::string> layerOptions = 
    layerOptionHelper->GetGDALLayerOptions();

309 310
  switch (m_OpenMode)
  {
311
  case Modes::Update_LayerOverwrite:
312
    {
313 314 315 316 317 318 319 320
    // First delete the layer
    if (layer)
      {
      DeleteLayer(GetLayerID(name));
      }

    // Then create it
    OGRLayer * ol = m_DataSource->CreateLayer(
321 322 323 324 325
      name.c_str() ,
      poSpatialRef ,
      eGType ,
      otb::ogr::StringListConverter( layerOptions ).to_ogr() );

326
    if (!ol)
327
      {
328
      itkGenericExceptionMacro(<< "Failed to create the layer <"<<name
329
        << "> in the GDALDataset file <" << GetDatasetDescription()
330 331 332 333 334
        <<">: " << CPLGetLastErrorMsg());
      }

    const bool modifiable = true;
    return Layer(ol, modifiable);
335
    }
336 337 338 339 340 341 342 343 344 345 346 347
    break;
  case Modes::Overwrite:
  case Modes::Update_LayerUpdate:
    {
    if (layer)
      {
      return layer;
      }
    else
      {
      // Then create it
      OGRLayer * ol = m_DataSource->CreateLayer(
348 349 350 351 352
        name.c_str() ,
        poSpatialRef ,
        eGType ,
        otb::ogr::StringListConverter( layerOptions ).to_ogr() );

353
      if (!ol)
354
        {
355
        itkGenericExceptionMacro(<< "Failed to create the layer <"<<name
356
          << "> in the GDALDataset file <" <<  GetDatasetDescription()
357 358
          <<">: " << CPLGetLastErrorMsg());
        }
359

360 361 362 363 364 365
      const bool modifiable = true;
      return Layer(ol, modifiable);
      }
    }
    break;
  case Modes::Update_LayerCreateOnly:
366
    {
367
    // The layer exists. Returns it
368
    // It will be non-modifiable if already existing at GDALDataset creation time
369 370 371 372 373 374 375
    if (layer)
      {
      return layer;
      }

    // Case where the layer does not exists
    OGRLayer * ol = m_DataSource->CreateLayer(
376 377 378 379 380
          name.c_str() ,
          poSpatialRef ,
          eGType ,
          otb::ogr::StringListConverter( layerOptions ).to_ogr() );

381 382 383
    if (!ol)
      {
      itkGenericExceptionMacro(<< "Failed to create the layer <"<<name
384
        << "> in the GDALDataset file <" <<  GetDatasetDescription()
385 386 387 388 389
        <<">: " << CPLGetLastErrorMsg());
      }

    const bool modifiable = true;
    return Layer(ol, modifiable);
390
    }
391 392 393
    break;
  default :
    assert(false && "Should never be there");
394
    itkGenericExceptionMacro(<< "GDALDataset opening mode not supported");
395 396
    break;
  }
397

398
  itkGenericExceptionMacro(<< "GDALDataset opening mode not supported");
399
  return Layer(ITK_NULLPTR, false); // keep compiler happy
400 401 402
}

otb::ogr::Layer otb::ogr::DataSource::CopyLayer(
OTB Bot's avatar
STYLE  
OTB Bot committed
403 404
  Layer & srcLayer,
  std::string const& newName,
405
  std::vector<std::string> const& papszOptions/* = NULL */)
406 407
{
  assert(m_DataSource && "Datasource not initialized");
408 409 410 411

  switch (m_OpenMode)
  {
    case Modes::Invalid:
412 413
      assert(false && "Invalid GDALDataset opening mode");
      itkGenericExceptionMacro(<< "Invalid GDALDataset opening mode");
414 415
      break;
    case Modes::Read:
416 417
      itkGenericExceptionMacro(<< "GDALDataset is opened in Read mode : "
                                  "cannot create a layer");
418 419 420 421
      break;
    default:
      break;
  }
422 423 424 425 426 427
  
  FileNameHelperType::Pointer layerOptionHelper = 
    FileNameHelperType::GetGDALLayerOptionsHelper( m_LayerOptions );
  layerOptionHelper->AddGDALLayerOptions( papszOptions );
  std::vector<std::string> layerOptions = 
    layerOptionHelper->GetGDALLayerOptions();
428

429
  OGRLayer * l0 = &srcLayer.ogr();
430 431 432 433
  OGRLayer * ol = m_DataSource->CopyLayer( 
                  l0 ,
                  newName.c_str() ,
                  otb::ogr::StringListConverter( layerOptions ).to_ogr() );
434
  if (!ol)
435
    {
436
    itkGenericExceptionMacro(<< "Failed to copy the layer <"
437 438
      << srcLayer.GetName() << "> into the new layer <" << newName
      << "> in the GDALDataset file <" <<  GetDatasetDescription()
439
      <<">: " << CPLGetLastErrorMsg());
440
    }
441
  const bool modifiable = true;
442
  Layer l( ol , modifiable );
443 444 445 446
  return l;
}

void otb::ogr::DataSource::DeleteLayer(size_t i)
Luc Hermitte's avatar
Luc Hermitte committed
447
{
448 449 450 451 452
  assert(m_DataSource && "Datasource not initialized");

  switch (m_OpenMode)
  {
    case Modes::Invalid:
453 454
      assert(false && "Invalid GDALDataset opening mode");
      itkGenericExceptionMacro(<< "Invalid GDALDataset opening mode");
455 456
      break;
    case Modes::Read:
457 458
      itkGenericExceptionMacro(<< "GDALDataset is opened in Read mode : "
        "cannot delete a layer");
459 460
      break;
    case Modes::Update_LayerCreateOnly:
461 462
      itkGenericExceptionMacro(<< "GDALDataset is opened in "
        "Update_LayerCreateOnly mode : cannot delete a layer");
463 464 465 466 467
      break;
    default:
      break;
  }

Luc Hermitte's avatar
Luc Hermitte committed
468 469
  const int nb_layers = GetLayersCount();
  if (int(i) >= nb_layers)
470
    {
471 472 473
    itkExceptionMacro(<< "Cannot delete " << i 
      << "th layer in the GDALDataset <" <<  GetDatasetDescription() 
      << "> as it contains only " << nb_layers << "layers.");
Luc Hermitte's avatar
Luc Hermitte committed
474
    }
475 476
  const OGRErr err = m_DataSource->DeleteLayer(int(i));
  if (err != OGRERR_NONE)
Luc Hermitte's avatar
Luc Hermitte committed
477
    {
478 479 480
    itkExceptionMacro(<< "Cannot delete " << i 
      << "th layer in the GDALDataset <" <<  GetDatasetDescription() 
      << ">: " << CPLGetLastErrorMsg());
Luc Hermitte's avatar
Luc Hermitte committed
481 482 483
    }
}

484 485
bool otb::ogr::DataSource::IsLayerModifiable(size_t i) const
{
486
  assert(m_DataSource && "Datasource not initialized");
487 488 489 490 491 492 493 494 495 496 497 498 499
  switch(m_OpenMode)
  {
    case Modes::Read:
      return false;
    case Modes::Update_LayerCreateOnly:
      return int(i) >= m_FirstModifiableLayerID;
    default:
      return true;
  }
}

bool otb::ogr::DataSource::IsLayerModifiable(std::string const& layername) const
{
500
  assert(m_DataSource && "Datasource not initialized");
501 502 503 504 505 506 507 508 509 510 511 512
  switch(m_OpenMode)
  {
    case Modes::Read:
      return false;
    case Modes::Update_LayerCreateOnly:
        {
        const int id = this->GetLayerIDUnchecked(layername);
        return id >= m_FirstModifiableLayerID;
        }
    default:
      return true;
  }
513 514
}

515
int otb::ogr::DataSource::GetLayerIDUnchecked(std::string const& name) const
516
{
517 518
  assert(m_DataSource && "Datasource not initialized");
  for (int i = 0, N = GetLayersCount(); i < N; i++)
519
    {
520 521 522 523
    OGRLayer * raw_layer = GetLayerUnchecked(i);
    // wrapping to give access to GetName() that doesn't exist with all version of gdal/ogr
    Layer layer(raw_layer, false);
    if (layer.GetName() == name)
524 525 526 527
      {
      return i;
      }
    }
528 529
  return -1;
}
530

531 532 533 534
size_t otb::ogr::DataSource::GetLayerID(std::string const& name) const
{
  int const id = GetLayerIDUnchecked(name);
  if (id < 0)
535
    {
536
    itkExceptionMacro( << "Cannot fetch any layer named <" << name
537
      << "> in the GDALDataset <" <<  GetDatasetDescription() << ">: "
538 539
      << CPLGetLastErrorMsg());
    }
540 541
  return 0; // keep compiler happy
}
542 543

otb::ogr::Layer otb::ogr::DataSource::GetLayerChecked(size_t i)
Luc Hermitte's avatar
Luc Hermitte committed
544
{
545
  assert(m_DataSource && "Datasource not initialized");
546 547
  const int nb_layers = GetLayersCount();
  if (int(i) >= nb_layers)
548
    {
549
    itkExceptionMacro(<< "Cannot fetch " << i << "th layer in the GDALDataset <"
550 551
      << GetDatasetDescription() << "> as it contains only " << nb_layers 
      << "layers.");
552 553 554 555
    }
  OGRLayer * layer_ptr = m_DataSource->GetLayer(int(i));
  if (!layer_ptr)
    {
556 557 558
    itkExceptionMacro( << "Unexpected error: cannot fetch " << i 
      << "th layer in the GDALDataset <" << GetDatasetDescription() 
      << ">: " << CPLGetLastErrorMsg());
559
    }
560
  return otb::ogr::Layer(layer_ptr, IsLayerModifiable(i));
Luc Hermitte's avatar
Luc Hermitte committed
561 562 563 564
}

OGRLayer* otb::ogr::DataSource::GetLayerUnchecked(size_t i)
{
565
  assert(m_DataSource && "Datasource not initialized");
Luc Hermitte's avatar
Luc Hermitte committed
566
  OGRLayer * layer_ptr = m_DataSource->GetLayer(int(i));
Luc Hermitte's avatar
Luc Hermitte committed
567
  return layer_ptr;
Luc Hermitte's avatar
Luc Hermitte committed
568 569
}

570 571 572 573
otb::ogr::Layer otb::ogr::DataSource::GetLayer(std::string const& name)
{
  assert(m_DataSource && "Datasource not initialized");
  OGRLayer * layer_ptr = m_DataSource->GetLayerByName(name.c_str());
574
  return otb::ogr::Layer(layer_ptr, layer_ptr ? IsLayerModifiable(name) : false);
575 576 577 578 579 580 581 582 583
}

otb::ogr::Layer otb::ogr::DataSource::GetLayerChecked(std::string const& name)
{
  assert(m_DataSource && "Datasource not initialized");
  OGRLayer * layer_ptr = m_DataSource->GetLayerByName(name.c_str());
  if (!layer_ptr)
    {
    itkExceptionMacro( << "Cannot fetch any layer named <" << name
584
      << "> in the GDALDataset <" << GetDatasetDescription() << ">: "
585
      << CPLGetLastErrorMsg());
586
    }
587
  return otb::ogr::Layer(layer_ptr, IsLayerModifiable(name));
588 589
}

Luc Hermitte's avatar
Luc Hermitte committed
590 591
int otb::ogr::DataSource::GetLayersCount() const
{
592
  assert(m_DataSource && "Datasource not initialized");
Luc Hermitte's avatar
Luc Hermitte committed
593 594 595
  return m_DataSource->GetLayerCount();
}

596
otb::ogr::Layer otb::ogr::DataSource::ExecuteSQL(
OTB Bot's avatar
STYLE  
OTB Bot committed
597 598
  std::string const& statement,
  OGRGeometry * poSpatialFilter,
599 600 601
  char        const* pszDialect)
{
  assert(m_DataSource && "Datasource not initialized");
602
  const bool modifiable = false;
603 604 605 606 607
  OGRLayer * layer_ptr = m_DataSource->ExecuteSQL(
    statement.c_str(), poSpatialFilter, pszDialect);
  if (!layer_ptr)
    {
#if defined(PREFER_EXCEPTION)
608 609 610
    itkExceptionMacro( << "Unexpected error: cannot execute the SQL request <" 
      << statement << "> in the GDALDataset <" <<  GetDatasetDescription() 
      << ">: " << CPLGetLastErrorMsg());
OTB Bot's avatar
STYLE  
OTB Bot committed
611
#else
612
    // Cannot use the deleter made for result sets obtained from
613
    // GDALDataset::ExecuteSQL because it checks for non-nullity....
614
    // *sigh*
615
    return otb::ogr::Layer(ITK_NULLPTR, modifiable);
616 617
#endif
    }
618
  return otb::ogr::Layer(layer_ptr, *m_DataSource, modifiable);
619 620
}

621 622 623 624 625 626 627 628 629
void
otb::ogr::DataSource::
SetLayerCreationOptions( std::vector< std::string > options )
{
  FileNameHelperType::Pointer helper = FileNameHelperType::New();
  helper->SetGDALLayerOptions( options );
  m_LayerOptions = helper->GetGDALLayerOptions();
  // perf : do we move code from  helper->SetGDALLayerOptions in here?
}
630

631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647
void
otb::ogr::DataSource::
AddLayerCreationOptions( std::vector< std::string > options )
{
  FileNameHelperType::Pointer helper = FileNameHelperType::New();
  helper->SetGDALLayerOptions( m_LayerOptions );
  helper->AddGDALLayerOptions( options );
  m_LayerOptions = helper->GetGDALLayerOptions();
  // perf : do we move code from helper->AddGDALLayerOptions in here?
}

std::vector< std::string >
otb::ogr::DataSource::
GetLayerCreationOptions()
{
  return m_LayerOptions;
}
Luc Hermitte's avatar
Luc Hermitte committed
648 649 650 651
/*===========================================================================*/
/*===============================[ features ]================================*/
/*===========================================================================*/
namespace  { // Anonymous namespace
Luc Hermitte's avatar
Luc Hermitte committed
652 653 654 655 656 657 658 659 660
/**\ingroup GeometryInternals
 * \brief %Functor used to accumulate the sizes of the layers in a \c DataSource.
 * \since OTB v 3.14.0
 */
struct AccuLayersSizes
  {
  AccuLayersSizes(bool doForceComputation)
    : m_doForceComputation(doForceComputation) { }
  int operator()(int accumulated, otb::ogr::Layer const& layer) const
Luc Hermitte's avatar
Luc Hermitte committed
661
    {
Luc Hermitte's avatar
Luc Hermitte committed
662 663 664 665 666 667
    const int loc_size = layer.GetFeatureCount(m_doForceComputation);
    return loc_size < 0 ? loc_size : loc_size+accumulated;
    }
private:
  bool m_doForceComputation;
  };
OTB Bot's avatar
STYLE  
OTB Bot committed
668
} // Anonymous namespace
Luc Hermitte's avatar
Luc Hermitte committed
669 670 671

int otb::ogr::DataSource::Size(bool doForceComputation) const
{
672
  return std::accumulate(begin(),end(), 0, AccuLayersSizes(doForceComputation));
Luc Hermitte's avatar
Luc Hermitte committed
673 674 675 676 677 678
}

/*===========================================================================*/
/*=================================[ Misc ]==================================*/
/*===========================================================================*/

679
OGREnvelope otb::ogr::DataSource::GetGlobalExtent(bool force/* = false */, std::string *outwkt) const
680
{
681
  assert(m_DataSource && "Datasource not initialized");
682
  const_iterator lit = this->begin();
683

684
  if(lit==this->end())
OTB Bot's avatar
STYLE  
OTB Bot committed
685
    {
686 687
    itkGenericExceptionMacro(<< "Cannot compute global extent because there "
      "are no layers in the DataSource");
688 689
    }

690
  const OGRSpatialReference * ref_srs = lit->GetSpatialRef();
691
  OGREnvelope sExtent = lit->GetExtent(force);
692

693 694 695 696 697
  if (outwkt)
    {
    *outwkt = lit->GetProjectionRef();
    }

698 699
  ++lit;

OTB Bot's avatar
STYLE  
OTB Bot committed
700
  for(; lit!=this->end(); ++lit)
701
    {
702 703 704 705
    OGREnvelope cExtent = lit->GetExtent(force); // may throw

    const OGRSpatialReference * current_srs = lit->GetSpatialRef();

706
  // If both srs are valid and if they are different
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
    if(ref_srs && current_srs && current_srs->IsSame(ref_srs) == 0)
      {
      // Reproject cExtent in ref_srs
      // OGRCreateCoordinateTransformation is not const-correct
      OGRCoordinateTransformation * coordTransformation = OGRCreateCoordinateTransformation(
        const_cast<OGRSpatialReference *>(current_srs),
        const_cast<OGRSpatialReference *>(ref_srs));

      coordTransformation->Transform(1,&cExtent.MinX,&cExtent.MinY);
      coordTransformation->Transform(1,&cExtent.MaxX,&cExtent.MaxY);

      const double real_minx = std::min(cExtent.MinX,cExtent.MaxX);
      const double real_miny = std::min(cExtent.MinY,cExtent.MaxY);
      const double real_maxx = std::max(cExtent.MinX,cExtent.MaxX);
      const double real_maxy = std::max(cExtent.MinY,cExtent.MaxY);

      cExtent.MinX = real_minx;
      cExtent.MinY = real_miny;
      cExtent.MaxX = real_maxx;
      cExtent.MaxY = real_maxy;

#if GDAL_VERSION_NUM >= 1700
      OGRCoordinateTransformation::DestroyCT(coordTransformation);
#else
#warning the following resource release may crash, please update your version of GDAL
      delete coordTransformation; // note there is no garanty
#endif
      }
    // else: If srs are invalid, we assume that extent are coherent

    // Merge with previous layers' extent
    sExtent.Merge(cExtent);
    } // for each layer

  return sExtent;
}
743

744 745 746 747 748 749 750 751
std::string otb::ogr::DataSource::GetGlobalExtent(double & ulx,
                                           double & uly,
                                           double & lrx,
                                           double & lry,
                                           bool force) const
{
  std::string outwkt;
  const OGREnvelope sExtent = GetGlobalExtent(force, &outwkt);
752 753 754 755
  ulx = sExtent.MinX;
  uly = sExtent.MinY;
  lrx = sExtent.MaxX;
  lry = sExtent.MaxY;
756 757

  return outwkt;
758 759 760
}


Luc Hermitte's avatar
Luc Hermitte committed
761 762 763 764
/*virtual*/
void otb::ogr::DataSource::PrintSelf(
  std::ostream& os, itk::Indent indent) const
{
765
  assert(m_DataSource && "Datasource not initialized");
766
  BOOST_FOREACH(Layer const& l, *this)
767 768 769
    {
    l.PrintSelf(os, indent);
    }
Luc Hermitte's avatar
Luc Hermitte committed
770 771
}

772
/*virtual*/ void otb::ogr::DataSource::Graft(const itk::DataObject * itkNotUsed(data))
Luc Hermitte's avatar
Luc Hermitte committed
773 774 775
{
  assert(! "Disabled to check if it makes sense...");
}
776

Luc Hermitte's avatar
Luc Hermitte committed
777
bool otb::ogr::DataSource::HasCapability(std::string const& capabilityName) const
778 779
{
  assert(m_DataSource && "Datasource not initialized");
780
  return m_DataSource->TestCapability(capabilityName.c_str());
781 782 783 784 785
}

void otb::ogr::DataSource::SyncToDisk()
{
  assert(m_DataSource && "Datasource not initialized");
786
  bool ret = otb::ogr::version_proxy::SyncToDisk(m_DataSource);
787

788
  if(!ret)
789
    {
790
    itkExceptionMacro( << "Cannot flush the pending of the OGRDataSource <"
791
      << GetDatasetDescription() << ">: " << CPLGetLastErrorMsg());
792 793
    }
}
794 795 796 797


std::string otb::ogr::DataSource::GetDatasetDescription() const
{
798 799
  std::vector<std::string> files = 
    otb::ogr::version_proxy::GetFileListAsStringVector( m_DataSource );
800
  std::string description = "";
801 802
  for( std::vector<std::string>::const_iterator it = files.begin() ; 
       it!=files.end() ; ++it )
803 804 805 806
    description+=(*it)+", ";

  return description;
}