otbOGRVectorDataIO.cxx 9.65 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.
 */
Thomas Feuvrier's avatar
Thomas Feuvrier committed
20

21
#include "otbOGRVectorDataIO.h"
Julien Michel's avatar
Julien Michel committed
22

23
#include "ogrsf_frmts.h"
24
#include "otbSystem.h"
25
#include "itksys/SystemTools.hxx"
Thomas Feuvrier's avatar
Thomas Feuvrier committed
26 27
#include "itkByteSwapper.h"
#include "otbMacro.h"
Julien Michel's avatar
Julien Michel committed
28
#include "otbDataNode.h"
29
#include "otbMetaDataKey.h"
30
#include "otbStopwatch.h"
31
#include "otbOGRIOHelper.h"
Julien Michel's avatar
Julien Michel committed
32

33
namespace otb
Thomas Feuvrier's avatar
Thomas Feuvrier committed
34
{
35 36

OGRVectorDataIO
OTB Bot's avatar
OTB Bot committed
37
::OGRVectorDataIO() :
38
  m_DataSource(nullptr)
39 40 41 42
{
  // OGR factory registration
  OGRRegisterAll();
}
43

44 45

OGRVectorDataIO::~OGRVectorDataIO()
46
{
47
  if (m_DataSource != nullptr)
48
    {
49
    this->CloseInternalDataSource();
50
    }
51
}
52

53

54
bool
55
OGRVectorDataIO::CanReadFile(const char* filename) const
56
{
57
  GDALDataset * poDS = ogr::version_proxy::Open(filename, true);
58

59
  if (poDS == nullptr)
60
    {
61
    std::cerr<<"Can not read file "<<filename<<" with GDALOpen"<<std::endl;
62
    return false;
63
    }
64
//     std::cout << poDS->GetDriver()->GetName() << std::endl;
65
  ogr::version_proxy::Close(poDS);
66 67
  return true;
}
68

69
// Used to print information about this object
70

71
void
72
OGRVectorDataIO::PrintSelf(std::ostream& os, itk::Indent indent) const
73 74 75 76 77
{
  Superclass::PrintSelf(os, indent);
}

// Read vector data
78

79
void
80
OGRVectorDataIO
81
::Read(itk::DataObject* datag)
82
{
83
  VectorDataPointerType data = dynamic_cast<VectorDataType*>(datag);
84
  // Destroy previous opened data source
85 86 87 88 89 90

  if(!data)
    {
    itkExceptionMacro(<<"Failed to dynamic cast to otb::VectorData (this should never happen)");
    }

91
  if (m_DataSource != nullptr)
OTB Bot's avatar
OTB Bot committed
92
    {
93
    this->CloseInternalDataSource();
OTB Bot's avatar
OTB Bot committed
94
    }
95

96
  m_DataSource = ogr::version_proxy::Open(this->m_FileName.c_str(),true);
97

98
  if (m_DataSource == nullptr)
OTB Bot's avatar
OTB Bot committed
99 100 101
    {
    itkExceptionMacro(<< "Failed to open data file " << this->m_FileName);
    }
102

OTB Bot's avatar
OTB Bot committed
103 104
  otbMsgDebugMacro(<< "Driver to read: OGR");
  otbMsgDebugMacro(<< "Reading  file: " << this->m_FileName);
105

106
  // Reading layers
OTB Bot's avatar
OTB Bot committed
107
  otbMsgDevMacro(<< "Number of layers: " << m_DataSource->GetLayerCount());
108

109 110 111
  // Retrieving root node
  DataTreePointerType tree = data->GetDataTree();
  DataNodePointerType root = tree->GetRoot()->Get();
Julien Michel's avatar
Julien Michel committed
112

113
  OGRSpatialReference * oSRS = nullptr;
114 115
  //We take the assumption that the spatial reference is common to all layers
  oSRS = m_DataSource->GetLayer(0)->GetSpatialRef();
116

117
  if (oSRS != nullptr)
OTB Bot's avatar
OTB Bot committed
118
    {
119 120 121
    char * projectionRefChar;
    oSRS->exportToWkt(&projectionRefChar);
    std::string projectionRef = projectionRefChar;
122
    CPLFree(projectionRefChar);
OTB Bot's avatar
OTB Bot committed
123 124 125
    itk::MetaDataDictionary& dict = data->GetMetaDataDictionary();
    itk::EncapsulateMetaData<std::string>(dict, MetaDataKey::ProjectionRefKey, projectionRef);
    }
126
  else
OTB Bot's avatar
OTB Bot committed
127
    {
128
    otbMsgDevMacro(<< "Can't retrieve the OGRSpatialReference from the shapefile");
OTB Bot's avatar
OTB Bot committed
129
    }
130

131
  std::string projectionRefWkt = data->GetProjectionRef();
132

133
  bool projectionInformationAvailable = !projectionRefWkt.empty();
134

135
  if (projectionInformationAvailable)
OTB Bot's avatar
OTB Bot committed
136
    {
137
    otbMsgDevMacro(<< "Projection information : " << projectionRefWkt);
OTB Bot's avatar
OTB Bot committed
138
    }
139
  else
OTB Bot's avatar
OTB Bot committed
140
    {
141
    otbMsgDevMacro(<< "Projection information unavailable: assuming WGS84");
OTB Bot's avatar
OTB Bot committed
142
    }
143 144

  // For each layer
145
  for (int layerIndex = 0; layerIndex < m_DataSource->GetLayerCount(); ++layerIndex)
OTB Bot's avatar
OTB Bot committed
146
    {
147 148
    /** retrieving layer and property */
    OGRLayer * layer = m_DataSource->GetLayer(layerIndex);
OTB Bot's avatar
OTB Bot committed
149
    otbMsgDevMacro(<< "Number of features: " << layer->GetFeatureCount());
150

151 152 153 154 155 156 157 158
    OGRFeatureDefn * dfn = layer->GetLayerDefn();

    /** Create the document node */
    DataNodePointerType document = DataNodeType::New();
    document->SetNodeType(DOCUMENT);
    document->SetNodeId(dfn->GetName());

    /** Retrieving the fields types */
159
//     OGRFieldDefn * field;
OTB Bot's avatar
OTB Bot committed
160
//     for (int fieldIndex = 0; fieldIndex<dfn->GetFieldCount(); ++fieldIndex)
161 162
//     {
//       field  = dfn->GetFieldDefn(fieldIndex);
OTB Bot's avatar
OTB Bot committed
163
//       document->SetField(field->GetNameRef(), OGRFieldDefn::GetFieldTypeName(field->GetType()));
164 165
//       // std::cout<<"Document "<<document->GetNodeId()<<": Adding field "<<field->GetNameRef()<<" "<<OGRFieldDefn::GetFieldTypeName(field->GetType())<<std::endl;
//     }
Julien Michel's avatar
Julien Michel committed
166

167
    /** Adding the layer to the data tree */
OTB Bot's avatar
OTB Bot committed
168
    tree->Add(document, root);
169

170 171 172
    /// This is not good but we do not have the choice if we want to
    /// get a hook on the internal structure
    InternalTreeNodeType * documentPtr = const_cast<InternalTreeNodeType *>(tree->GetNode(document));
OTB Bot's avatar
OTB Bot committed
173

174
    /** IO class helper to convert ogr layer*/
175

176
    OGRIOHelper::Pointer OGRConversion = OGRIOHelper::New();
177
    OGRConversion->ConvertOGRLayerToDataTreeNode(layer, documentPtr);
OTB Bot's avatar
OTB Bot committed
178 179

    } // end For each layer
180

181 182 183 184 185 186 187
  this->CloseInternalDataSource();
}

void OGRVectorDataIO::CloseInternalDataSource()
{
  assert(m_DataSource != NULL && "m_DataSource cannot be NULL");
  ogr::version_proxy::Close(m_DataSource);
188
  m_DataSource = nullptr;
189 190
}

191 192

bool OGRVectorDataIO::CanWriteFile(const char* filename) const
193
{
OTB Bot's avatar
OTB Bot committed
194

195
  std::string lFileName(filename);
196
  if (itksys::SystemTools::FileIsDirectory(lFileName) == true)
OTB Bot's avatar
OTB Bot committed
197
    {
198
    return false;
OTB Bot's avatar
OTB Bot committed
199 200 201
    }

  return (this->GetOGRDriverName(filename) != "NOT-FOUND");
202
}
Julien Michel's avatar
Julien Michel committed
203

204

205
void OGRVectorDataIO::Write(const itk::DataObject* datag, char ** /** unused */)
206
{
207
  otb::Stopwatch chrono = otb::Stopwatch::StartNew();
OTB Bot's avatar
OTB Bot committed
208

209 210
  VectorDataConstPointerType data = dynamic_cast<const VectorDataType*>(datag);

211 212 213 214 215 216
  if(!data)
    {
    itkExceptionMacro(<<"Failed to dynamic cast to otb::VectorData (this should never happen).");
    }


217
  //Find first the OGR driver
218
  GDALDriver * ogrDriver =
219
    GetGDALDriverManager()->GetDriverByName(this->GetOGRDriverName(this->m_FileName).data());
220

221
  if (ogrDriver == nullptr)
222
    {
OTB Bot's avatar
OTB Bot committed
223
    itkExceptionMacro(<< "No OGR driver found to write file " << this->m_FileName);
224
    }
Thomas Feuvrier's avatar
Thomas Feuvrier committed
225

226
  // free an existing previous data source, if any
227
  if (m_DataSource != nullptr)
228
    {
229
    ogr::version_proxy::Close(m_DataSource);
230
    }
231

232
  // Erase the dataSource if already exist
233
  ogr::version_proxy::Delete(this->m_FileName.c_str());
234

235
  // m_DataSource = OGRSFDriverRegistrar::Open(this->m_FileName.c_str(), TRUE);
236
  m_DataSource = ogr::version_proxy::Create(ogrDriver,this->m_FileName.c_str());
237

238
  // check the created data source
239
  if (m_DataSource == nullptr)
240
    {
OTB Bot's avatar
OTB Bot committed
241 242 243
    itkExceptionMacro(
      << "Failed to create OGR data source for file " << this->m_FileName <<
      ". Since OGR can not overwrite existing file, be sure that this file does not already exist");
244
    }
245

246
  // Retrieve data required for georeferencing
247

248
  std::string projectionRefWkt = data->GetProjectionRef();
OTB Bot's avatar
OTB Bot committed
249
  bool        projectionInformationAvailable = !projectionRefWkt.empty();
250

251
  if (projectionInformationAvailable)
252
    {
253
    otbMsgDevMacro(<< "Projection information : " << projectionRefWkt);
254
    }
255
  else
256
    {
257
    otbMsgDevMacro(<< "Projection information unavailable");
258
    }
259

260
  //TODO georeference here from OGRSpatialReference http://www.gdal.org/ogr/classOGRDataSource.html
261
  OGRSpatialReference * oSRS = nullptr;
262 263
  if (projectionInformationAvailable)
    {
264
    oSRS = static_cast<OGRSpatialReference *>(OSRNewSpatialReference(projectionRefWkt.c_str()));
265 266
    }

267 268
  // Retrieving root node
  DataTreeConstPointerType tree = data->GetDataTree();
269
  if (tree->GetRoot() == nullptr)
270
    {
OTB Bot's avatar
OTB Bot committed
271
    itkExceptionMacro(<< "Data tree is empty: Root == NULL");
272
    }
273
  DataNodePointerType root = tree->GetRoot()->Get();
274

275
  unsigned int layerKept;
276
  OGRLayer *   ogrCurrentLayer = nullptr;
277
//   OGRFeatureVectorType ogrFeatures;
278
  OGRGeometryCollection * ogrCollection = nullptr;
279 280
  // OGRGeometry * ogrCurrentGeometry = NULL;

281 282
  // Get the input tree root
  InternalTreeNodeType * inputRoot = const_cast<InternalTreeNodeType *>(tree->GetRoot());
OTB Bot's avatar
OTB Bot committed
283

284
  //Refactoring SHPIO Manuel
285
  OGRIOHelper::Pointer IOConversion = OGRIOHelper::New();
286
  layerKept = IOConversion->ProcessNodeWrite(inputRoot, m_DataSource, ogrCollection, ogrCurrentLayer, oSRS);
287

288
  otbMsgDevMacro( << "layerKept " << layerKept );
289
  (void)layerKept; // keep compiler happy
290

291
  otb::ogr::version_proxy::Close(m_DataSource);
292
  m_DataSource = nullptr;
293

294
  if (oSRS != nullptr)
OTB Bot's avatar
OTB Bot committed
295
    {
296
    OSRRelease(oSRS);
OTB Bot's avatar
OTB Bot committed
297
    }
298

299
  chrono.Stop();
300
  otbMsgDevMacro( << "OGRVectorDataIO: file saved in " << chrono.GetElapsedMilliseconds() << " ms. (" << layerKept <<
Julien Malik's avatar
Julien Malik committed
301
  " elements)" );
302

OTB Bot's avatar
OTB Bot committed
303
  otbMsgDevMacro(<< " OGRVectorDataIO::Write()  ");
304
}
305

306

307
std::string
308
OGRVectorDataIO::GetOGRDriverName(std::string name) const
309 310 311
{
  std::string extension;
  std::string driverOGR;
OTB Bot's avatar
OTB Bot committed
312

313
  std::string upperName;
OTB Bot's avatar
OTB Bot committed
314 315 316
  upperName = name;
  std::transform(name.begin(), name.end(), upperName.begin(), (int (*)(int))toupper);

317
  //Test of PostGIS connection string
OTB Bot's avatar
OTB Bot committed
318 319 320 321
  if (upperName.substr(0, 3) == "PG:")
    {
    driverOGR = "PostgreSQL";
    }
322
  else
OTB Bot's avatar
OTB Bot committed
323
    {
324 325 326 327 328 329
    extension = itksys::SystemTools::GetFilenameLastExtension(upperName);
    if (extension == ".SHP") driverOGR = "ESRI Shapefile";
    else if ((extension == ".TAB")) driverOGR = "MapInfo File";
    else if (extension == ".GML") driverOGR = "GML";
    else if (extension == ".GPX") driverOGR = "GPX";
    else if (extension == ".SQLITE") driverOGR = "SQLite";
330 331
    else if (extension==".KML") driverOGR="KML";
    else if (extension == ".GMT") driverOGR = "OGR_GMT";
OTB Bot's avatar
OTB Bot committed
332 333
    else driverOGR = "NOT-FOUND";
    }
OTB Bot's avatar
OTB Bot committed
334
  //std::cout << name << " " << driverOGR <<" "<<upperName<< " "<< upperName.substr(0, 3) << std::endl;
335
  return driverOGR;
336
}
337

338
} // end namespace otb