1 : /******************************************************************************
2 : * $Id: ntf_generic.cpp 10645 2007-01-18 02:22:39Z warmerdam $
3 : *
4 : * Project: NTF Translator
5 : * Purpose: Handle NTF products that aren't recognised generically.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1999, Frank Warmerdam
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include <stdarg.h>
31 : #include "ntf.h"
32 : #include "cpl_string.h"
33 :
34 : CPL_CVSID("$Id: ntf_generic.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
35 :
36 : #define MAX_LINK 5000
37 :
38 : /************************************************************************/
39 : /* ==================================================================== */
40 : /* NTFGenericClass */
41 : /* */
42 : /* The NTFGenericClass class exists to hold aggregated */
43 : /* information for each type of record encountered in a set of */
44 : /* NTF files, primarily the list of attributes actually */
45 : /* encountered. */
46 : /* ==================================================================== */
47 : /************************************************************************/
48 :
49 : /************************************************************************/
50 : /* NTFGenericClass */
51 : /************************************************************************/
52 :
53 29700 : NTFGenericClass::NTFGenericClass()
54 : {
55 29700 : nFeatureCount = 0;
56 :
57 29700 : b3D = FALSE;
58 29700 : nAttrCount = 0;
59 29700 : papszAttrNames = NULL;
60 29700 : papszAttrFormats = NULL;
61 29700 : panAttrMaxWidth = NULL;
62 29700 : pabAttrMultiple = NULL;
63 29700 : }
64 :
65 : /************************************************************************/
66 : /* ~NTFGenericClass */
67 : /************************************************************************/
68 :
69 29700 : NTFGenericClass::~NTFGenericClass()
70 :
71 : {
72 29700 : CSLDestroy( papszAttrNames );
73 29700 : CSLDestroy( papszAttrFormats );
74 29700 : CPLFree( panAttrMaxWidth );
75 29700 : CPLFree( pabAttrMultiple );
76 29700 : }
77 :
78 : /************************************************************************/
79 : /* CheckAddAttr() */
80 : /* */
81 : /* Check if an attribute already exists. If not add it with */
82 : /* it's format. Note we don't check for format conflicts at */
83 : /* this time. */
84 : /************************************************************************/
85 :
86 : void NTFGenericClass::CheckAddAttr( const char * pszName,
87 : const char * pszFormat,
88 0 : int nWidth )
89 :
90 : {
91 : int iAttrOffset;
92 :
93 0 : if( EQUAL(pszName,"TX") )
94 0 : pszName = "TEXT";
95 0 : if( EQUAL(pszName,"FC") )
96 0 : pszName = "FEAT_CODE";
97 :
98 0 : iAttrOffset = CSLFindString( papszAttrNames, pszName );
99 :
100 0 : if( iAttrOffset == -1 )
101 : {
102 0 : nAttrCount++;
103 :
104 0 : papszAttrNames = CSLAddString( papszAttrNames, pszName );
105 0 : papszAttrFormats = CSLAddString( papszAttrFormats, pszFormat );
106 :
107 : panAttrMaxWidth = (int *)
108 0 : CPLRealloc( panAttrMaxWidth, sizeof(int) * nAttrCount );
109 :
110 0 : panAttrMaxWidth[nAttrCount-1] = nWidth;
111 :
112 : pabAttrMultiple = (int *)
113 0 : CPLRealloc( pabAttrMultiple, sizeof(int) * nAttrCount );
114 :
115 0 : pabAttrMultiple[nAttrCount-1] = FALSE;
116 : }
117 : else
118 : {
119 0 : if( panAttrMaxWidth[iAttrOffset] < nWidth )
120 0 : panAttrMaxWidth[iAttrOffset] = nWidth;
121 : }
122 0 : }
123 :
124 : /************************************************************************/
125 : /* SetMultiple() */
126 : /* */
127 : /* Mark this attribute as appearing multiple times on some */
128 : /* features. */
129 : /************************************************************************/
130 :
131 0 : void NTFGenericClass::SetMultiple( const char *pszName )
132 :
133 : {
134 : int iAttrOffset;
135 :
136 0 : if( EQUAL(pszName,"TX") )
137 0 : pszName = "TEXT";
138 0 : if( EQUAL(pszName,"FC") )
139 0 : pszName = "FEAT_CODE";
140 :
141 0 : iAttrOffset = CSLFindString( papszAttrNames, pszName );
142 0 : if( iAttrOffset == -1 )
143 0 : return;
144 :
145 0 : pabAttrMultiple[iAttrOffset] = TRUE;
146 : }
147 :
148 : /************************************************************************/
149 : /* WorkupGeneric() */
150 : /* */
151 : /* Scan a whole file, in order to build up a list of attributes */
152 : /* for the generic types. */
153 : /************************************************************************/
154 :
155 0 : void OGRNTFDataSource::WorkupGeneric( NTFFileReader * poReader )
156 :
157 : {
158 0 : NTFRecord **papoGroup = NULL;
159 :
160 0 : if( poReader->GetNTFLevel() > 2 )
161 : {
162 0 : poReader->IndexFile();
163 0 : if( CPLGetLastErrorType() == CE_Failure )
164 0 : return;
165 : }
166 : else
167 0 : poReader->Reset();
168 :
169 : /* ==================================================================== */
170 : /* Read all record groups in the file. */
171 : /* ==================================================================== */
172 0 : while( TRUE )
173 : {
174 : /* -------------------------------------------------------------------- */
175 : /* Read a record group */
176 : /* -------------------------------------------------------------------- */
177 0 : if( poReader->GetNTFLevel() > 2 )
178 0 : papoGroup = poReader->GetNextIndexedRecordGroup(papoGroup);
179 : else
180 0 : papoGroup = poReader->ReadRecordGroup();
181 :
182 0 : if( papoGroup == NULL || papoGroup[0]->GetType() == 99 )
183 0 : break;
184 :
185 : /* -------------------------------------------------------------------- */
186 : /* Get the class corresponding to the anchor record. */
187 : /* -------------------------------------------------------------------- */
188 0 : NTFGenericClass *poClass = GetGClass( papoGroup[0]->GetType() );
189 0 : char **papszFullAttList = NULL;
190 :
191 0 : poClass->nFeatureCount++;
192 :
193 : /* -------------------------------------------------------------------- */
194 : /* Loop over constituent records collecting attributes. */
195 : /* -------------------------------------------------------------------- */
196 0 : for( int iRec = 0; papoGroup[iRec] != NULL; iRec++ )
197 : {
198 0 : NTFRecord *poRecord = papoGroup[iRec];
199 :
200 0 : switch( poRecord->GetType() )
201 : {
202 : case NRT_ATTREC:
203 : {
204 : char **papszTypes, **papszValues;
205 :
206 : poReader->ProcessAttRec( poRecord, NULL,
207 0 : &papszTypes, &papszValues );
208 :
209 0 : for( int iAtt = 0; papszTypes[iAtt] != NULL; iAtt++ )
210 : {
211 : NTFAttDesc *poAttDesc;
212 :
213 0 : poAttDesc = poReader->GetAttDesc( papszTypes[iAtt] );
214 0 : if( poAttDesc != NULL )
215 : {
216 : poClass->CheckAddAttr( poAttDesc->val_type,
217 : poAttDesc->finter,
218 0 : strlen(papszValues[iAtt]) );
219 : }
220 :
221 0 : if( CSLFindString( papszFullAttList,
222 : papszTypes[iAtt] ) == -1 )
223 : papszFullAttList =
224 : CSLAddString( papszFullAttList,
225 0 : papszTypes[iAtt] );
226 : else
227 0 : poClass->SetMultiple( poAttDesc->val_type );
228 : }
229 :
230 0 : CSLDestroy( papszTypes );
231 0 : CSLDestroy( papszValues );
232 : }
233 0 : break;
234 :
235 : case NRT_TEXTREP:
236 : case NRT_NAMEPOSTN:
237 0 : poClass->CheckAddAttr( "FONT", "I4", 4 );
238 0 : poClass->CheckAddAttr( "TEXT_HT", "R3,1", 3 );
239 0 : poClass->CheckAddAttr( "TEXT_HT_GROUND", "R9,3", 9 );
240 0 : poClass->CheckAddAttr( "TEXT_HT", "R3,1", 3 );
241 0 : poClass->CheckAddAttr( "DIG_POSTN", "I1", 1 );
242 0 : poClass->CheckAddAttr( "ORIENT", "R4,1", 4 );
243 0 : break;
244 :
245 : case NRT_NAMEREC:
246 : poClass->CheckAddAttr( "TEXT", "A*",
247 0 : atoi(poRecord->GetField(13,14)) );
248 0 : break;
249 :
250 : case NRT_GEOMETRY:
251 : case NRT_GEOMETRY3D:
252 0 : if( atoi(poRecord->GetField(3,8)) != 0 )
253 0 : poClass->CheckAddAttr( "GEOM_ID", "I6", 6 );
254 0 : if( poRecord->GetType() == NRT_GEOMETRY3D )
255 0 : poClass->b3D = TRUE;
256 0 : break;
257 :
258 : case NRT_POINTREC:
259 : case NRT_LINEREC:
260 0 : if( poReader->GetNTFLevel() < 3 )
261 : {
262 : NTFAttDesc *poAttDesc;
263 :
264 0 : poAttDesc = poReader->GetAttDesc(poRecord->GetField(9,10));
265 0 : if( poAttDesc != NULL )
266 : poClass->CheckAddAttr( poAttDesc->val_type,
267 0 : poAttDesc->finter, 6 );
268 :
269 0 : if( !EQUAL(poRecord->GetField(17,20)," ") )
270 0 : poClass->CheckAddAttr( "FEAT_CODE", "A4", 4 );
271 : }
272 : break;
273 :
274 : default:
275 : break;
276 : }
277 : }
278 :
279 0 : CSLDestroy( papszFullAttList );
280 : }
281 :
282 0 : if( GetOption("CACHING") != NULL
283 : && EQUAL(GetOption("CACHING"),"OFF") )
284 0 : poReader->DestroyIndex();
285 :
286 0 : poReader->Reset();
287 : }
288 :
289 : /************************************************************************/
290 : /* AddGenericAttributes() */
291 : /************************************************************************/
292 :
293 : static void AddGenericAttributes( NTFFileReader * poReader,
294 : NTFRecord **papoGroup,
295 0 : OGRFeature * poFeature )
296 :
297 : {
298 : char **papszTypes, **papszValues;
299 :
300 0 : if( !poReader->ProcessAttRecGroup( papoGroup, &papszTypes, &papszValues ) )
301 0 : return;
302 :
303 0 : for( int iAtt = 0; papszTypes != NULL && papszTypes[iAtt] != NULL; iAtt++ )
304 : {
305 : int iField;
306 :
307 0 : if( EQUAL(papszTypes[iAtt],"TX") )
308 0 : iField = poFeature->GetFieldIndex("TEXT");
309 0 : else if( EQUAL(papszTypes[iAtt],"FC") )
310 0 : iField = poFeature->GetFieldIndex("FEAT_CODE");
311 : else
312 0 : iField = poFeature->GetFieldIndex(papszTypes[iAtt]);
313 :
314 0 : if( iField == -1 )
315 0 : continue;
316 :
317 : poReader->ApplyAttributeValue( poFeature, iField, papszTypes[iAtt],
318 0 : papszTypes, papszValues );
319 :
320 : /* -------------------------------------------------------------------- */
321 : /* Do we have a corresponding list field we should be */
322 : /* accumulating this into? */
323 : /* -------------------------------------------------------------------- */
324 : char szListName[128];
325 : int iListField;
326 :
327 : sprintf( szListName, "%s_LIST",
328 0 : poFeature->GetFieldDefnRef(iField)->GetNameRef() );
329 0 : iListField = poFeature->GetFieldIndex( szListName );
330 :
331 : /* -------------------------------------------------------------------- */
332 : /* Yes, so perform processing similar to ApplyAttributeValue(), */
333 : /* and append to list value. */
334 : /* -------------------------------------------------------------------- */
335 0 : if( iListField != -1 )
336 : {
337 : char *pszAttLongName, *pszAttValue, *pszCodeDesc;
338 :
339 : poReader->ProcessAttValue( papszTypes[iAtt], papszValues[iAtt],
340 : &pszAttLongName, &pszAttValue,
341 0 : &pszCodeDesc );
342 :
343 0 : if( poFeature->IsFieldSet( iListField ) )
344 : {
345 : poFeature->SetField( iListField,
346 : CPLSPrintf( "%s,%s",
347 : poFeature->GetFieldAsString( iListField ),
348 0 : pszAttValue ) );
349 : }
350 : else
351 : {
352 0 : poFeature->SetField( iListField, pszAttValue );
353 : }
354 : }
355 : }
356 :
357 0 : CSLDestroy( papszTypes );
358 0 : CSLDestroy( papszValues );
359 : }
360 :
361 : /************************************************************************/
362 : /* TranslateGenericNode() */
363 : /************************************************************************/
364 :
365 : static OGRFeature *TranslateGenericNode( NTFFileReader *poReader,
366 : OGRNTFLayer *poLayer,
367 0 : NTFRecord **papoGroup )
368 :
369 : {
370 0 : if( CSLCount((char **) papoGroup) < 2
371 : || papoGroup[0]->GetType() != NRT_NODEREC
372 : || (papoGroup[1]->GetType() != NRT_GEOMETRY
373 : && papoGroup[1]->GetType() != NRT_GEOMETRY3D) )
374 : {
375 0 : return NULL;
376 : }
377 :
378 0 : OGRFeature *poFeature = new OGRFeature( poLayer->GetLayerDefn() );
379 :
380 : // NODE_ID
381 0 : poFeature->SetField( "NODE_ID", atoi(papoGroup[0]->GetField( 3, 8 )) );
382 :
383 : // Geometry
384 0 : poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1]));
385 0 : poFeature->SetField( "GEOM_ID", papoGroup[1]->GetField(3,8) );
386 :
387 : // NUM_LINKS
388 0 : int nLinkCount=0;
389 0 : int *panLinks = NULL;
390 :
391 0 : if( papoGroup[0]->GetLength() > 18 )
392 : {
393 0 : nLinkCount = atoi(papoGroup[0]->GetField(15,18));
394 0 : panLinks = (int *) CPLCalloc(sizeof(int),nLinkCount);
395 : }
396 :
397 0 : poFeature->SetField( "NUM_LINKS", nLinkCount );
398 :
399 : // GEOM_ID_OF_LINK
400 : int iLink;
401 0 : for( iLink = 0; iLink < nLinkCount; iLink++ )
402 : panLinks[iLink] = atoi(papoGroup[0]->GetField(20+iLink*12,
403 0 : 25+iLink*12));
404 :
405 0 : poFeature->SetField( "GEOM_ID_OF_LINK", nLinkCount, panLinks );
406 :
407 : // DIR
408 0 : for( iLink = 0; iLink < nLinkCount; iLink++ )
409 : panLinks[iLink] = atoi(papoGroup[0]->GetField(19+iLink*12,
410 0 : 19+iLink*12));
411 :
412 0 : poFeature->SetField( "DIR", nLinkCount, panLinks );
413 :
414 : // should we add LEVEL and/or ORIENT?
415 :
416 0 : CPLFree( panLinks );
417 :
418 0 : return poFeature;
419 : }
420 :
421 : /************************************************************************/
422 : /* TranslateGenericCollection() */
423 : /************************************************************************/
424 :
425 : static OGRFeature *TranslateGenericCollection( NTFFileReader *poReader,
426 : OGRNTFLayer *poLayer,
427 0 : NTFRecord **papoGroup )
428 :
429 : {
430 0 : if( CSLCount((char **) papoGroup) < 1
431 : || papoGroup[0]->GetType() != NRT_COLLECT )
432 0 : return NULL;
433 :
434 0 : OGRFeature *poFeature = new OGRFeature( poLayer->GetLayerDefn() );
435 :
436 : // COLL_ID
437 0 : poFeature->SetField( "COLL_ID", atoi(papoGroup[0]->GetField( 3, 8 )) );
438 :
439 : // NUM_PARTS
440 0 : int nPartCount=0;
441 0 : int *panParts = NULL;
442 :
443 0 : if( papoGroup[0]->GetLength() > 18 )
444 : {
445 0 : nPartCount = atoi(papoGroup[0]->GetField(9,12));
446 0 : panParts = (int *) CPLCalloc(sizeof(int),nPartCount);
447 : }
448 :
449 0 : poFeature->SetField( "NUM_PARTS", nPartCount );
450 :
451 : // TYPE
452 : int iPart;
453 0 : for( iPart = 0; iPart < nPartCount; iPart++ )
454 : panParts[iPart] = atoi(papoGroup[0]->GetField(13+iPart*8,
455 0 : 14+iPart*8));
456 :
457 0 : poFeature->SetField( "TYPE", nPartCount, panParts );
458 :
459 : // ID
460 0 : for( iPart = 0; iPart < nPartCount; iPart++ )
461 : panParts[iPart] = atoi(papoGroup[0]->GetField(15+iPart*8,
462 0 : 20+iPart*8));
463 :
464 0 : poFeature->SetField( "ID", nPartCount, panParts );
465 :
466 0 : CPLFree( panParts );
467 :
468 : // ATTREC Attributes
469 0 : AddGenericAttributes( poReader, papoGroup, poFeature );
470 :
471 0 : return poFeature;
472 : }
473 :
474 : /************************************************************************/
475 : /* TranslateGenericText() */
476 : /************************************************************************/
477 :
478 : static OGRFeature *TranslateGenericText( NTFFileReader *poReader,
479 : OGRNTFLayer *poLayer,
480 0 : NTFRecord **papoGroup )
481 :
482 : {
483 : int iRec;
484 :
485 0 : if( CSLCount((char **) papoGroup) < 2
486 : || papoGroup[0]->GetType() != NRT_TEXTREC )
487 0 : return NULL;
488 :
489 0 : OGRFeature *poFeature = new OGRFeature( poLayer->GetLayerDefn() );
490 :
491 : // TEXT_ID
492 0 : poFeature->SetField( "TEXT_ID", atoi(papoGroup[0]->GetField( 3, 8 )) );
493 :
494 : // Geometry
495 0 : for( iRec = 0; papoGroup[iRec] != NULL; iRec++ )
496 : {
497 0 : if( papoGroup[iRec]->GetType() == NRT_GEOMETRY
498 : || papoGroup[iRec]->GetType() == NRT_GEOMETRY3D )
499 : {
500 : poFeature->SetGeometryDirectly(
501 0 : poReader->ProcessGeometry(papoGroup[iRec]));
502 0 : poFeature->SetField( "GEOM_ID", papoGroup[iRec]->GetField(3,8) );
503 0 : break;
504 : }
505 : }
506 :
507 : // ATTREC Attributes
508 0 : AddGenericAttributes( poReader, papoGroup, poFeature );
509 :
510 : // TEXTREP information
511 0 : for( iRec = 0; papoGroup[iRec] != NULL; iRec++ )
512 : {
513 0 : NTFRecord *poRecord = papoGroup[iRec];
514 :
515 0 : if( poRecord->GetType() == NRT_TEXTREP )
516 : {
517 0 : poFeature->SetField( "FONT", atoi(poRecord->GetField(9,12)) );
518 : poFeature->SetField( "TEXT_HT",
519 0 : atoi(poRecord->GetField(13,15)) * 0.1 );
520 : poFeature->SetField( "TEXT_HT_GROUND",
521 : atoi(poRecord->GetField(13,15))
522 0 : * 0.1 * poReader->GetPaperToGround() );
523 : poFeature->SetField( "DIG_POSTN",
524 0 : atoi(poRecord->GetField(16,16)) );
525 : poFeature->SetField( "ORIENT",
526 0 : atoi(poRecord->GetField(17,20)) * 0.1 );
527 0 : break;
528 : }
529 : }
530 :
531 0 : return poFeature;
532 : }
533 :
534 : /************************************************************************/
535 : /* TranslateGenericName() */
536 : /************************************************************************/
537 :
538 : static OGRFeature *TranslateGenericName( NTFFileReader *poReader,
539 : OGRNTFLayer *poLayer,
540 0 : NTFRecord **papoGroup )
541 :
542 : {
543 : int iRec;
544 :
545 0 : if( CSLCount((char **) papoGroup) < 2
546 : || papoGroup[0]->GetType() != NRT_NAMEREC )
547 0 : return NULL;
548 :
549 0 : OGRFeature *poFeature = new OGRFeature( poLayer->GetLayerDefn() );
550 :
551 : // NAME_ID
552 0 : poFeature->SetField( "NAME_ID", atoi(papoGroup[0]->GetField( 3, 8 )) );
553 :
554 : // TEXT_CODE
555 0 : poFeature->SetField( "TEXT_CODE", papoGroup[0]->GetField( 8, 12 ) );
556 :
557 : // TEXT
558 0 : int nNumChar = atoi(papoGroup[0]->GetField(13,14));
559 :
560 0 : poFeature->SetField( "TEXT", papoGroup[0]->GetField( 15, 15+nNumChar-1));
561 :
562 : // Geometry
563 0 : for( iRec = 0; papoGroup[iRec] != NULL; iRec++ )
564 : {
565 0 : if( papoGroup[iRec]->GetType() == NRT_GEOMETRY
566 : || papoGroup[iRec]->GetType() == NRT_GEOMETRY3D )
567 : {
568 : poFeature->SetGeometryDirectly(
569 0 : poReader->ProcessGeometry(papoGroup[iRec]));
570 0 : poFeature->SetField( "GEOM_ID", papoGroup[iRec]->GetField(3,8) );
571 0 : break;
572 : }
573 : }
574 :
575 : // ATTREC Attributes
576 0 : AddGenericAttributes( poReader, papoGroup, poFeature );
577 :
578 : // NAMEPOSTN information
579 0 : for( iRec = 0; papoGroup[iRec] != NULL; iRec++ )
580 : {
581 0 : NTFRecord *poRecord = papoGroup[iRec];
582 :
583 0 : if( poRecord->GetType() == NRT_NAMEPOSTN )
584 : {
585 0 : poFeature->SetField( "FONT", atoi(poRecord->GetField(3,6)) );
586 : poFeature->SetField( "TEXT_HT",
587 0 : atoi(poRecord->GetField(7,9)) * 0.1 );
588 : poFeature->SetField( "TEXT_HT_GROUND",
589 : atoi(poRecord->GetField(7,9))
590 0 : * 0.1 * poReader->GetPaperToGround() );
591 : poFeature->SetField( "DIG_POSTN",
592 0 : atoi(poRecord->GetField(10,10)) );
593 : poFeature->SetField( "ORIENT",
594 0 : atoi(poRecord->GetField(11,14)) * 0.1 );
595 0 : break;
596 : }
597 : }
598 :
599 0 : return poFeature;
600 : }
601 :
602 : /************************************************************************/
603 : /* TranslateGenericPoint() */
604 : /************************************************************************/
605 :
606 : static OGRFeature *TranslateGenericPoint( NTFFileReader *poReader,
607 : OGRNTFLayer *poLayer,
608 0 : NTFRecord **papoGroup )
609 :
610 : {
611 0 : if( CSLCount((char **) papoGroup) < 2
612 : || papoGroup[0]->GetType() != NRT_POINTREC
613 : || (papoGroup[1]->GetType() != NRT_GEOMETRY
614 : && papoGroup[1]->GetType() != NRT_GEOMETRY3D) )
615 : {
616 0 : return NULL;
617 : }
618 :
619 0 : OGRFeature *poFeature = new OGRFeature( poLayer->GetLayerDefn() );
620 :
621 : // POINT_ID
622 0 : poFeature->SetField( "POINT_ID", atoi(papoGroup[0]->GetField( 3, 8 )) );
623 :
624 : // Geometry
625 0 : poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1]));
626 0 : poFeature->SetField( "GEOM_ID", papoGroup[1]->GetField(3,8) );
627 :
628 : // ATTREC Attributes
629 0 : AddGenericAttributes( poReader, papoGroup, poFeature );
630 :
631 : // Handle singular attribute in pre-level 3 POINTREC.
632 0 : if( poReader->GetNTFLevel() < 3 )
633 : {
634 : char szValType[3];
635 :
636 0 : strcpy( szValType, papoGroup[0]->GetField(9,10) );
637 0 : if( !EQUAL(szValType," ") )
638 : {
639 : char *pszProcessedValue;
640 :
641 0 : if( poReader->ProcessAttValue(szValType,
642 : papoGroup[0]->GetField(11,16),
643 : NULL, &pszProcessedValue, NULL ) )
644 0 : poFeature->SetField(szValType, pszProcessedValue);
645 : }
646 :
647 0 : if( !EQUAL(papoGroup[0]->GetField(17,20)," ") )
648 : {
649 0 : poFeature->SetField("FEAT_CODE",papoGroup[0]->GetField(17,20));
650 : }
651 : }
652 :
653 0 : return poFeature;
654 : }
655 :
656 : /************************************************************************/
657 : /* TranslateGenericLine() */
658 : /************************************************************************/
659 :
660 : static OGRFeature *TranslateGenericLine( NTFFileReader *poReader,
661 : OGRNTFLayer *poLayer,
662 0 : NTFRecord **papoGroup )
663 :
664 : {
665 0 : if( CSLCount((char **) papoGroup) < 2
666 : || papoGroup[0]->GetType() != NRT_LINEREC
667 : || (papoGroup[1]->GetType() != NRT_GEOMETRY
668 : && papoGroup[1]->GetType() != NRT_GEOMETRY3D) )
669 0 : return NULL;
670 :
671 0 : OGRFeature *poFeature = new OGRFeature( poLayer->GetLayerDefn() );
672 :
673 : // LINE_ID
674 0 : poFeature->SetField( "LINE_ID", atoi(papoGroup[0]->GetField( 3, 8 )) );
675 :
676 : // Geometry
677 0 : poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1]));
678 0 : poFeature->SetField( "GEOM_ID", papoGroup[1]->GetField(3,8) );
679 :
680 : // ATTREC Attributes
681 0 : AddGenericAttributes( poReader, papoGroup, poFeature );
682 :
683 : // Handle singular attribute in pre-level 3 LINEREC.
684 0 : if( poReader->GetNTFLevel() < 3 )
685 : {
686 : char szValType[3];
687 :
688 0 : strcpy( szValType, papoGroup[0]->GetField(9,10) );
689 0 : if( !EQUAL(szValType," ") )
690 : {
691 : char *pszProcessedValue;
692 :
693 0 : if( poReader->ProcessAttValue(szValType,
694 : papoGroup[0]->GetField(11,16),
695 : NULL, &pszProcessedValue, NULL ) )
696 0 : poFeature->SetField(szValType, pszProcessedValue);
697 : }
698 :
699 0 : if( !EQUAL(papoGroup[0]->GetField(17,20)," ") )
700 : {
701 0 : poFeature->SetField("FEAT_CODE",papoGroup[0]->GetField(17,20));
702 : }
703 : }
704 :
705 0 : return poFeature;
706 : }
707 :
708 : /************************************************************************/
709 : /* TranslateGenericPoly() */
710 : /************************************************************************/
711 :
712 : static OGRFeature *TranslateGenericPoly( NTFFileReader *poReader,
713 : OGRNTFLayer *poLayer,
714 0 : NTFRecord **papoGroup )
715 :
716 : {
717 : /* ==================================================================== */
718 : /* Traditional POLYGON record groups. */
719 : /* ==================================================================== */
720 0 : if( CSLCount((char **) papoGroup) >= 2
721 : && papoGroup[0]->GetType() == NRT_POLYGON
722 : && papoGroup[1]->GetType() == NRT_CHAIN )
723 : {
724 0 : OGRFeature *poFeature = new OGRFeature( poLayer->GetLayerDefn() );
725 :
726 : // POLY_ID
727 0 : poFeature->SetField( 0, atoi(papoGroup[0]->GetField( 3, 8 )) );
728 :
729 : // NUM_PARTS
730 0 : int nNumLinks = atoi(papoGroup[1]->GetField( 9, 12 ));
731 :
732 0 : if( nNumLinks > MAX_LINK )
733 : {
734 : CPLError( CE_Failure, CPLE_AppDefined,
735 0 : "MAX_LINK exceeded in ntf_generic.cpp." );
736 0 : return poFeature;
737 : }
738 :
739 0 : poFeature->SetField( "NUM_PARTS", nNumLinks );
740 :
741 : // DIR
742 : int i, anList[MAX_LINK];
743 :
744 0 : for( i = 0; i < nNumLinks; i++ )
745 0 : anList[i] = atoi(papoGroup[1]->GetField( 19+i*7, 19+i*7 ));
746 :
747 0 : poFeature->SetField( "DIR", nNumLinks, anList );
748 :
749 : // GEOM_ID_OF_LINK
750 0 : for( i = 0; i < nNumLinks; i++ )
751 0 : anList[i] = atoi(papoGroup[1]->GetField( 13+i*7, 18+i*7 ));
752 :
753 0 : poFeature->SetField( "GEOM_ID_OF_LINK", nNumLinks, anList );
754 :
755 : // RingStart
756 0 : int nRingList = 0;
757 0 : poFeature->SetField( "RingStart", 1, &nRingList );
758 :
759 : // ATTREC Attributes
760 0 : AddGenericAttributes( poReader, papoGroup, poFeature );
761 :
762 : // Read point geometry
763 0 : if( papoGroup[2] != NULL
764 : && (papoGroup[2]->GetType() == NRT_GEOMETRY
765 : || papoGroup[2]->GetType() == NRT_GEOMETRY3D) )
766 : {
767 : poFeature->SetGeometryDirectly(
768 0 : poReader->ProcessGeometry(papoGroup[2]));
769 0 : poFeature->SetField( "GEOM_ID", papoGroup[2]->GetField(3,8) );
770 : }
771 :
772 0 : return poFeature;
773 : }
774 :
775 0 : return NULL;
776 : }
777 :
778 : /************************************************************************/
779 : /* TranslateGenericCPoly() */
780 : /************************************************************************/
781 :
782 : static OGRFeature *TranslateGenericCPoly( NTFFileReader *poReader,
783 : OGRNTFLayer *poLayer,
784 0 : NTFRecord **papoGroup )
785 :
786 : {
787 : /* -------------------------------------------------------------------- */
788 : /* First we do validation of the grouping. */
789 : /* -------------------------------------------------------------------- */
790 0 : if( papoGroup[0]->GetType() != NRT_CPOLY )
791 0 : return NULL;
792 :
793 0 : if( papoGroup[1] == NULL ||
794 : (papoGroup[1]->GetType() != NRT_GEOMETRY
795 : && papoGroup[1]->GetType() != NRT_GEOMETRY3D) )
796 0 : return NULL;
797 :
798 0 : if( papoGroup[1] != NULL
799 : && papoGroup[2]->GetType() != NRT_ATTREC )
800 0 : return NULL;
801 :
802 : /* -------------------------------------------------------------------- */
803 : /* collect information for whole complex polygon. */
804 : /* -------------------------------------------------------------------- */
805 0 : OGRFeature *poFeature = new OGRFeature( poLayer->GetLayerDefn() );
806 :
807 : // CPOLY_ID
808 0 : poFeature->SetField( "CPOLY_ID", atoi(papoGroup[0]->GetField( 3, 8 )) );
809 :
810 : // ATTREC Attributes
811 0 : AddGenericAttributes( poReader, papoGroup, poFeature );
812 :
813 : // Read point geometry
814 0 : if( papoGroup[1] != NULL
815 : && (papoGroup[1]->GetType() == NRT_GEOMETRY
816 : || papoGroup[1]->GetType() == NRT_GEOMETRY3D) )
817 : {
818 : poFeature->SetGeometryDirectly(
819 0 : poReader->ProcessGeometry(papoGroup[1]));
820 : poFeature->SetField( "GEOM_ID",
821 0 : atoi(papoGroup[1]->GetField(3,8)) );
822 : }
823 :
824 : /* -------------------------------------------------------------------- */
825 : /* Collect the chains for each of the rings, and just aggregate */
826 : /* these into the master list without any concept of where the */
827 : /* boundaries are. The boundary information will be emmitted */
828 : /* in the RingStart field. */
829 : /* -------------------------------------------------------------------- */
830 0 : int nNumLink = 0, iLink;
831 : int anPolyId[MAX_LINK*2];
832 :
833 0 : nNumLink = atoi(papoGroup[0]->GetField(9,12));
834 0 : for( iLink = 0; iLink < nNumLink; iLink++ )
835 : {
836 : anPolyId[iLink] = atoi(papoGroup[0]->GetField(13 + iLink*7,
837 0 : 18 + iLink*7));
838 : }
839 :
840 : // NUM_PARTS
841 0 : poFeature->SetField( "NUM_PARTS", nNumLink );
842 :
843 : // POLY_ID
844 0 : poFeature->SetField( "POLY_ID", nNumLink, anPolyId );
845 :
846 0 : return poFeature;
847 : }
848 :
849 : /************************************************************************/
850 : /* EstablishGenericLayers() */
851 : /************************************************************************/
852 :
853 2 : void OGRNTFDataSource::EstablishGenericLayers()
854 :
855 : {
856 : int iType;
857 :
858 : /* -------------------------------------------------------------------- */
859 : /* Pick an initial NTFFileReader to build the layers against. */
860 : /* -------------------------------------------------------------------- */
861 4 : for( int iFile = 0; iFile < nNTFFileCount; iFile++ )
862 : {
863 2 : NTFFileReader *poPReader = NULL;
864 2 : int n3DFlag = 0;
865 :
866 2 : poPReader = papoNTFFileReader[iFile];
867 2 : if( poPReader->GetProductId() != NPC_UNKNOWN )
868 2 : continue;
869 :
870 : /* -------------------------------------------------------------------- */
871 : /* If any of the generic classes are 3D, then assume all our */
872 : /* geometry should be marked as 3D. */
873 : /* -------------------------------------------------------------------- */
874 0 : for( iType = 0; iType < 99; iType++ )
875 : {
876 0 : NTFGenericClass *poClass = aoGenericClass + iType;
877 :
878 0 : if( poClass->nFeatureCount > 0 && poClass->b3D )
879 0 : n3DFlag = wkb25DBit;
880 : }
881 :
882 : /* -------------------------------------------------------------------- */
883 : /* Create layers for all recognised layer types with features. */
884 : /* -------------------------------------------------------------------- */
885 0 : for( iType = 0; iType < 99; iType++ )
886 : {
887 0 : NTFGenericClass *poClass = aoGenericClass + iType;
888 :
889 0 : if( poClass->nFeatureCount == 0 )
890 0 : continue;
891 :
892 0 : if( iType == NRT_POINTREC )
893 : {
894 : poPReader->
895 : EstablishLayer( "GENERIC_POINT",
896 : (OGRwkbGeometryType) (wkbPoint | n3DFlag),
897 : TranslateGenericPoint,
898 : NRT_POINTREC, poClass,
899 : "POINT_ID", OFTInteger, 6, 0,
900 0 : NULL );
901 : }
902 0 : else if( iType == NRT_LINEREC )
903 : {
904 : poPReader->
905 : EstablishLayer( "GENERIC_LINE",
906 : (OGRwkbGeometryType)
907 : (wkbLineString | n3DFlag),
908 : TranslateGenericLine,
909 : NRT_LINEREC, poClass,
910 : "LINE_ID", OFTInteger, 6, 0,
911 0 : NULL );
912 : }
913 0 : else if( iType == NRT_TEXTREC )
914 : {
915 : poPReader->
916 : EstablishLayer( "GENERIC_TEXT",
917 : (OGRwkbGeometryType)
918 : (wkbPoint | n3DFlag),
919 : TranslateGenericText,
920 : NRT_TEXTREC, poClass,
921 : "TEXT_ID", OFTInteger, 6, 0,
922 0 : NULL );
923 : }
924 0 : else if( iType == NRT_NAMEREC )
925 : {
926 : poPReader->
927 : EstablishLayer( "GENERIC_NAME",
928 : (OGRwkbGeometryType)
929 : (wkbPoint | n3DFlag),
930 : TranslateGenericName,
931 : NRT_NAMEREC, poClass,
932 : "NAME_ID", OFTInteger, 6, 0,
933 0 : NULL );
934 : }
935 0 : else if( iType == NRT_NODEREC )
936 : {
937 : poPReader->
938 : EstablishLayer( "GENERIC_NODE",
939 : (OGRwkbGeometryType)
940 : (wkbPoint | n3DFlag),
941 : TranslateGenericNode,
942 : NRT_NODEREC, poClass,
943 : "NODE_ID", OFTInteger, 6, 0,
944 : "NUM_LINKS", OFTInteger, 4, 0,
945 : "GEOM_ID_OF_LINK", OFTIntegerList, 6, 0,
946 : "DIR", OFTIntegerList, 1, 0,
947 0 : NULL );
948 : }
949 0 : else if( iType == NRT_COLLECT )
950 : {
951 : poPReader->
952 : EstablishLayer( "GENERIC_COLLECTION", wkbNone,
953 : TranslateGenericCollection,
954 : NRT_COLLECT, poClass,
955 : "COLL_ID", OFTInteger, 6, 0,
956 : "NUM_PARTS", OFTInteger, 4, 0,
957 : "TYPE", OFTIntegerList, 2, 0,
958 : "ID", OFTIntegerList, 6, 0,
959 0 : NULL );
960 : }
961 0 : else if( iType == NRT_POLYGON )
962 : {
963 : poPReader->
964 : EstablishLayer( "GENERIC_POLY",
965 : (OGRwkbGeometryType) (wkbPoint | n3DFlag),
966 : TranslateGenericPoly,
967 : NRT_POLYGON, poClass,
968 : "POLY_ID", OFTInteger, 6, 0,
969 : "NUM_PARTS", OFTInteger, 4, 0,
970 : "DIR", OFTIntegerList, 1, 0,
971 : "GEOM_ID_OF_LINK", OFTIntegerList, 6, 0,
972 : "RingStart", OFTIntegerList, 6, 0,
973 0 : NULL );
974 : }
975 0 : else if( iType == NRT_CPOLY )
976 : {
977 : poPReader->
978 : EstablishLayer( "GENERIC_CPOLY",
979 : (OGRwkbGeometryType) (wkbPoint | n3DFlag),
980 : TranslateGenericCPoly,
981 : NRT_CPOLY, poClass,
982 : "CPOLY_ID", OFTInteger, 6, 0,
983 : "NUM_PARTS", OFTInteger, 4, 0,
984 : "POLY_ID", OFTIntegerList, 1, 0,
985 0 : NULL );
986 : }
987 : }
988 : }
989 2 : }
990 :
|