1 : /******************************************************************************
2 : * $Id: tigercompletechain.cpp 22961 2011-08-20 17:09:59Z rouault $
3 : *
4 : * Project: TIGER/Line Translator
5 : * Purpose: Implements TigerCompleteChain, providing access to RT1 and
6 : * related files.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 1999, Frank Warmerdam
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 "ogr_tiger.h"
32 : #include "cpl_conv.h"
33 :
34 : CPL_CVSID("$Id: tigercompletechain.cpp 22961 2011-08-20 17:09:59Z rouault $");
35 :
36 : static const TigerFieldInfo rt1_2002_fields[] = {
37 : // fieldname fmt type OFTType beg end len bDefine bSet bWrite
38 : { "MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0, 0 },
39 : { "TLID", 'R', 'N', OFTInteger, 6, 15, 10, 1, 1, 1 },
40 : { "SIDE1", 'R', 'N', OFTInteger, 16, 16, 1, 1, 1, 1 },
41 : { "SOURCE", 'L', 'A', OFTString, 17, 17, 1, 1, 1, 1 },
42 : { "FEDIRP", 'L', 'A', OFTString, 18, 19, 2, 1, 1, 1 },
43 : { "FENAME", 'L', 'A', OFTString, 20, 49, 30, 1, 1, 1 },
44 : { "FETYPE", 'L', 'A', OFTString, 50, 53, 4, 1, 1, 1 },
45 : { "FEDIRS", 'L', 'A', OFTString, 54, 55, 2, 1, 1, 1 },
46 : { "CFCC", 'L', 'A', OFTString, 56, 58, 3, 1, 1, 1 },
47 : { "FRADDL", 'R', 'A', OFTString, 59, 69, 11, 1, 1, 1 },
48 : { "TOADDL", 'R', 'A', OFTString, 70, 80, 11, 1, 1, 1 },
49 : { "FRADDR", 'R', 'A', OFTString, 81, 91, 11, 1, 1, 1 },
50 : { "TOADDR", 'R', 'A', OFTString, 92, 102, 11, 1, 1, 1 },
51 : { "FRIADDL", 'L', 'A', OFTString, 103, 103, 1, 1, 1, 1 },
52 : { "TOIADDL", 'L', 'A', OFTString, 104, 104, 1, 1, 1, 1 },
53 : { "FRIADDR", 'L', 'A', OFTString, 105, 105, 1, 1, 1, 1 },
54 : { "TOIADDR", 'L', 'A', OFTString, 106, 106, 1, 1, 1, 1 },
55 : { "ZIPL", 'L', 'N', OFTInteger, 107, 111, 5, 1, 1, 1 },
56 : { "ZIPR", 'L', 'N', OFTInteger, 112, 116, 5, 1, 1, 1 },
57 : { "AIANHHFPL", 'L', 'N', OFTInteger, 117, 121, 5, 1, 1, 1 },
58 : { "AIANHHFPR", 'L', 'N', OFTInteger, 122, 126, 5, 1, 1, 1 },
59 : { "AIHHTLIL", 'L', 'A', OFTString, 127, 127, 1, 1, 1, 1 },
60 : { "AIHHTLIR", 'L', 'A', OFTString, 128, 128, 1, 1, 1, 1 },
61 : { "CENSUS1", 'L', 'A', OFTString, 129, 129, 1, 1, 1, 1 },
62 : { "CENSUS2", 'L', 'A', OFTString, 130, 130, 1, 1, 1, 1 },
63 : { "STATEL", 'L', 'N', OFTInteger, 131, 132, 2, 1, 1, 1 },
64 : { "STATER", 'L', 'N', OFTInteger, 133, 134, 2, 1, 1, 1 },
65 : { "COUNTYL", 'L', 'N', OFTInteger, 135, 137, 3, 1, 1, 1 },
66 : { "COUNTYR", 'L', 'N', OFTInteger, 138, 140, 3, 1, 1, 1 },
67 :
68 : { "COUSUBL", 'L', 'N', OFTInteger, 141, 145, 5, 1, 1, 1 },
69 : { "COUSUBR", 'L', 'N', OFTInteger, 146, 150, 5, 1, 1, 1 },
70 : { "SUBMCDL", 'L', 'N', OFTInteger, 151, 155, 5, 1, 1, 1 },
71 : { "SUBMCDR", 'L', 'N', OFTInteger, 156, 160, 5, 1, 1, 1 },
72 : { "PLACEL", 'L', 'N', OFTInteger, 161, 165, 5, 1, 1, 1 },
73 : { "PLACER", 'L', 'N', OFTInteger, 166, 170, 5, 1, 1, 1 },
74 : { "TRACTL", 'L', 'N', OFTInteger, 171, 176, 6, 1, 1, 1 },
75 : { "TRACTR", 'L', 'N', OFTInteger, 177, 182, 6, 1, 1, 1 },
76 : { "BLOCKL", 'L', 'N', OFTInteger, 183, 186, 4, 1, 1, 1 },
77 : { "BLOCKR", 'L', 'N', OFTInteger, 187, 190, 4, 1, 1, 1 }
78 : };
79 : static const TigerRecordInfo rt1_2002_info =
80 : {
81 : rt1_2002_fields,
82 : sizeof(rt1_2002_fields) / sizeof(TigerFieldInfo),
83 : 228
84 : };
85 :
86 : static const TigerFieldInfo rt1_fields[] = {
87 : // fieldname fmt type OFTType beg end len bDefine bSet bWrite
88 : { "MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0, 0 },
89 : { "TLID", 'R', 'N', OFTInteger, 6, 15, 10, 1, 1, 1 },
90 : { "SIDE1", 'R', 'N', OFTInteger, 16, 16, 1, 1, 1, 1 },
91 : { "SOURCE", 'L', 'A', OFTString, 17, 17, 1, 1, 1, 1 },
92 : { "FEDIRP", 'L', 'A', OFTString, 18, 19, 2, 1, 1, 1 },
93 : { "FENAME", 'L', 'A', OFTString, 20, 49, 30, 1, 1, 1 },
94 : { "FETYPE", 'L', 'A', OFTString, 50, 53, 4, 1, 1, 1 },
95 : { "FEDIRS", 'L', 'A', OFTString, 54, 55, 2, 1, 1, 1 },
96 : { "CFCC", 'L', 'A', OFTString, 56, 58, 3, 1, 1, 1 },
97 : { "FRADDL", 'R', 'A', OFTString, 59, 69, 11, 1, 1, 1 },
98 : { "TOADDL", 'R', 'A', OFTString, 70, 80, 11, 1, 1, 1 },
99 : { "FRADDR", 'R', 'A', OFTString, 81, 91, 11, 1, 1, 1 },
100 : { "TOADDR", 'R', 'A', OFTString, 92, 102, 11, 1, 1, 1 },
101 : { "FRIADDL", 'L', 'A', OFTInteger, 103, 103, 1, 1, 1, 1 },
102 : { "TOIADDL", 'L', 'A', OFTInteger, 104, 104, 1, 1, 1, 1 },
103 : { "FRIADDR", 'L', 'A', OFTInteger, 105, 105, 1, 1, 1, 1 },
104 : { "TOIADDR", 'L', 'A', OFTInteger, 106, 106, 1, 1, 1, 1 },
105 : { "ZIPL", 'L', 'N', OFTInteger, 107, 111, 5, 1, 1, 1 },
106 : { "ZIPR", 'L', 'N', OFTInteger, 112, 116, 5, 1, 1, 1 },
107 : { "FAIRL", 'L', 'N', OFTInteger, 117, 121, 5, 1, 1, 1 },
108 : { "FAIRR", 'L', 'N', OFTInteger, 122, 126, 5, 1, 1, 1 },
109 : { "TRUSTL", 'L', 'A', OFTString, 127, 127, 1, 1, 1, 1 },
110 : { "TRUSTR", 'L', 'A', OFTString, 128, 128, 1, 1, 1, 1 },
111 : { "CENSUS1", 'L', 'A', OFTString, 129, 129, 1, 1, 1, 1 },
112 : { "CENSUS2", 'L', 'A', OFTString, 130, 130, 1, 1, 1, 1 },
113 : { "STATEL", 'L', 'N', OFTInteger, 131, 132, 2, 1, 1, 1 },
114 : { "STATER", 'L', 'N', OFTInteger, 133, 134, 2, 1, 1, 1 },
115 : { "COUNTYL", 'L', 'N', OFTInteger, 135, 137, 3, 1, 1, 1 },
116 : { "COUNTYR", 'L', 'N', OFTInteger, 138, 140, 3, 1, 1, 1 },
117 :
118 : { "FMCDL", 'L', 'N', OFTInteger, 141, 145, 5, 1, 1, 1 },
119 : { "FMCDR", 'L', 'N', OFTInteger, 146, 150, 5, 1, 1, 1 },
120 : { "FSMCDL", 'L', 'N', OFTInteger, 151, 155, 5, 1, 1, 1 },
121 : { "FSMCDR", 'L', 'N', OFTInteger, 156, 160, 5, 1, 1, 1 },
122 : { "FPLL", 'L', 'N', OFTInteger, 161, 165, 5, 1, 1, 1 },
123 : { "FPLR", 'L', 'N', OFTInteger, 166, 170, 5, 1, 1, 1 },
124 : { "CTBNAL", 'L', 'N', OFTInteger, 171, 176, 6, 1, 1, 1 },
125 : { "CTBNAR", 'L', 'N', OFTInteger, 177, 182, 6, 1, 1, 1 },
126 : { "BLKL", 'L', 'N', OFTString, 183, 186, 4, 1, 1, 1 },
127 : { "BLKR", 'L', 'N', OFTString, 187, 190, 4, 1, 1, 1 }
128 : };
129 : static const TigerRecordInfo rt1_info =
130 : {
131 : rt1_fields,
132 : sizeof(rt1_fields) / sizeof(TigerFieldInfo),
133 : 228
134 : };
135 :
136 : static const TigerRecordInfo rt2_info =
137 : {
138 : NULL, // RT2 is handled specially in the code below; the only
139 : 0, // thing from this structure that is used is:
140 : 208 // <--- nRecordLength
141 : };
142 :
143 :
144 : static const TigerFieldInfo rt3_2000_Redistricting_fields[] = {
145 : // fieldname fmt type OFTType beg end len bDefine bSet bWrite
146 : { "TLID", 'R', 'N', OFTInteger, 6, 15, 10, 0, 0, 1 },
147 : { "STATE90L", 'L', 'N', OFTInteger, 16, 17, 2, 1, 1, 1 },
148 : { "STATE90R", 'L', 'N', OFTInteger, 18, 19, 2, 1, 1, 1 },
149 : { "COUN90L", 'L', 'N', OFTInteger, 20, 22, 3, 1, 1, 1 },
150 : { "COUN90R", 'L', 'N', OFTInteger, 23, 25, 3, 1, 1, 1 },
151 : { "FMCD90L", 'L', 'N', OFTInteger, 26, 30, 5, 1, 1, 1 },
152 : { "FMCD90R", 'L', 'N', OFTInteger, 31, 35, 5, 1, 1, 1 },
153 : { "FPL90L", 'L', 'N', OFTInteger, 36, 40, 5, 1, 1, 1 },
154 : { "FPL90R", 'L', 'N', OFTInteger, 41, 45, 5, 1, 1, 1 },
155 : { "CTBNA90L", 'L', 'N', OFTInteger, 46, 51, 6, 1, 1, 1 },
156 : { "CTBNA90R", 'L', 'N', OFTInteger, 52, 57, 6, 1, 1, 1 },
157 : { "AIR90L", 'L', 'N', OFTInteger, 58, 61, 4, 1, 1, 1 },
158 : { "AIR90R", 'L', 'N', OFTInteger, 62, 65, 4, 1, 1, 1 },
159 : { "TRUST90L", 'L', 'A', OFTString, 66, 66, 1, 1, 1, 1 },
160 : { "TRUST90R", 'L', 'A', OFTString, 67, 67, 1, 1, 1, 1 },
161 : { "BLK90L", 'L', 'A', OFTString, 70, 73, 4, 1, 1, 1 },
162 : { "BLK90R", 'L', 'A', OFTString, 74, 77, 4, 1, 1, 1 },
163 : { "AIRL", 'L', 'N', OFTInteger, 78, 81, 4, 1, 1, 1 },
164 : { "AIRR", 'L', 'N', OFTInteger, 82, 85, 4, 1, 1, 1 },
165 :
166 : { "ANRCL", 'L', 'N', OFTInteger, 86, 90, 5, 1, 1, 1 },
167 : { "ANRCR", 'L', 'N', OFTInteger, 91, 95, 5, 1, 1, 1 },
168 : { "AITSCEL", 'L', 'N', OFTInteger, 96, 98, 3, 1, 1, 1 },
169 : { "AITSCER", 'L', 'N', OFTInteger, 99, 101, 3, 1, 1, 1 },
170 : { "AITSL", 'L', 'N', OFTInteger, 102, 106, 5 , 1, 1, 1 },
171 : { "AITSR", 'L', 'N', OFTInteger, 107, 111, 5, 1, 1, 1 }
172 : };
173 : static const TigerRecordInfo rt3_2000_Redistricting_info =
174 : {
175 : rt3_2000_Redistricting_fields,
176 : sizeof(rt3_2000_Redistricting_fields) / sizeof(TigerFieldInfo),
177 : 111
178 : };
179 :
180 : static const TigerFieldInfo rt3_fields[] = {
181 : // fieldname fmt type OFTType beg end len bDefine bSet bWrite
182 : { "TLID", 'R', 'N', OFTInteger, 6, 15, 10, 0, 0, 1 },
183 : { "STATE90L", 'L', 'N', OFTInteger, 16, 17, 2, 1, 1, 1 },
184 : { "STATE90R", 'L', 'N', OFTInteger, 18, 19, 2, 1, 1, 1 },
185 : { "COUN90L", 'L', 'N', OFTInteger, 20, 22, 3, 1, 1, 1 },
186 : { "COUN90R", 'L', 'N', OFTInteger, 23, 25, 3, 1, 1, 1 },
187 : { "FMCD90L", 'L', 'N', OFTInteger, 26, 30, 5, 1, 1, 1 },
188 : { "FMCD90R", 'L', 'N', OFTInteger, 31, 35, 5, 1, 1, 1 },
189 : { "FPL90L", 'L', 'N', OFTInteger, 36, 40, 5, 1, 1, 1 },
190 : { "FPL90R", 'L', 'N', OFTInteger, 41, 45, 5, 1, 1, 1 },
191 : { "CTBNA90L", 'L', 'N', OFTInteger, 46, 51, 6, 1, 1, 1 },
192 : { "CTBNA90R", 'L', 'N', OFTInteger, 52, 57, 6, 1, 1, 1 },
193 : { "AIR90L", 'L', 'N', OFTInteger, 58, 61, 4, 1, 1, 1 },
194 : { "AIR90R", 'L', 'N', OFTInteger, 62, 65, 4, 1, 1, 1 },
195 : { "TRUST90L", 'L', 'A', OFTInteger, 66, 66, 1, 1, 1, 1 },
196 : { "TRUST90R", 'L', 'A', OFTInteger, 67, 67, 1, 1, 1, 1 },
197 : { "BLK90L", 'L', 'A', OFTString, 70, 73, 4, 1, 1, 1 },
198 : { "BLK90R", 'L', 'A', OFTString, 74, 77, 4, 1, 1, 1 },
199 : { "AIRL", 'L', 'N', OFTInteger, 78, 81, 4, 1, 1, 1 },
200 : { "AIRR", 'L', 'N', OFTInteger, 82, 85, 4, 1, 1, 1 },
201 :
202 : { "VTDL", 'L', 'A', OFTString, 104, 107, 4, 1, 1, 1 },
203 : { "VTDR", 'L', 'A', OFTString, 108, 111, 4, 1, 1, 1 }
204 :
205 : };
206 : static const TigerRecordInfo rt3_info =
207 : {
208 : rt3_fields,
209 : sizeof(rt3_fields) / sizeof(TigerFieldInfo),
210 : 111
211 : };
212 :
213 : /************************************************************************/
214 : /* TigerCompleteChain() */
215 : /************************************************************************/
216 :
217 7 : TigerCompleteChain::TigerCompleteChain( OGRTigerDataSource * poDSIn,
218 7 : const char * pszPrototypeModule )
219 :
220 : {
221 7 : poDS = poDSIn;
222 7 : poFeatureDefn = new OGRFeatureDefn( "CompleteChain" );
223 7 : poFeatureDefn->Reference();
224 7 : poFeatureDefn->SetGeomType( wkbLineString );
225 :
226 :
227 7 : if (poDS->GetVersion() >= TIGER_2002) {
228 7 : psRT1Info = &rt1_2002_info;
229 7 : bUsingRT3 = FALSE;
230 : } else {
231 0 : psRT1Info = &rt1_info;
232 0 : bUsingRT3 = TRUE;
233 : }
234 :
235 7 : psRT2Info = &rt2_info;
236 :
237 7 : nRT1RecOffset = 0;
238 :
239 7 : if (poDS->GetVersion() >= TIGER_2000_Redistricting) {
240 7 : psRT3Info = &rt3_2000_Redistricting_info;
241 : } else {
242 0 : psRT3Info = &rt3_info;
243 : }
244 :
245 7 : fpRT3 = NULL;
246 :
247 7 : panShapeRecordId = NULL;
248 7 : fpShape = NULL;
249 :
250 : /* -------------------------------------------------------------------- */
251 : /* Fields from type 1 record. */
252 : /* -------------------------------------------------------------------- */
253 :
254 7 : AddFieldDefns( psRT1Info, poFeatureDefn );
255 :
256 : /* -------------------------------------------------------------------- */
257 : /* Fields from type 3 record. Eventually we should verify that */
258 : /* a .RT3 file is available before adding these fields. */
259 : /* -------------------------------------------------------------------- */
260 7 : if( bUsingRT3 ) {
261 0 : AddFieldDefns( psRT3Info, poFeatureDefn );
262 : }
263 7 : }
264 :
265 : /************************************************************************/
266 : /* ~TigerCompleteChain() */
267 : /************************************************************************/
268 :
269 7 : TigerCompleteChain::~TigerCompleteChain()
270 :
271 : {
272 7 : CPLFree( panShapeRecordId );
273 :
274 7 : if( fpRT3 != NULL )
275 0 : VSIFClose( fpRT3 );
276 :
277 7 : if( fpShape != NULL )
278 5 : VSIFClose( fpShape );
279 7 : }
280 :
281 : /************************************************************************/
282 : /* SetModule() */
283 : /************************************************************************/
284 :
285 31 : int TigerCompleteChain::SetModule( const char * pszModule )
286 :
287 : {
288 31 : if( !OpenFile( pszModule, "1" ) )
289 0 : return FALSE;
290 :
291 31 : EstablishFeatureCount();
292 :
293 : /* -------------------------------------------------------------------- */
294 : /* Is this a copyright record inserted at the beginning of the */
295 : /* RT1 file by the folks at GDT? If so, setup to ignore the */
296 : /* first record. */
297 : /* -------------------------------------------------------------------- */
298 31 : nRT1RecOffset = 0;
299 31 : if( pszModule )
300 : {
301 : char achHeader[10];
302 :
303 24 : VSIFSeek( fpPrimary, 0, SEEK_SET );
304 24 : VSIFRead( achHeader, sizeof(achHeader), 1, fpPrimary );
305 :
306 24 : if( EQUALN(achHeader,"Copyright",8) )
307 : {
308 0 : nRT1RecOffset = 1;
309 0 : nFeatures--;
310 : }
311 : }
312 :
313 : /* -------------------------------------------------------------------- */
314 : /* Open the RT3 file */
315 : /* -------------------------------------------------------------------- */
316 31 : if( bUsingRT3 )
317 : {
318 0 : if( fpRT3 != NULL )
319 : {
320 0 : VSIFClose( fpRT3 );
321 0 : fpRT3 = NULL;
322 : }
323 :
324 0 : if( pszModule )
325 : {
326 : char *pszFilename;
327 :
328 0 : pszFilename = poDS->BuildFilename( pszModule, "3" );
329 :
330 0 : fpRT3 = VSIFOpen( pszFilename, "rb" );
331 :
332 0 : CPLFree( pszFilename );
333 : }
334 : }
335 :
336 : /* -------------------------------------------------------------------- */
337 : /* Close the shape point file, if open and free the list of */
338 : /* record ids. */
339 : /* -------------------------------------------------------------------- */
340 31 : if( fpShape != NULL )
341 : {
342 20 : VSIFClose( fpShape );
343 20 : fpShape = NULL;
344 : }
345 :
346 31 : CPLFree( panShapeRecordId );
347 31 : panShapeRecordId = NULL;
348 :
349 : /* -------------------------------------------------------------------- */
350 : /* Try to open the RT2 file corresponding to this RT1 file. */
351 : /* -------------------------------------------------------------------- */
352 31 : if( pszModule != NULL )
353 : {
354 : char *pszFilename;
355 :
356 24 : pszFilename = poDS->BuildFilename( pszModule, "2" );
357 :
358 24 : fpShape = VSIFOpen( pszFilename, "rb" );
359 :
360 24 : if( fpShape == NULL )
361 : {
362 0 : if( nRT1RecOffset == 0 )
363 : CPLError( CE_Warning, CPLE_OpenFailed,
364 : "Failed to open %s, intermediate shape arcs will not be available.\n",
365 0 : pszFilename );
366 : }
367 : else
368 24 : panShapeRecordId = (int *)CPLCalloc(sizeof(int),GetFeatureCount());
369 :
370 24 : CPLFree( pszFilename );
371 : }
372 :
373 31 : return TRUE;
374 : }
375 :
376 : /************************************************************************/
377 : /* GetFeature() */
378 : /************************************************************************/
379 :
380 212194 : OGRFeature *TigerCompleteChain::GetFeature( int nRecordId )
381 :
382 : {
383 : char achRecord[OGR_TIGER_RECBUF_LEN];
384 :
385 212194 : if( nRecordId < 0 || nRecordId >= nFeatures )
386 : {
387 : CPLError( CE_Failure, CPLE_FileIO,
388 : "Request for out-of-range feature %d of %s1",
389 0 : nRecordId, pszModule );
390 0 : return NULL;
391 : }
392 :
393 : /* -------------------------------------------------------------------- */
394 : /* Read the raw record data from the file. */
395 : /* -------------------------------------------------------------------- */
396 212194 : if( fpPrimary == NULL )
397 0 : return NULL;
398 :
399 212194 : if( VSIFSeek( fpPrimary, (nRecordId+nRT1RecOffset) * nRecordLength,
400 : SEEK_SET ) != 0 )
401 : {
402 : CPLError( CE_Failure, CPLE_FileIO,
403 : "Failed to seek to %d of %s1",
404 0 : nRecordId * nRecordLength, pszModule );
405 0 : return NULL;
406 : }
407 :
408 212194 : if( VSIFRead( achRecord, psRT1Info->nRecordLength, 1, fpPrimary ) != 1 )
409 : {
410 : CPLError( CE_Failure, CPLE_FileIO,
411 : "Failed to read %d bytes of record %d of %s1 at offset %d",
412 : psRT1Info->nRecordLength, nRecordId, pszModule,
413 0 : (nRecordId+nRT1RecOffset) * nRecordLength );
414 0 : return NULL;
415 : }
416 :
417 : /* -------------------------------------------------------------------- */
418 : /* Set fields. */
419 : /* -------------------------------------------------------------------- */
420 :
421 212194 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
422 :
423 212194 : SetFields( psRT1Info, poFeature, achRecord );
424 :
425 : /* -------------------------------------------------------------------- */
426 : /* Read RT3 record, and apply fields. */
427 : /* -------------------------------------------------------------------- */
428 :
429 212194 : if( fpRT3 != NULL )
430 : {
431 : char achRT3Rec[OGR_TIGER_RECBUF_LEN];
432 0 : int nRT3RecLen = psRT3Info->nRecordLength + nRecordLength - psRT1Info->nRecordLength;
433 :
434 0 : if( VSIFSeek( fpRT3, nRecordId * nRT3RecLen, SEEK_SET ) != 0 )
435 : {
436 : CPLError( CE_Failure, CPLE_FileIO,
437 : "Failed to seek to %d of %s3",
438 0 : nRecordId * nRT3RecLen, pszModule );
439 0 : return NULL;
440 : }
441 :
442 0 : if( VSIFRead( achRT3Rec, psRT3Info->nRecordLength, 1, fpRT3 ) != 1 )
443 : {
444 : CPLError( CE_Failure, CPLE_FileIO,
445 : "Failed to read record %d of %s3",
446 0 : nRecordId, pszModule );
447 0 : return NULL;
448 : }
449 :
450 0 : SetFields( psRT3Info, poFeature, achRT3Rec );
451 :
452 : }
453 :
454 : /* -------------------------------------------------------------------- */
455 : /* Set geometry */
456 : /* -------------------------------------------------------------------- */
457 212194 : OGRLineString *poLine = new OGRLineString();
458 :
459 : poLine->setPoint(0,
460 : atoi(GetField(achRecord, 191, 200)) / 1000000.0,
461 212194 : atoi(GetField(achRecord, 201, 209)) / 1000000.0 );
462 :
463 212194 : if( !AddShapePoints( poFeature->GetFieldAsInteger("TLID"), nRecordId,
464 : poLine, 0 ) )
465 : {
466 0 : delete poFeature;
467 0 : return NULL;
468 : }
469 :
470 : poLine->addPoint(atoi(GetField(achRecord, 210, 219)) / 1000000.0,
471 212194 : atoi(GetField(achRecord, 220, 228)) / 1000000.0 );
472 :
473 212194 : poFeature->SetGeometryDirectly( poLine );
474 :
475 212194 : return poFeature;
476 : }
477 :
478 : /************************************************************************/
479 : /* AddShapePoints() */
480 : /* */
481 : /* Record zero or more shape records associated with this line */
482 : /* and add the points to the passed line geometry. */
483 : /************************************************************************/
484 :
485 212194 : int TigerCompleteChain::AddShapePoints( int nTLID, int nRecordId,
486 : OGRLineString * poLine, int nSeqNum )
487 :
488 : {
489 : int nShapeRecId;
490 :
491 212194 : nShapeRecId = GetShapeRecordId( nRecordId, nTLID );
492 :
493 : // -2 means an error occured.
494 212194 : if( nShapeRecId == -2 )
495 0 : return FALSE;
496 :
497 : // -1 means there are no extra shape vertices, but things worked fine.
498 212194 : if( nShapeRecId == -1 )
499 34354 : return TRUE;
500 :
501 : /* -------------------------------------------------------------------- */
502 : /* Read all the sequential records with the same TLID. */
503 : /* -------------------------------------------------------------------- */
504 : char achShapeRec[OGR_TIGER_RECBUF_LEN];
505 177840 : int nShapeRecLen = psRT2Info->nRecordLength + nRecordLength - psRT1Info->nRecordLength;
506 :
507 171710 : for( ; TRUE; nShapeRecId++ )
508 : {
509 349550 : int nBytesRead = 0;
510 :
511 349550 : if( VSIFSeek( fpShape, (nShapeRecId-1) * nShapeRecLen,
512 : SEEK_SET ) != 0 )
513 : {
514 : CPLError( CE_Failure, CPLE_FileIO,
515 : "Failed to seek to %d of %s2",
516 0 : (nShapeRecId-1) * nShapeRecLen, pszModule );
517 0 : return FALSE;
518 : }
519 :
520 : nBytesRead = VSIFRead( achShapeRec, 1, psRT2Info->nRecordLength,
521 349550 : fpShape );
522 :
523 : /*
524 : ** Handle case where the last record in the file is full. We will
525 : ** try to read another record but not find it. We require that we
526 : ** have found at least one shape record for this case though.
527 : */
528 349550 : if( nBytesRead <= 0 && VSIFEof( fpShape )
529 : && poLine->getNumPoints() > 0 )
530 0 : break;
531 :
532 349550 : if( nBytesRead != psRT2Info->nRecordLength )
533 : {
534 : CPLError( CE_Failure, CPLE_FileIO,
535 : "Failed to read %d bytes of record %d of %s2 at offset %d",
536 : psRT2Info->nRecordLength, nShapeRecId, pszModule,
537 0 : (nShapeRecId-1) * nShapeRecLen );
538 0 : return FALSE;
539 : }
540 :
541 349550 : if( atoi(GetField(achShapeRec,6,15)) != nTLID )
542 10065 : break;
543 :
544 : /* -------------------------------------------------------------------- */
545 : /* Translate the locations into OGRLineString vertices. */
546 : /* -------------------------------------------------------------------- */
547 : int iVertex;
548 :
549 2759154 : for( iVertex = 0; iVertex < 10; iVertex++ )
550 : {
551 2587444 : int iStart = 19 + 19*iVertex;
552 2587444 : int nX = atoi(GetField(achShapeRec,iStart,iStart+9));
553 2587444 : int nY = atoi(GetField(achShapeRec,iStart+10,iStart+18));
554 :
555 2587444 : if( nX == 0 && nY == 0 )
556 167775 : break;
557 :
558 2419669 : poLine->addPoint( nX / 1000000.0, nY / 1000000.0 );
559 : }
560 :
561 : /* -------------------------------------------------------------------- */
562 : /* Don't get another record if this one was incomplete. */
563 : /* -------------------------------------------------------------------- */
564 339485 : if( iVertex < 10 )
565 167775 : break;
566 : }
567 :
568 177840 : return TRUE;
569 : }
570 :
571 : /************************************************************************/
572 : /* GetShapeRecordId() */
573 : /* */
574 : /* Get the record id of the first record of shape points for */
575 : /* the provided TLID (complete chain). */
576 : /************************************************************************/
577 :
578 212194 : int TigerCompleteChain::GetShapeRecordId( int nChainId, int nTLID )
579 :
580 : {
581 212194 : CPLAssert( nChainId >= 0 && nChainId < GetFeatureCount() );
582 :
583 212194 : if( fpShape == NULL || panShapeRecordId == NULL )
584 0 : return -1;
585 :
586 : /* -------------------------------------------------------------------- */
587 : /* Do we already have the answer? */
588 : /* -------------------------------------------------------------------- */
589 212194 : if( panShapeRecordId[nChainId] != 0 )
590 2 : return panShapeRecordId[nChainId];
591 :
592 : /* -------------------------------------------------------------------- */
593 : /* If we don't already have this value, then search from the */
594 : /* previous known record. */
595 : /* -------------------------------------------------------------------- */
596 : int iTestChain, nWorkingRecId;
597 :
598 475594 : for( iTestChain = nChainId-1;
599 263402 : iTestChain >= 0 && panShapeRecordId[iTestChain] <= 0;
600 : iTestChain-- ) {}
601 :
602 212192 : if( iTestChain < 0 )
603 : {
604 18 : iTestChain = -1;
605 18 : nWorkingRecId = 1;
606 : }
607 : else
608 : {
609 212174 : nWorkingRecId = panShapeRecordId[iTestChain]+1;
610 : }
611 :
612 : /* -------------------------------------------------------------------- */
613 : /* If we have non existent records following (-1's) we can */
614 : /* narrow our search a bit. */
615 : /* -------------------------------------------------------------------- */
616 475612 : while( panShapeRecordId[iTestChain+1] == -1 )
617 : {
618 51228 : iTestChain++;
619 : }
620 :
621 : /* -------------------------------------------------------------------- */
622 : /* Read records up to the maximum distance that is possibly */
623 : /* required, looking for our target TLID. */
624 : /* -------------------------------------------------------------------- */
625 212192 : int nMaxChainToRead = nChainId - iTestChain;
626 212192 : int nChainsRead = 0;
627 : char achShapeRec[OGR_TIGER_RECBUF_LEN];
628 212192 : int nShapeRecLen = psRT2Info->nRecordLength + nRecordLength - psRT1Info->nRecordLength;
629 :
630 640733 : while( nChainsRead < nMaxChainToRead )
631 : {
632 394198 : if( VSIFSeek( fpShape, (nWorkingRecId-1) * nShapeRecLen,
633 : SEEK_SET ) != 0 )
634 : {
635 : CPLError( CE_Failure, CPLE_FileIO,
636 : "Failed to seek to %d of %s2",
637 0 : (nWorkingRecId-1) * nShapeRecLen, pszModule );
638 0 : return -2;
639 : }
640 :
641 394198 : if( VSIFRead( achShapeRec, psRT2Info->nRecordLength, 1, fpShape ) != 1 )
642 : {
643 11 : if( !VSIFEof( fpShape ) )
644 : {
645 : CPLError( CE_Failure, CPLE_FileIO,
646 : "Failed to read record %d of %s2",
647 0 : nWorkingRecId-1, pszModule );
648 0 : return -2;
649 : }
650 : else
651 11 : return -1;
652 : }
653 :
654 394187 : if( atoi(GetField(achShapeRec,6,15)) == nTLID )
655 : {
656 177838 : panShapeRecordId[nChainId] = nWorkingRecId;
657 :
658 177838 : return nWorkingRecId;
659 : }
660 :
661 216349 : if( atoi(GetField(achShapeRec,16,18)) == 1 )
662 : {
663 34343 : nChainsRead++;
664 : }
665 :
666 216349 : nWorkingRecId++;
667 : }
668 :
669 34343 : panShapeRecordId[nChainId] = -1;
670 :
671 34343 : return -1;
672 : }
673 :
674 : /************************************************************************/
675 : /* SetWriteModule() */
676 : /************************************************************************/
677 19289 : int TigerCompleteChain::SetWriteModule( const char *pszFileCode, int nRecLen,
678 : OGRFeature *poFeature )
679 :
680 : {
681 : int bSuccess;
682 :
683 19289 : bSuccess = TigerFileBase::SetWriteModule( pszFileCode, nRecLen, poFeature);
684 19289 : if( !bSuccess )
685 0 : return bSuccess;
686 :
687 : /* -------------------------------------------------------------------- */
688 : /* Open the RT3 file */
689 : /* -------------------------------------------------------------------- */
690 19289 : if( bUsingRT3 )
691 : {
692 0 : if( fpRT3 != NULL )
693 : {
694 0 : VSIFClose( fpRT3 );
695 0 : fpRT3 = NULL;
696 : }
697 :
698 0 : if( pszModule )
699 : {
700 : char *pszFilename;
701 :
702 0 : pszFilename = poDS->BuildFilename( pszModule, "3" );
703 :
704 0 : fpRT3 = VSIFOpen( pszFilename, "ab" );
705 :
706 0 : CPLFree( pszFilename );
707 : }
708 : }
709 :
710 : /* -------------------------------------------------------------------- */
711 : /* Close the shape point file, if open and free the list of */
712 : /* record ids. */
713 : /* -------------------------------------------------------------------- */
714 19289 : if( fpShape != NULL )
715 : {
716 19288 : VSIFClose( fpShape );
717 19288 : fpShape = NULL;
718 : }
719 :
720 19289 : if( pszModule )
721 : {
722 : char *pszFilename;
723 :
724 19289 : pszFilename = poDS->BuildFilename( pszModule, "2" );
725 :
726 19289 : fpShape = VSIFOpen( pszFilename, "ab" );
727 :
728 19289 : CPLFree( pszFilename );
729 : }
730 :
731 19289 : return TRUE;
732 : }
733 :
734 : /************************************************************************/
735 : /* CreateFeature() */
736 : /************************************************************************/
737 :
738 19289 : OGRErr TigerCompleteChain::CreateFeature( OGRFeature *poFeature )
739 :
740 : {
741 : char szRecord[OGR_TIGER_RECBUF_LEN];
742 19289 : OGRLineString *poLine = (OGRLineString *) poFeature->GetGeometryRef();
743 :
744 38578 : if( poLine == NULL
745 19289 : || (poLine->getGeometryType() != wkbLineString
746 0 : && poLine->getGeometryType() != wkbLineString25D) )
747 0 : return OGRERR_FAILURE;
748 :
749 : /* -------------------------------------------------------------------- */
750 : /* Write basic data record ("RT1") */
751 : /* -------------------------------------------------------------------- */
752 19289 : if( !SetWriteModule( "1", psRT1Info->nRecordLength+2, poFeature ) )
753 0 : return OGRERR_FAILURE;
754 19289 : memset( szRecord, ' ', psRT1Info->nRecordLength );
755 19289 : WriteFields( psRT1Info, poFeature, szRecord );
756 19289 : WritePoint( szRecord, 191, poLine->getX(0), poLine->getY(0) );
757 : WritePoint( szRecord, 210,
758 : poLine->getX(poLine->getNumPoints()-1),
759 19289 : poLine->getY(poLine->getNumPoints()-1) );
760 19289 : WriteRecord( szRecord, psRT1Info->nRecordLength, "1" );
761 :
762 : /* -------------------------------------------------------------------- */
763 : /* Write geographic entity codes (RT3) */
764 : /* -------------------------------------------------------------------- */
765 19289 : if (bUsingRT3) {
766 0 : memset( szRecord, ' ', psRT3Info->nRecordLength );
767 0 : WriteFields( psRT3Info, poFeature, szRecord );
768 0 : WriteRecord( szRecord, psRT3Info->nRecordLength, "3", fpRT3 );
769 : }
770 :
771 : /* -------------------------------------------------------------------- */
772 : /* Write shapes sections (RT2) */
773 : /* -------------------------------------------------------------------- */
774 19289 : if( poLine->getNumPoints() > 2 )
775 : {
776 16166 : int nPoints = poLine->getNumPoints();
777 16166 : int iPoint, nRTSQ = 1;
778 :
779 63193 : for( iPoint = 1; iPoint < nPoints-1; )
780 : {
781 : int i;
782 : char szTemp[5];
783 :
784 30861 : memset( szRecord, ' ', psRT2Info->nRecordLength );
785 :
786 30861 : WriteField( poFeature, "TLID", szRecord, 6, 15, 'R', 'N' );
787 :
788 30861 : sprintf( szTemp, "%3d", nRTSQ );
789 30861 : strncpy( ((char *)szRecord) + 15, szTemp, 4 );
790 :
791 339471 : for( i = 0; i < 10; i++ )
792 : {
793 308610 : if( iPoint < nPoints-1 )
794 : WritePoint( szRecord, 19+19*i,
795 219965 : poLine->getX(iPoint), poLine->getY(iPoint) );
796 : else
797 88645 : WritePoint( szRecord, 19+19*i, 0.0, 0.0 );
798 :
799 308610 : iPoint++;
800 : }
801 :
802 30861 : WriteRecord( szRecord, psRT2Info->nRecordLength, "2", fpShape );
803 :
804 30861 : nRTSQ++;
805 : }
806 : }
807 :
808 19289 : return OGRERR_NONE;
809 : }
|