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