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