Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: Program to generate a UMN MapServer compatible tile index for a
5 : * set of OGR data sources.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2002, Frank Warmerdam
10 : * Copyright (c) 2007-2010, Even Rouault <even dot rouault at spatialys.com>
11 : *
12 : * SPDX-License-Identifier: MIT
13 : ****************************************************************************/
14 :
15 : #include "cpl_port.h"
16 :
17 : #include <cassert>
18 : #include <vector>
19 :
20 : #include "cpl_conv.h"
21 : #include "cpl_string.h"
22 : #include "gdal_version.h"
23 : #include "gdalargumentparser.h"
24 : #include "ogr_api.h"
25 : #include "ogrsf_frmts.h"
26 : #include "commonutils.h"
27 :
28 : typedef enum
29 : {
30 : FORMAT_AUTO,
31 : FORMAT_WKT,
32 : FORMAT_EPSG,
33 : FORMAT_PROJ
34 : } SrcSRSFormat;
35 :
36 : /**
37 : * @brief Makes sure the GDAL library is properly cleaned up before exiting.
38 : * @param nCode exit code
39 : * @todo Move to API
40 : */
41 0 : static void GDALExit(int nCode)
42 : {
43 0 : GDALDestroy();
44 0 : exit(nCode);
45 : }
46 :
47 : /************************************************************************/
48 : /* main() */
49 : /************************************************************************/
50 :
51 8 : MAIN_START(nArgc, papszArgv)
52 :
53 : {
54 :
55 : // Check strict compilation and runtime library version as we use C++ API.
56 8 : if (!GDAL_CHECK_VERSION(papszArgv[0]))
57 0 : GDALExit(1);
58 :
59 8 : EarlySetConfigOptions(nArgc, papszArgv);
60 :
61 : /* -------------------------------------------------------------------- */
62 : /* Processing command line arguments. */
63 : /* -------------------------------------------------------------------- */
64 8 : bool bLayersWildcarded = true;
65 15 : std::string osOutputFormat;
66 15 : std::string osTileIndexField;
67 15 : std::string osOutputName;
68 8 : bool bWriteAbsolutePath{false};
69 8 : bool bSkipDifferentProjection{false};
70 8 : char *pszCurrentPath = nullptr;
71 8 : bool bAcceptDifferentSchemas{false};
72 8 : bool bFirstWarningForNonMatchingAttributes = true;
73 15 : std::string osTargetSRS;
74 8 : bool bSetTargetSRS = false;
75 15 : std::string osSrcSRSName;
76 8 : int i_SrcSRSName = -1;
77 8 : SrcSRSFormat eSrcSRSFormat = FORMAT_AUTO;
78 8 : size_t nMaxFieldSize = 254;
79 15 : std::vector<std::string> aosSrcDatasets;
80 15 : std::vector<std::string> aosLayerNames;
81 15 : std::vector<int> anLayerNumbers;
82 :
83 23 : GDALArgumentParser argParser{"ogrtindex", true};
84 :
85 : argParser.add_description(
86 : _("Program to generate a UMN MapServer compatible "
87 8 : "tile index for a set of OGR data sources."));
88 :
89 : argParser.add_epilog(
90 : _("For more details, see the full documentation for ogrtindex "
91 8 : "at\nhttps://gdal.org/programs/ogrtindex.html"));
92 :
93 8 : argParser.add_argument("-lnum")
94 16 : .metavar("<n>")
95 8 : .append()
96 8 : .scan<'i', int>()
97 8 : .store_into(anLayerNumbers)
98 : .help(
99 8 : _("Add layer number <n> from each source file in the tile index."));
100 :
101 8 : argParser.add_argument("-lname")
102 16 : .metavar("<name>")
103 8 : .append()
104 8 : .store_into(aosLayerNames)
105 : .help(_(
106 8 : "Add layer named <name> from each source file in the tile index."));
107 :
108 8 : argParser.add_output_format_argument(osOutputFormat);
109 :
110 8 : argParser.add_argument("-tileindex")
111 16 : .metavar("<tileindex>")
112 8 : .default_value("LOCATION")
113 8 : .nargs(1)
114 8 : .store_into(osTileIndexField)
115 8 : .help(_("Name to use for the dataset name."));
116 :
117 8 : argParser.add_argument("-write_absolute_path")
118 8 : .flag()
119 8 : .store_into(bWriteAbsolutePath)
120 8 : .help(_("Write absolute path of the source file in the tile index."));
121 :
122 8 : argParser.add_argument("-skip_different_projection")
123 8 : .flag()
124 8 : .store_into(bSkipDifferentProjection)
125 : .help(_("Skip layers that are not in the same projection as the first "
126 8 : "layer."));
127 :
128 8 : argParser.add_argument("-t_srs")
129 16 : .metavar("<srs_def>")
130 8 : .store_into(osTargetSRS)
131 : .help(
132 : _("Extent of input files will be transformed to the desired target "
133 8 : "coordinate reference system."));
134 :
135 8 : argParser.add_argument("-src_srs_name")
136 16 : .metavar("<field_name>")
137 8 : .store_into(osSrcSRSName)
138 8 : .help(_("Name of the field to store the SRS of each tile."));
139 :
140 8 : argParser.add_argument("-src_srs_format")
141 16 : .metavar("{AUTO|WKT|EPSG|PROJ}")
142 8 : .choices("AUTO", "WKT", "EPSG", "PROJ")
143 : .action(
144 8 : [&eSrcSRSFormat](const auto &f)
145 : {
146 4 : if (f == "WKT")
147 1 : eSrcSRSFormat = FORMAT_WKT;
148 3 : else if (f == "EPSG")
149 1 : eSrcSRSFormat = FORMAT_EPSG;
150 2 : else if (f == "PROJ")
151 1 : eSrcSRSFormat = FORMAT_PROJ;
152 : else
153 1 : eSrcSRSFormat = FORMAT_AUTO;
154 8 : })
155 8 : .help(_("Format of the source SRS to store in the tile index file."));
156 :
157 8 : argParser.add_argument("-accept_different_schemas")
158 8 : .flag()
159 8 : .store_into(bAcceptDifferentSchemas)
160 : .help(_(
161 8 : "Disable check for identical schemas for layers in input files."));
162 :
163 8 : argParser.add_argument("output_dataset")
164 16 : .metavar("<output_dataset>")
165 8 : .store_into(osOutputName)
166 8 : .help(_("Name of the output dataset."));
167 :
168 8 : argParser.add_argument("src_dataset")
169 16 : .metavar("<src_dataset>")
170 8 : .nargs(nargs_pattern::at_least_one)
171 8 : .store_into(aosSrcDatasets)
172 8 : .help(_("Name of the source dataset(s)."));
173 :
174 8 : CPLStringList aosArgv;
175 :
176 74 : for (int i = 0; i < nArgc; i++)
177 : {
178 66 : aosArgv.AddString(papszArgv[i]);
179 : }
180 :
181 : try
182 : {
183 8 : argParser.parse_args(aosArgv);
184 : }
185 0 : catch (const std::exception &e)
186 : {
187 0 : argParser.display_error_and_usage(e);
188 0 : GDALExit(1);
189 : }
190 :
191 : /* -------------------------------------------------------------------- */
192 : /* Validate input */
193 : /* -------------------------------------------------------------------- */
194 :
195 : //srs_name must be specified when srs_format is specified.
196 11 : if (argParser.is_used("-src_srs_format") &&
197 11 : !argParser.is_used("-src_srs_name"))
198 : {
199 0 : fprintf(stderr, "-src_srs_name must be specified when -src_srs_format "
200 : "is specified.\n");
201 0 : GDALExit(1);
202 : }
203 :
204 7 : bLayersWildcarded = aosLayerNames.empty() && anLayerNumbers.empty();
205 :
206 : /* -------------------------------------------------------------------- */
207 : /* Register format(s). */
208 : /* -------------------------------------------------------------------- */
209 7 : OGRRegisterAll();
210 :
211 : /* -------------------------------------------------------------------- */
212 : /* Create and validate target SRS if given. */
213 : /* -------------------------------------------------------------------- */
214 :
215 7 : OGRSpatialReference *poTargetSRS = nullptr;
216 :
217 7 : if (!osTargetSRS.empty())
218 : {
219 5 : if (bSkipDifferentProjection)
220 : {
221 0 : fprintf(stderr,
222 : "Warning : -skip_different_projection does not apply "
223 : "when -t_srs is requested.\n");
224 : }
225 5 : poTargetSRS = new OGRSpatialReference();
226 5 : poTargetSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
227 : // coverity[tainted_data]
228 5 : if (poTargetSRS->SetFromUserInput(osTargetSRS.c_str()) != CE_None)
229 : {
230 0 : delete poTargetSRS;
231 0 : fprintf(stderr, "Invalid target SRS `%s'.\n", osTargetSRS.c_str());
232 0 : GDALExit(1);
233 : }
234 5 : bSetTargetSRS = true;
235 : }
236 :
237 : /* -------------------------------------------------------------------- */
238 : /* Try to open as an existing dataset for update access. */
239 : /* -------------------------------------------------------------------- */
240 : GDALDataset *poDstDS =
241 7 : GDALDataset::FromHandle(OGROpen(osOutputName.c_str(), TRUE, nullptr));
242 :
243 : /* -------------------------------------------------------------------- */
244 : /* If that failed, find the driver so we can create the tile index.*/
245 : /* -------------------------------------------------------------------- */
246 7 : OGRLayer *poDstLayer = nullptr;
247 :
248 7 : if (poDstDS == nullptr)
249 : {
250 14 : CPLString osFormat;
251 7 : if (osOutputFormat.empty())
252 : {
253 : const auto aoDrivers =
254 12 : GetOutputDriversFor(osOutputName.c_str(), GDAL_OF_VECTOR);
255 6 : if (aoDrivers.empty())
256 : {
257 0 : CPLError(CE_Failure, CPLE_AppDefined,
258 : "Cannot guess driver for %s", osOutputName.c_str());
259 0 : GDALExit(10);
260 : }
261 : else
262 : {
263 6 : if (aoDrivers.size() > 1)
264 : {
265 0 : CPLError(CE_Warning, CPLE_AppDefined,
266 : "Several drivers matching %s extension. Using %s",
267 : CPLGetExtension(osOutputName.c_str()),
268 0 : aoDrivers[0].c_str());
269 : }
270 6 : osFormat = aoDrivers[0];
271 : }
272 : }
273 : else
274 : {
275 1 : osFormat = osOutputFormat;
276 : }
277 :
278 7 : if (!EQUAL(osFormat, "ESRI Shapefile"))
279 1 : nMaxFieldSize = 0;
280 :
281 7 : GDALDriverH hDriver = GDALGetDriverByName(osFormat.c_str());
282 7 : if (hDriver == nullptr)
283 : {
284 0 : GDALDriverManager *poDM = GetGDALDriverManager();
285 0 : for (int iDriver = 0; iDriver < poDM->GetDriverCount(); iDriver++)
286 : {
287 0 : fprintf(stderr, "Unable to find driver `%s'.\n",
288 : osFormat.c_str());
289 0 : fprintf(stderr, "The following drivers are available:\n");
290 :
291 0 : GDALDriver *poIter = poDM->GetDriver(iDriver);
292 0 : char **papszDriverMD = poIter->GetMetadata();
293 0 : if (CPLTestBool(CSLFetchNameValueDef(
294 0 : papszDriverMD, GDAL_DCAP_VECTOR, "FALSE")) &&
295 0 : CPLTestBool(CSLFetchNameValueDef(
296 : papszDriverMD, GDAL_DCAP_CREATE, "FALSE")))
297 : {
298 0 : fprintf(stderr, " -> `%s'\n", poIter->GetDescription());
299 : }
300 : }
301 0 : GDALExit(1);
302 : }
303 :
304 7 : if (!CPLTestBool(CSLFetchNameValueDef(GDALGetMetadata(hDriver, nullptr),
305 : GDAL_DCAP_CREATE, "FALSE")))
306 : {
307 0 : fprintf(stderr,
308 : "%s driver does not support data source creation.\n",
309 : osFormat.c_str());
310 0 : GDALExit(1);
311 : }
312 :
313 : /* --------------------------------------------------------------------
314 : */
315 : /* Now create it. */
316 : /* --------------------------------------------------------------------
317 : */
318 :
319 7 : poDstDS = GDALDataset::FromHandle(GDALCreate(
320 : hDriver, osOutputName.c_str(), 0, 0, 0, GDT_Unknown, nullptr));
321 7 : if (poDstDS == nullptr)
322 : {
323 0 : fprintf(stderr, "%s driver failed to create %s\n", osFormat.c_str(),
324 : osOutputName.c_str());
325 0 : GDALExit(1);
326 : }
327 :
328 7 : if (poDstDS->GetLayerCount() == 0)
329 : {
330 :
331 7 : OGRSpatialReference *poSrcSpatialRef = nullptr;
332 7 : if (bSetTargetSRS)
333 : {
334 : // Fetches the SRS from target SRS (if set), or from the SRS of
335 : // the first layer and use it when creating the
336 : // tileindex layer.
337 5 : poSrcSpatialRef = poTargetSRS->Clone();
338 : }
339 2 : else if (!aosSrcDatasets.empty())
340 : {
341 2 : GDALDataset *poDS = GDALDataset::FromHandle(
342 2 : OGROpen(aosSrcDatasets.front().c_str(), FALSE, nullptr));
343 2 : if (poDS != nullptr)
344 : {
345 2 : for (int iLayer = 0; iLayer < poDS->GetLayerCount();
346 : iLayer++)
347 : {
348 2 : bool bRequested = bLayersWildcarded;
349 2 : OGRLayer *poLayer = poDS->GetLayer(iLayer);
350 :
351 2 : if (!bRequested)
352 : {
353 0 : if (std::find(anLayerNumbers.cbegin(),
354 : anLayerNumbers.cend(),
355 0 : iLayer) != anLayerNumbers.cend())
356 0 : bRequested = true;
357 0 : else if (std::find(
358 : aosLayerNames.cbegin(),
359 : aosLayerNames.cend(),
360 0 : poLayer->GetLayerDefn()->GetName()) !=
361 0 : aosLayerNames.cend())
362 0 : bRequested = true;
363 : }
364 :
365 2 : if (!bRequested)
366 0 : continue;
367 :
368 2 : if (poLayer->GetSpatialRef())
369 1 : poSrcSpatialRef = poLayer->GetSpatialRef()->Clone();
370 2 : break;
371 : }
372 : }
373 :
374 2 : GDALClose(poDS);
375 : }
376 :
377 7 : poDstLayer = poDstDS->CreateLayer("tileindex", poSrcSpatialRef);
378 :
379 14 : OGRFieldDefn oLocation(osTileIndexField.c_str(), OFTString);
380 7 : oLocation.SetWidth(200);
381 7 : poDstLayer->CreateField(&oLocation);
382 :
383 7 : if (!osSrcSRSName.empty())
384 : {
385 10 : OGRFieldDefn oSrcSRSNameField(osSrcSRSName.c_str(), OFTString);
386 5 : poDstLayer->CreateField(&oSrcSRSNameField);
387 : }
388 :
389 7 : if (poSrcSpatialRef)
390 6 : poSrcSpatialRef->Release();
391 : }
392 : }
393 :
394 : /* -------------------------------------------------------------------- */
395 : /* Identify target layer and field. */
396 : /* -------------------------------------------------------------------- */
397 :
398 7 : poDstLayer = poDstDS->GetLayer(0);
399 7 : if (poDstLayer == nullptr)
400 : {
401 0 : fprintf(stderr, "Can't find any layer in output tileindex!\n");
402 0 : GDALExit(1);
403 : }
404 :
405 : const int iTileIndexField =
406 7 : poDstLayer->GetLayerDefn()->GetFieldIndex(osTileIndexField.c_str());
407 7 : if (iTileIndexField == -1)
408 : {
409 0 : fprintf(stderr, "Can't find %s field in tile index dataset.\n",
410 : osTileIndexField.c_str());
411 0 : GDALExit(1);
412 : }
413 :
414 7 : if (!osSrcSRSName.empty())
415 : i_SrcSRSName =
416 5 : poDstLayer->GetLayerDefn()->GetFieldIndex(osSrcSRSName.c_str());
417 :
418 7 : OGRFeatureDefn *poFeatureDefn = nullptr;
419 :
420 : // Load in memory existing file names in SHP.
421 7 : char **existingLayersTab = nullptr;
422 7 : OGRSpatialReference *alreadyExistingSpatialRef = nullptr;
423 7 : bool alreadyExistingSpatialRefValid = false;
424 7 : const int nExistingLayers = static_cast<int>(poDstLayer->GetFeatureCount());
425 7 : if (nExistingLayers)
426 : {
427 : existingLayersTab =
428 0 : static_cast<char **>(CPLMalloc(nExistingLayers * sizeof(char *)));
429 0 : for (int i = 0; i < nExistingLayers; i++)
430 : {
431 0 : OGRFeature *feature = poDstLayer->GetNextFeature();
432 0 : existingLayersTab[i] =
433 0 : CPLStrdup(feature->GetFieldAsString(iTileIndexField));
434 0 : if (i == 0)
435 : {
436 0 : char *filename = CPLStrdup(existingLayersTab[i]);
437 : // j used after for.
438 0 : int j = static_cast<int>(strlen(filename)) - 1;
439 0 : for (; j >= 0; j--)
440 : {
441 0 : if (filename[j] == ',')
442 0 : break;
443 : }
444 0 : GDALDataset *poDS = nullptr;
445 0 : if (j >= 0)
446 : {
447 0 : const int iLayer = atoi(filename + j + 1);
448 0 : filename[j] = 0;
449 0 : poDS = GDALDataset::FromHandle(
450 0 : OGROpen(filename, FALSE, nullptr));
451 0 : if (poDS != nullptr)
452 : {
453 0 : OGRLayer *poLayer = poDS->GetLayer(iLayer);
454 0 : if (poLayer)
455 : {
456 0 : alreadyExistingSpatialRefValid = true;
457 0 : alreadyExistingSpatialRef =
458 0 : poLayer->GetSpatialRef()
459 0 : ? poLayer->GetSpatialRef()->Clone()
460 : : nullptr;
461 :
462 0 : if (poFeatureDefn == nullptr)
463 : poFeatureDefn =
464 0 : poLayer->GetLayerDefn()->Clone();
465 : }
466 0 : GDALClose(poDS);
467 : }
468 : }
469 : }
470 : }
471 : }
472 :
473 7 : if (bWriteAbsolutePath)
474 : {
475 0 : pszCurrentPath = CPLGetCurrentDir();
476 0 : if (pszCurrentPath == nullptr)
477 : {
478 0 : fprintf(stderr,
479 : "This system does not support the CPLGetCurrentDir call. "
480 : "The option -write_absolute_path will have no effect\n");
481 0 : bWriteAbsolutePath = false;
482 : }
483 : }
484 : /* ==================================================================== */
485 : /* Process each input datasource in turn. */
486 : /* ==================================================================== */
487 25 : for (const auto &srcDataSet : aosSrcDatasets)
488 : {
489 :
490 18 : char *fileNameToWrite = nullptr;
491 : VSIStatBuf sStatBuf;
492 :
493 18 : if (bWriteAbsolutePath && CPLIsFilenameRelative(srcDataSet.c_str()) &&
494 0 : VSIStat(srcDataSet.c_str(), &sStatBuf) == 0)
495 : {
496 0 : fileNameToWrite = CPLStrdup(
497 : CPLProjectRelativeFilename(pszCurrentPath, srcDataSet.c_str()));
498 : }
499 : else
500 : {
501 18 : fileNameToWrite = CPLStrdup(srcDataSet.c_str());
502 : }
503 :
504 18 : GDALDataset *poDS = GDALDataset::FromHandle(
505 18 : OGROpen(srcDataSet.c_str(), FALSE, nullptr));
506 :
507 18 : if (poDS == nullptr)
508 : {
509 0 : fprintf(stderr, "Failed to open dataset %s, skipping.\n",
510 : srcDataSet.c_str());
511 0 : CPLFree(fileNameToWrite);
512 0 : continue;
513 : }
514 :
515 : /* ----------------------------------------------------------------- */
516 : /* Check all layers, and see if they match requests. */
517 : /* ----------------------------------------------------------------- */
518 :
519 36 : for (int iLayer = 0; iLayer < poDS->GetLayerCount(); iLayer++)
520 : {
521 18 : bool bRequested = bLayersWildcarded;
522 18 : OGRLayer *poLayer = poDS->GetLayer(iLayer);
523 :
524 18 : if (!bRequested)
525 : {
526 0 : if (std::find(anLayerNumbers.cbegin(), anLayerNumbers.cend(),
527 0 : iLayer) != anLayerNumbers.cend())
528 0 : bRequested = true;
529 0 : else if (std::find(aosLayerNames.cbegin(), aosLayerNames.cend(),
530 0 : poLayer->GetLayerDefn()->GetName()) !=
531 0 : aosLayerNames.cend())
532 0 : bRequested = true;
533 : }
534 :
535 18 : if (!bRequested)
536 0 : continue;
537 :
538 : // Checks that the layer is not already in tileindex.
539 18 : int i = 0; // Used after for.
540 18 : for (; i < nExistingLayers; i++)
541 : {
542 : // TODO(schwehr): Move this off of the stack.
543 0 : char szLocation[5000] = {};
544 0 : snprintf(szLocation, sizeof(szLocation), "%s,%d",
545 : fileNameToWrite, iLayer);
546 0 : if (EQUAL(szLocation, existingLayersTab[i]))
547 : {
548 0 : fprintf(stderr,
549 : "Layer %d of %s is already in tileindex. "
550 : "Skipping it.\n",
551 : iLayer, srcDataSet.c_str());
552 0 : break;
553 : }
554 : }
555 18 : if (i != nExistingLayers)
556 : {
557 0 : continue;
558 : }
559 :
560 18 : OGRSpatialReference *spatialRef = poLayer->GetSpatialRef();
561 : // If not set target srs, test that the current file uses same
562 : // projection as others.
563 18 : if (!bSetTargetSRS)
564 : {
565 8 : if (alreadyExistingSpatialRefValid)
566 : {
567 3 : if ((spatialRef != nullptr &&
568 3 : alreadyExistingSpatialRef != nullptr &&
569 3 : spatialRef->IsSame(alreadyExistingSpatialRef) ==
570 12 : FALSE) ||
571 6 : ((spatialRef != nullptr) !=
572 6 : (alreadyExistingSpatialRef != nullptr)))
573 : {
574 0 : fprintf(
575 : stderr,
576 : "Warning : layer %d of %s is not using the same "
577 : "projection system as other files in the "
578 : "tileindex. This may cause problems when using it "
579 : "in MapServer for example.%s\n",
580 : iLayer, srcDataSet.c_str(),
581 : bSkipDifferentProjection ? " Skipping it" : "");
582 0 : if (bSkipDifferentProjection)
583 : {
584 0 : continue;
585 : }
586 : }
587 : }
588 : else
589 : {
590 2 : alreadyExistingSpatialRefValid = true;
591 2 : alreadyExistingSpatialRef =
592 2 : spatialRef ? spatialRef->Clone() : nullptr;
593 : }
594 : }
595 :
596 : /* ------------------------------------------------------------------ */
597 : /* Check if all layers in dataset have the same attributes schema. */
598 : /* ------------------------------------------------------------------ */
599 :
600 18 : if (poFeatureDefn == nullptr)
601 : {
602 7 : poFeatureDefn = poLayer->GetLayerDefn()->Clone();
603 : }
604 11 : else if (!bAcceptDifferentSchemas)
605 : {
606 11 : OGRFeatureDefn *poFeatureDefnCur = poLayer->GetLayerDefn();
607 11 : assert(nullptr != poFeatureDefnCur);
608 :
609 11 : const int fieldCount = poFeatureDefnCur->GetFieldCount();
610 :
611 11 : if (fieldCount != poFeatureDefn->GetFieldCount())
612 : {
613 0 : fprintf(stderr,
614 : "Number of attributes of layer %s of %s "
615 : "does not match ... skipping it.\n",
616 0 : poLayer->GetLayerDefn()->GetName(),
617 : srcDataSet.c_str());
618 0 : if (bFirstWarningForNonMatchingAttributes)
619 : {
620 0 : fprintf(
621 : stderr,
622 : "Note : you can override this "
623 : "behavior with -accept_different_schemas option\n"
624 : "but this may result in a tileindex incompatible "
625 : "with MapServer\n");
626 0 : bFirstWarningForNonMatchingAttributes = false;
627 : }
628 0 : continue;
629 : }
630 :
631 11 : bool bSkip = false;
632 22 : for (int fn = 0; fn < poFeatureDefnCur->GetFieldCount(); fn++)
633 : {
634 11 : OGRFieldDefn *poField = poFeatureDefn->GetFieldDefn(fn);
635 : OGRFieldDefn *poFieldCur =
636 11 : poFeatureDefnCur->GetFieldDefn(fn);
637 :
638 : // XXX - Should those pointers be checked against NULL?
639 11 : assert(nullptr != poField);
640 11 : assert(nullptr != poFieldCur);
641 :
642 22 : if (poField->GetType() != poFieldCur->GetType() ||
643 22 : poField->GetWidth() != poFieldCur->GetWidth() ||
644 33 : poField->GetPrecision() != poFieldCur->GetPrecision() ||
645 11 : !EQUAL(poField->GetNameRef(), poFieldCur->GetNameRef()))
646 : {
647 0 : fprintf(stderr,
648 : "Schema of attributes of layer %s of %s "
649 : "does not match. Skipping it.\n",
650 0 : poLayer->GetLayerDefn()->GetName(),
651 : srcDataSet.c_str());
652 0 : if (bFirstWarningForNonMatchingAttributes)
653 : {
654 0 : fprintf(
655 : stderr,
656 : "Note : you can override this "
657 : "behavior with -accept_different_schemas "
658 : "option,\nbut this may result in a tileindex "
659 : "incompatible with MapServer\n");
660 0 : bFirstWarningForNonMatchingAttributes = false;
661 : }
662 0 : bSkip = true;
663 0 : break;
664 : }
665 : }
666 :
667 11 : if (bSkip)
668 0 : continue;
669 : }
670 :
671 : /* ----------------------------------------------------------------- */
672 : /* Get layer extents, and create a corresponding polygon */
673 : /* geometry. */
674 : /* ----------------------------------------------------------------- */
675 18 : OGREnvelope sExtents;
676 :
677 18 : if (poLayer->GetExtent(&sExtents, TRUE) != OGRERR_NONE)
678 : {
679 0 : fprintf(stderr,
680 : "GetExtent() failed on layer %s of %s, skipping.\n",
681 0 : poLayer->GetLayerDefn()->GetName(), srcDataSet.c_str());
682 0 : continue;
683 : }
684 :
685 18 : OGRLinearRing oRing;
686 18 : oRing.addPoint(sExtents.MinX, sExtents.MinY);
687 18 : oRing.addPoint(sExtents.MinX, sExtents.MaxY);
688 18 : oRing.addPoint(sExtents.MaxX, sExtents.MaxY);
689 18 : oRing.addPoint(sExtents.MaxX, sExtents.MinY);
690 18 : oRing.addPoint(sExtents.MinX, sExtents.MinY);
691 :
692 18 : OGRPolygon oRegion;
693 18 : oRegion.addRing(&oRing);
694 :
695 : // If set target srs, do the forward transformation of all points.
696 18 : if (bSetTargetSRS && spatialRef != nullptr)
697 : {
698 10 : if (!spatialRef->IsSame(poTargetSRS))
699 : {
700 : auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
701 : OGRCreateCoordinateTransformation(spatialRef,
702 5 : poTargetSRS));
703 10 : if (poCT == nullptr ||
704 5 : oRegion.transform(poCT.get()) == OGRERR_FAILURE)
705 : {
706 0 : char *pszSourceWKT = nullptr;
707 0 : spatialRef->exportToWkt(&pszSourceWKT);
708 0 : fprintf(
709 : stderr,
710 : "Warning : unable to transform points from source "
711 : "SRS `%s' to target SRS `%s'\n"
712 : "for file `%s' - file skipped\n",
713 : pszSourceWKT, osTargetSRS.c_str(),
714 : srcDataSet.c_str());
715 0 : CPLFree(pszSourceWKT);
716 0 : continue;
717 : }
718 : }
719 : }
720 :
721 : /* ---------------------------------------------------------------- */
722 : /* Add layer to tileindex. */
723 : /* ---------------------------------------------------------------- */
724 36 : OGRFeature oTileFeat(poDstLayer->GetLayerDefn());
725 :
726 : // TODO(schwehr): Move this off of the stack.
727 18 : char szLocation[5000] = {};
728 18 : snprintf(szLocation, sizeof(szLocation), "%s,%d", fileNameToWrite,
729 : iLayer);
730 18 : oTileFeat.SetGeometry(&oRegion);
731 18 : oTileFeat.SetField(iTileIndexField, szLocation);
732 :
733 18 : if (i_SrcSRSName >= 0 && spatialRef != nullptr)
734 : {
735 : const char *pszAuthorityCode =
736 10 : spatialRef->GetAuthorityCode(nullptr);
737 : const char *pszAuthorityName =
738 10 : spatialRef->GetAuthorityName(nullptr);
739 10 : char *pszWKT = nullptr;
740 10 : spatialRef->exportToWkt(&pszWKT);
741 10 : if (eSrcSRSFormat == FORMAT_AUTO)
742 : {
743 4 : if (pszAuthorityName != nullptr &&
744 : pszAuthorityCode != nullptr)
745 : {
746 4 : oTileFeat.SetField(i_SrcSRSName,
747 : CPLSPrintf("%s:%s", pszAuthorityName,
748 : pszAuthorityCode));
749 : }
750 0 : else if (nMaxFieldSize == 0 ||
751 0 : strlen(pszWKT) <= nMaxFieldSize)
752 : {
753 0 : oTileFeat.SetField(i_SrcSRSName, pszWKT);
754 : }
755 : else
756 : {
757 0 : char *pszProj4 = nullptr;
758 0 : if (spatialRef->exportToProj4(&pszProj4) == OGRERR_NONE)
759 : {
760 0 : oTileFeat.SetField(i_SrcSRSName, pszProj4);
761 0 : CPLFree(pszProj4);
762 : }
763 : else
764 : {
765 0 : oTileFeat.SetField(i_SrcSRSName, pszWKT);
766 : }
767 : }
768 : }
769 6 : else if (eSrcSRSFormat == FORMAT_WKT)
770 : {
771 2 : if (nMaxFieldSize == 0 || strlen(pszWKT) <= nMaxFieldSize)
772 : {
773 2 : oTileFeat.SetField(i_SrcSRSName, pszWKT);
774 : }
775 : else
776 : {
777 0 : fprintf(
778 : stderr,
779 : "Cannot write WKT for file %s as it is too long!\n",
780 : fileNameToWrite);
781 : }
782 : }
783 4 : else if (eSrcSRSFormat == FORMAT_PROJ)
784 : {
785 2 : char *pszProj4 = nullptr;
786 2 : if (spatialRef->exportToProj4(&pszProj4) == OGRERR_NONE)
787 : {
788 2 : oTileFeat.SetField(i_SrcSRSName, pszProj4);
789 2 : CPLFree(pszProj4);
790 : }
791 : }
792 2 : else if (eSrcSRSFormat == FORMAT_EPSG)
793 : {
794 2 : if (pszAuthorityName != nullptr &&
795 : pszAuthorityCode != nullptr)
796 2 : oTileFeat.SetField(i_SrcSRSName,
797 : CPLSPrintf("%s:%s", pszAuthorityName,
798 : pszAuthorityCode));
799 : }
800 10 : CPLFree(pszWKT);
801 : }
802 18 : if (poDstLayer->CreateFeature(&oTileFeat) != OGRERR_NONE)
803 : {
804 0 : fprintf(stderr, "Failed to create feature on tile index. "
805 : "Terminating.");
806 0 : GDALClose(poDstDS);
807 0 : exit(1);
808 : }
809 : }
810 :
811 : /* ---------------------------------------------------------------- */
812 : /* Cleanup this data source. */
813 : /* ---------------------------------------------------------------- */
814 18 : CPLFree(fileNameToWrite);
815 18 : GDALClose(poDS);
816 : }
817 :
818 : /* -------------------------------------------------------------------- */
819 : /* Close tile index and clear buffers. */
820 : /* -------------------------------------------------------------------- */
821 7 : int nRetCode = 0;
822 7 : if (GDALClose(poDstDS) != CE_None)
823 0 : nRetCode = 1;
824 7 : OGRFeatureDefn::DestroyFeatureDefn(poFeatureDefn);
825 :
826 7 : if (alreadyExistingSpatialRef != nullptr)
827 1 : alreadyExistingSpatialRef->Release();
828 7 : delete poTargetSRS;
829 :
830 7 : CPLFree(pszCurrentPath);
831 :
832 7 : if (nExistingLayers)
833 : {
834 0 : for (int i = 0; i < nExistingLayers; i++)
835 : {
836 0 : CPLFree(existingLayersTab[i]);
837 : }
838 0 : CPLFree(existingLayersTab);
839 : }
840 :
841 7 : GDALDestroy();
842 :
843 7 : return nRetCode;
844 : }
845 :
846 0 : MAIN_END
|