/src/gdal/ogr/ogrsf_frmts/avc/avc_e00gen.cpp
Line | Count | Source |
1 | | /********************************************************************** |
2 | | * |
3 | | * Name: avc_e00gen.c |
4 | | * Project: Arc/Info vector coverage (AVC) BIN->E00 conversion library |
5 | | * Language: ANSI C |
6 | | * Purpose: Functions to generate ASCII E00 lines form binary structures. |
7 | | * Author: Daniel Morissette, dmorissette@dmsolutions.ca |
8 | | * |
9 | | ********************************************************************** |
10 | | * Copyright (c) 1999-2005, Daniel Morissette |
11 | | * |
12 | | * SPDX-License-Identifier: MIT |
13 | | ********************************************************************** |
14 | | * |
15 | | * $Log: avc_e00gen.c,v $ |
16 | | * Revision 1.18 2008/07/23 20:51:38 dmorissette |
17 | | * Fixed GCC 4.1.x compile warnings related to use of char vs unsigned char |
18 | | * (GDAL/OGR ticket http://trac.osgeo.org/gdal/ticket/2495) |
19 | | * |
20 | | * Revision 1.17 2006/06/14 15:01:33 daniel |
21 | | * Remove any embedded '\0' from data line in AVCE00GenTableRec() |
22 | | * |
23 | | * Revision 1.16 2005/06/03 03:49:58 daniel |
24 | | * Update email address, website url, and copyright dates |
25 | | * |
26 | | * Revision 1.15 2004/08/19 17:48:20 warmerda |
27 | | * Avoid uninitialized variable warnings. |
28 | | * |
29 | | * Revision 1.14 2001/11/25 21:15:23 daniel |
30 | | * Added hack (AVC_MAP_TYPE40_TO_DOUBLE) to map type 40 fields bigger than 8 |
31 | | * digits to double precision as we generate E00 output (bug599) |
32 | | * |
33 | | * Revision 1.13 2001/11/19 20:39:48 daniel |
34 | | * Change to correctly format 0-arc PAL records, so that they have a |
35 | | * single "filler" arc record |
36 | | * |
37 | | * Revision 1.12 2000/09/26 20:21:04 daniel |
38 | | * Added AVCCoverPC write |
39 | | * |
40 | | * Revision 1.11 2000/09/22 19:45:20 daniel |
41 | | * Switch to MIT-style license |
42 | | * |
43 | | * Revision 1.10 2000/02/04 04:54:03 daniel |
44 | | * Fixed warnings |
45 | | * |
46 | | * Revision 1.9 2000/02/03 07:21:02 daniel |
47 | | * TXT/TX6 with string longer than 80 chars: split string in 80 chars chunks |
48 | | * |
49 | | * Revision 1.8 2000/02/02 04:28:00 daniel |
50 | | * Fixed support of TX6/RXP/RPL coming from "weird" coverages |
51 | | * |
52 | | * Revision 1.7 1999/08/23 18:20:49 daniel |
53 | | * Fixed support for attribute fields type 40 |
54 | | * |
55 | | * Revision 1.6 1999/05/17 16:19:39 daniel |
56 | | * Made sure ACVE00GenTableRec() removes all spaces at the end of a |
57 | | * table record line (it used to leave one space) |
58 | | * |
59 | | * Revision 1.5 1999/05/11 02:08:17 daniel |
60 | | * Simple changes related to the addition of coverage write support. |
61 | | * |
62 | | * Revision 1.4 1999/03/03 02:06:38 daniel |
63 | | * Properly handle 8 bytes floats inside single precision tables. |
64 | | * |
65 | | * Revision 1.3 1999/02/25 17:01:58 daniel |
66 | | * Added support for 16 bit integers in INFO tables (type=50, size=2) |
67 | | * |
68 | | * Revision 1.2 1999/02/25 04:17:51 daniel |
69 | | * Added TXT, TX6/TX7, RXP and RPL support + some minor changes |
70 | | * |
71 | | * Revision 1.1 1999/01/29 16:28:52 daniel |
72 | | * Initial revision |
73 | | * |
74 | | **********************************************************************/ |
75 | | |
76 | | #include "avc.h" |
77 | | |
78 | | #include <algorithm> |
79 | | #include <cassert> |
80 | | #include <cmath> |
81 | | #include <ctype.h> /* toupper() */ |
82 | | |
83 | | /********************************************************************** |
84 | | * AVCE00GenInfoAlloc() |
85 | | * |
86 | | * Allocate and initialize a new AVCE00GenInfo structure. |
87 | | * |
88 | | * The structure will eventually have to be freed with AVCE00GenInfoFree(). |
89 | | **********************************************************************/ |
90 | | AVCE00GenInfo *AVCE00GenInfoAlloc(int nCoverPrecision) |
91 | 16.1k | { |
92 | 16.1k | AVCE00GenInfo *psInfo; |
93 | | |
94 | 16.1k | psInfo = (AVCE00GenInfo *)CPLCalloc(1, sizeof(AVCE00GenInfo)); |
95 | | |
96 | | /* Allocate output buffer. |
97 | | * 2k should be enough... the biggest thing we'll need to store |
98 | | * in it will be 1 complete INFO table record. |
99 | | */ |
100 | 16.1k | psInfo->nBufSize = 2048; |
101 | 16.1k | psInfo->pszBuf = (char *)CPLMalloc(psInfo->nBufSize * sizeof(char)); |
102 | | |
103 | 16.1k | psInfo->nPrecision = nCoverPrecision; |
104 | | |
105 | 16.1k | return psInfo; |
106 | 16.1k | } |
107 | | |
108 | | /********************************************************************** |
109 | | * AVCE00GenInfoFree() |
110 | | * |
111 | | * Free any memory associated with a AVCE00GenInfo structure. |
112 | | **********************************************************************/ |
113 | | void AVCE00GenInfoFree(AVCE00GenInfo *psInfo) |
114 | 16.1k | { |
115 | 16.1k | if (psInfo) |
116 | 16.1k | CPLFree(psInfo->pszBuf); |
117 | 16.1k | CPLFree(psInfo); |
118 | 16.1k | } |
119 | | |
120 | | /********************************************************************** |
121 | | * AVCE00GenReset() |
122 | | * |
123 | | * Reset the fields in the AVCE00GenInfo structure so that further calls |
124 | | * with bCont = TRUE (ex: AVCE00GenArc(psInfo, TRUE)) would return nullptr. |
125 | | **********************************************************************/ |
126 | | void AVCE00GenReset(AVCE00GenInfo *psInfo) |
127 | 0 | { |
128 | | /* Reinitialize counters so that further calls with bCont = TRUE, |
129 | | * like AVCE00GenArc(psInfo, TRUE) would return nullptr. |
130 | | */ |
131 | 0 | psInfo->iCurItem = psInfo->numItems = 0; |
132 | 0 | } |
133 | | |
134 | | /********************************************************************** |
135 | | * AVCE00GenStartSection() |
136 | | * |
137 | | * Generate the first line of an E00 section. |
138 | | * |
139 | | * pszClassName applies only to JABBERWOCKY type of sections. |
140 | | **********************************************************************/ |
141 | | const char *AVCE00GenStartSection(AVCE00GenInfo *psInfo, AVCFileType eType, |
142 | | const char *pszClassName) |
143 | 0 | { |
144 | 0 | const char *pszName = "UNK"; |
145 | |
|
146 | 0 | AVCE00GenReset(psInfo); |
147 | |
|
148 | 0 | if (eType == AVCFileTX6 || eType == AVCFileRXP || eType == AVCFileRPL) |
149 | 0 | { |
150 | | /* TX6/RXP/RPL sections start with the class name (the basename |
151 | | * of the file) in uppercase. |
152 | | * ex: The section for "cities.txt" would start with "CITIES" |
153 | | */ |
154 | 0 | int i; |
155 | 0 | for (i = 0; pszClassName[i] != '\0'; i++) |
156 | 0 | { |
157 | 0 | psInfo->pszBuf[i] = |
158 | 0 | (char)CPLToupper(static_cast<unsigned char>(pszClassName[i])); |
159 | 0 | } |
160 | 0 | psInfo->pszBuf[i] = '\0'; |
161 | 0 | } |
162 | 0 | else |
163 | 0 | { |
164 | | /* In most cases, the section starts with a 3 letters code followed |
165 | | * by the precision code (2 or 3) |
166 | | */ |
167 | 0 | switch (eType) |
168 | 0 | { |
169 | 0 | case AVCFileARC: |
170 | 0 | pszName = "ARC"; |
171 | 0 | break; |
172 | 0 | case AVCFilePAL: |
173 | 0 | pszName = "PAL"; |
174 | 0 | break; |
175 | 0 | case AVCFileCNT: |
176 | 0 | pszName = "CNT"; |
177 | 0 | break; |
178 | 0 | case AVCFileLAB: |
179 | 0 | pszName = "LAB"; |
180 | 0 | break; |
181 | 0 | case AVCFileTOL: |
182 | 0 | pszName = "TOL"; |
183 | 0 | break; |
184 | 0 | case AVCFilePRJ: |
185 | 0 | pszName = "PRJ"; |
186 | 0 | break; |
187 | 0 | case AVCFileTXT: |
188 | 0 | pszName = "TXT"; |
189 | 0 | break; |
190 | 0 | default: |
191 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
192 | 0 | "Unsupported E00 section type!"); |
193 | 0 | } |
194 | | |
195 | 0 | if (psInfo->nPrecision == AVC_DOUBLE_PREC) |
196 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%s 3", pszName); |
197 | 0 | else |
198 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%s 2", pszName); |
199 | 0 | } |
200 | | |
201 | 0 | return psInfo->pszBuf; |
202 | 0 | } |
203 | | |
204 | | /********************************************************************** |
205 | | * AVCE00GenEndSection() |
206 | | * |
207 | | * Generate the last line(s) of an E00 section. |
208 | | * |
209 | | * This function should be called once with bCont=FALSE to get the |
210 | | * first "end of section" line for the current section, and then call |
211 | | * with bCont=TRUE to get all the other lines. |
212 | | * |
213 | | * The function returns nullptr when there are no more lines to generate |
214 | | * for this "end of section". |
215 | | **********************************************************************/ |
216 | | const char *AVCE00GenEndSection(AVCE00GenInfo *psInfo, AVCFileType eType, |
217 | | GBool bCont) |
218 | 0 | { |
219 | 0 | if (bCont == FALSE) |
220 | 0 | { |
221 | | /*------------------------------------------------------------- |
222 | | * Most section types end with only 1 line. |
223 | | *------------------------------------------------------------*/ |
224 | 0 | AVCE00GenReset(psInfo); |
225 | 0 | psInfo->iCurItem = 0; |
226 | |
|
227 | 0 | if (eType == AVCFileARC || eType == AVCFilePAL || eType == AVCFileRPL || |
228 | 0 | eType == AVCFileCNT || eType == AVCFileTOL || eType == AVCFileTXT || |
229 | 0 | eType == AVCFileTX6) |
230 | 0 | { |
231 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
232 | 0 | " -1 0 0 0 0 " |
233 | 0 | " 0 0"); |
234 | 0 | } |
235 | 0 | else if (eType == AVCFileLAB) |
236 | 0 | { |
237 | 0 | if (psInfo->nPrecision == AVC_DOUBLE_PREC) |
238 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
239 | 0 | " -1 0 0.00000000000000E+00 " |
240 | 0 | "0.00000000000000E+00"); |
241 | 0 | else |
242 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
243 | 0 | " -1 0 0.0000000E+00 0.0000000E+00"); |
244 | 0 | } |
245 | 0 | else if (eType == AVCFilePRJ) |
246 | 0 | { |
247 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "EOP"); |
248 | 0 | } |
249 | 0 | else if (eType == AVCFileRXP) |
250 | 0 | { |
251 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, " -1 0"); |
252 | 0 | } |
253 | 0 | else |
254 | 0 | { |
255 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
256 | 0 | "Unsupported E00 section type!"); |
257 | 0 | return nullptr; |
258 | 0 | } |
259 | 0 | } |
260 | 0 | else if (psInfo->iCurItem == 0 && psInfo->nPrecision == AVC_DOUBLE_PREC && |
261 | 0 | (eType == AVCFilePAL || eType == AVCFileRPL)) |
262 | 0 | { |
263 | | /*--------------------------------------------------------- |
264 | | * Return the 2nd line for the end of a PAL or RPL section. |
265 | | *--------------------------------------------------------*/ |
266 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
267 | 0 | " 0.00000000000000E+00 0.00000000000000E+00"); |
268 | |
|
269 | 0 | psInfo->iCurItem++; |
270 | 0 | } |
271 | 0 | else |
272 | 0 | { |
273 | | /*----------------------------------------------------- |
274 | | * All other section types end with only one line, and thus |
275 | | * we return nullptr when bCont==TRUE |
276 | | *----------------------------------------------------*/ |
277 | 0 | return nullptr; |
278 | 0 | } |
279 | | |
280 | 0 | return psInfo->pszBuf; |
281 | 0 | } |
282 | | |
283 | | /********************************************************************** |
284 | | * AVCE00GenObject() |
285 | | * |
286 | | * Cover function on top of AVCE00GenArc/Pal/Cnt/Lab() that will |
287 | | * call the right function according to argument eType. |
288 | | * |
289 | | * Since there is no compiler type checking on psObj, you have to |
290 | | * be very careful to make sure you pass an object of the right type |
291 | | * when you use this function! |
292 | | * |
293 | | * The function returns nullptr when there are no more lines to generate |
294 | | * for this ARC. |
295 | | **********************************************************************/ |
296 | | const char *AVCE00GenObject(AVCE00GenInfo *psInfo, AVCFileType eType, |
297 | | void *psObj, GBool bCont) |
298 | 0 | { |
299 | 0 | const char *pszLine = nullptr; |
300 | |
|
301 | 0 | switch (eType) |
302 | 0 | { |
303 | 0 | case AVCFileARC: |
304 | 0 | pszLine = AVCE00GenArc(psInfo, (AVCArc *)psObj, bCont); |
305 | 0 | break; |
306 | 0 | case AVCFilePAL: |
307 | 0 | case AVCFileRPL: |
308 | 0 | pszLine = AVCE00GenPal(psInfo, (AVCPal *)psObj, bCont); |
309 | 0 | break; |
310 | 0 | case AVCFileCNT: |
311 | 0 | pszLine = AVCE00GenCnt(psInfo, (AVCCnt *)psObj, bCont); |
312 | 0 | break; |
313 | 0 | case AVCFileLAB: |
314 | 0 | pszLine = AVCE00GenLab(psInfo, (AVCLab *)psObj, bCont); |
315 | 0 | break; |
316 | 0 | case AVCFileTOL: |
317 | 0 | pszLine = AVCE00GenTol(psInfo, (AVCTol *)psObj, bCont); |
318 | 0 | break; |
319 | 0 | case AVCFileTXT: |
320 | 0 | pszLine = AVCE00GenTxt(psInfo, (AVCTxt *)psObj, bCont); |
321 | 0 | break; |
322 | 0 | case AVCFileTX6: |
323 | 0 | pszLine = AVCE00GenTx6(psInfo, (AVCTxt *)psObj, bCont); |
324 | 0 | break; |
325 | 0 | case AVCFilePRJ: |
326 | 0 | pszLine = AVCE00GenPrj(psInfo, (char **)psObj, bCont); |
327 | 0 | break; |
328 | 0 | case AVCFileRXP: |
329 | 0 | pszLine = AVCE00GenRxp(psInfo, (AVCRxp *)psObj, bCont); |
330 | 0 | break; |
331 | 0 | default: |
332 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
333 | 0 | "AVCE00GenObject(): Unsupported file type!"); |
334 | 0 | } |
335 | | |
336 | 0 | return pszLine; |
337 | 0 | } |
338 | | |
339 | | /*===================================================================== |
340 | | ARC stuff |
341 | | =====================================================================*/ |
342 | | |
343 | | /********************************************************************** |
344 | | * AVCE00GenArc() |
345 | | * |
346 | | * Generate the next line of an E00 ARC. |
347 | | * |
348 | | * This function should be called once with bCont=FALSE to get the |
349 | | * first E00 line for the current ARC, and then call with bCont=TRUE |
350 | | * to get all the other lines for this ARC. |
351 | | * |
352 | | * The function returns nullptr when there are no more lines to generate |
353 | | * for this ARC. |
354 | | **********************************************************************/ |
355 | | const char *AVCE00GenArc(AVCE00GenInfo *psInfo, AVCArc *psArc, GBool bCont) |
356 | 0 | { |
357 | 0 | if (bCont == FALSE) |
358 | 0 | { |
359 | | /* Initialize the psInfo structure with info about the |
360 | | * current ARC. |
361 | | */ |
362 | 0 | psInfo->iCurItem = 0; |
363 | 0 | if (psInfo->nPrecision == AVC_DOUBLE_PREC) |
364 | 0 | psInfo->numItems = psArc->numVertices; |
365 | 0 | else |
366 | 0 | psInfo->numItems = (psArc->numVertices + 1) / 2; |
367 | | |
368 | | /* And return the ARC header line |
369 | | */ |
370 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
371 | 0 | "%10d%10d%10d%10d%10d%10d%10d", psArc->nArcId, psArc->nUserId, |
372 | 0 | psArc->nFNode, psArc->nTNode, psArc->nLPoly, psArc->nRPoly, |
373 | 0 | psArc->numVertices); |
374 | 0 | } |
375 | 0 | else if (psInfo->iCurItem < psInfo->numItems) |
376 | 0 | { |
377 | 0 | int iVertex; |
378 | | |
379 | | /* return the next set of vertices for the ARC. |
380 | | */ |
381 | 0 | if (psInfo->nPrecision == AVC_DOUBLE_PREC) |
382 | 0 | { |
383 | 0 | iVertex = psInfo->iCurItem; |
384 | |
|
385 | 0 | psInfo->pszBuf[0] = '\0'; |
386 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
387 | 0 | psInfo->nPrecision, AVCFileARC, |
388 | 0 | psArc->pasVertices[iVertex].x); |
389 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
390 | 0 | psInfo->nPrecision, AVCFileARC, |
391 | 0 | psArc->pasVertices[iVertex].y); |
392 | 0 | } |
393 | 0 | else |
394 | 0 | { |
395 | 0 | iVertex = psInfo->iCurItem * 2; |
396 | |
|
397 | 0 | psInfo->pszBuf[0] = '\0'; |
398 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
399 | 0 | psInfo->nPrecision, AVCFileARC, |
400 | 0 | psArc->pasVertices[iVertex].x); |
401 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
402 | 0 | psInfo->nPrecision, AVCFileARC, |
403 | 0 | psArc->pasVertices[iVertex].y); |
404 | | |
405 | | /* Check because if we have a odd number of vertices then |
406 | | * the last line contains only one pair of vertices. |
407 | | */ |
408 | 0 | if (iVertex + 1 < psArc->numVertices) |
409 | 0 | { |
410 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
411 | 0 | psInfo->nPrecision, AVCFileARC, |
412 | 0 | psArc->pasVertices[iVertex + 1].x); |
413 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
414 | 0 | psInfo->nPrecision, AVCFileARC, |
415 | 0 | psArc->pasVertices[iVertex + 1].y); |
416 | 0 | } |
417 | 0 | } |
418 | 0 | psInfo->iCurItem++; |
419 | 0 | } |
420 | 0 | else |
421 | 0 | { |
422 | | /* No more lines to generate for this ARC. |
423 | | */ |
424 | 0 | return nullptr; |
425 | 0 | } |
426 | | |
427 | 0 | return psInfo->pszBuf; |
428 | 0 | } |
429 | | |
430 | | /*===================================================================== |
431 | | PAL stuff |
432 | | =====================================================================*/ |
433 | | |
434 | | /********************************************************************** |
435 | | * AVCE00GenPal() |
436 | | * |
437 | | * Generate the next line of an E00 PAL (Polygon Arc List) entry. |
438 | | * |
439 | | * This function should be called once with bCont=FALSE to get the |
440 | | * first E00 line for the current PAL, and then call with bCont=TRUE |
441 | | * to get all the other lines for this PAL. |
442 | | * |
443 | | * The function returns nullptr when there are no more lines to generate |
444 | | * for this PAL entry. |
445 | | **********************************************************************/ |
446 | | const char *AVCE00GenPal(AVCE00GenInfo *psInfo, AVCPal *psPal, GBool bCont) |
447 | 0 | { |
448 | 0 | if (bCont == FALSE) |
449 | 0 | { |
450 | | /* Initialize the psInfo structure with info about the |
451 | | * current PAL. (Number of lines excluding header) |
452 | | */ |
453 | 0 | psInfo->numItems = (psPal->numArcs + 1) / 2; |
454 | | |
455 | | /* And return the PAL header line. |
456 | | */ |
457 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d", psPal->numArcs); |
458 | |
|
459 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
460 | 0 | AVCFilePAL, psPal->sMin.x); |
461 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
462 | 0 | AVCFilePAL, psPal->sMin.y); |
463 | | |
464 | | /* Double precision PAL entries have their header on 2 lines! |
465 | | */ |
466 | 0 | if (psInfo->nPrecision == AVC_DOUBLE_PREC) |
467 | 0 | { |
468 | 0 | psInfo->iCurItem = -1; /* Means 1 line left in header */ |
469 | 0 | } |
470 | 0 | else |
471 | 0 | { |
472 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
473 | 0 | psInfo->nPrecision, AVCFilePAL, psPal->sMax.x); |
474 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
475 | 0 | psInfo->nPrecision, AVCFilePAL, psPal->sMax.y); |
476 | 0 | psInfo->iCurItem = 0; /* Next thing = first Arc entry */ |
477 | 0 | } |
478 | 0 | } |
479 | 0 | else if (psInfo->iCurItem == -1) |
480 | 0 | { |
481 | | /* Second (and last) header line for double precision coverages |
482 | | */ |
483 | 0 | psInfo->pszBuf[0] = '\0'; |
484 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
485 | 0 | AVCFilePAL, psPal->sMax.x); |
486 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
487 | 0 | AVCFilePAL, psPal->sMax.y); |
488 | |
|
489 | 0 | if (psInfo->numItems == 0) |
490 | 0 | { |
491 | 0 | psInfo->iCurItem = -2; /* We have a 0-arc polygon, which needs |
492 | | an arc list with one "0 0 0" element */ |
493 | 0 | } |
494 | 0 | else |
495 | 0 | { |
496 | 0 | psInfo->iCurItem = 0; /* Next thing = first Arc entry */ |
497 | 0 | } |
498 | 0 | } |
499 | 0 | else if (psInfo->iCurItem == -2) |
500 | 0 | { |
501 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d%10d", 0, 0, 0); |
502 | 0 | psInfo->iCurItem = 0; /* Next thing = first Arc entry */ |
503 | 0 | } |
504 | 0 | else if (psInfo->iCurItem < psInfo->numItems) |
505 | 0 | { |
506 | | /* Return PAL Arc entries... |
507 | | */ |
508 | 0 | int iArc; |
509 | |
|
510 | 0 | iArc = psInfo->iCurItem * 2; |
511 | | |
512 | | /* If we have a odd number of arcs then |
513 | | * the last line contains only one arc entry. |
514 | | */ |
515 | 0 | if (iArc + 1 < psPal->numArcs) |
516 | 0 | { |
517 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
518 | 0 | "%10d%10d%10d%10d%10d%10d", psPal->pasArcs[iArc].nArcId, |
519 | 0 | psPal->pasArcs[iArc].nFNode, psPal->pasArcs[iArc].nAdjPoly, |
520 | 0 | psPal->pasArcs[iArc + 1].nArcId, |
521 | 0 | psPal->pasArcs[iArc + 1].nFNode, |
522 | 0 | psPal->pasArcs[iArc + 1].nAdjPoly); |
523 | 0 | } |
524 | 0 | else |
525 | 0 | { |
526 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d%10d", |
527 | 0 | psPal->pasArcs[iArc].nArcId, psPal->pasArcs[iArc].nFNode, |
528 | 0 | psPal->pasArcs[iArc].nAdjPoly); |
529 | 0 | } |
530 | 0 | psInfo->iCurItem++; |
531 | 0 | } |
532 | 0 | else |
533 | 0 | { |
534 | | /* No more lines to generate for this PAL. |
535 | | */ |
536 | 0 | return nullptr; |
537 | 0 | } |
538 | | |
539 | 0 | return psInfo->pszBuf; |
540 | 0 | } |
541 | | |
542 | | /*===================================================================== |
543 | | CNT stuff |
544 | | =====================================================================*/ |
545 | | |
546 | | /********************************************************************** |
547 | | * AVCE00GenCnt() |
548 | | * |
549 | | * Generate the next line of an E00 CNT (Polygon Centroid) entry. |
550 | | * |
551 | | * This function should be called once with bCont=FALSE to get the |
552 | | * first E00 line for the current CNT, and then call with bCont=TRUE |
553 | | * to get all the other lines for this CNT. |
554 | | * |
555 | | * The function returns nullptr when there are no more lines to generate |
556 | | * for this CNT entry. |
557 | | **********************************************************************/ |
558 | | const char *AVCE00GenCnt(AVCE00GenInfo *psInfo, AVCCnt *psCnt, GBool bCont) |
559 | 0 | { |
560 | 0 | if (bCont == FALSE) |
561 | 0 | { |
562 | | /* Initialize the psInfo structure with info about the |
563 | | * current CNT. |
564 | | */ |
565 | 0 | psInfo->iCurItem = 0; |
566 | 0 | psInfo->numItems = (psCnt->numLabels + 7) / 8; |
567 | | |
568 | | /* And return the CNT header line. |
569 | | */ |
570 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d", psCnt->numLabels); |
571 | |
|
572 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
573 | 0 | AVCFileCNT, psCnt->sCoord.x); |
574 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
575 | 0 | AVCFileCNT, psCnt->sCoord.y); |
576 | 0 | } |
577 | 0 | else if (psInfo->iCurItem < psInfo->numItems) |
578 | 0 | { |
579 | | /* Return CNT Label Ids, 8 label Ids per line... |
580 | | */ |
581 | 0 | int i, nFirstLabel, numLabels; |
582 | |
|
583 | 0 | nFirstLabel = psInfo->iCurItem * 8; |
584 | 0 | numLabels = std::min(8, (psCnt->numLabels - nFirstLabel)); |
585 | |
|
586 | 0 | psInfo->pszBuf[0] = '\0'; |
587 | 0 | for (i = 0; i < numLabels; i++) |
588 | 0 | { |
589 | 0 | snprintf(psInfo->pszBuf + strlen(psInfo->pszBuf), |
590 | 0 | psInfo->nBufSize - strlen(psInfo->pszBuf), "%10d", |
591 | 0 | psCnt->panLabelIds[nFirstLabel + i]); |
592 | 0 | } |
593 | |
|
594 | 0 | psInfo->iCurItem++; |
595 | 0 | } |
596 | 0 | else |
597 | 0 | { |
598 | | /* No more lines to generate for this CNT. |
599 | | */ |
600 | 0 | return nullptr; |
601 | 0 | } |
602 | | |
603 | 0 | return psInfo->pszBuf; |
604 | 0 | } |
605 | | |
606 | | /*===================================================================== |
607 | | LAB stuff |
608 | | =====================================================================*/ |
609 | | |
610 | | /********************************************************************** |
611 | | * AVCE00GenLab() |
612 | | * |
613 | | * Generate the next line of an E00 LAB (Label) entry. |
614 | | * |
615 | | * This function should be called once with bCont=FALSE to get the |
616 | | * first E00 line for the current LAB, and then call with bCont=TRUE |
617 | | * to get all the other lines for this LAB. |
618 | | * |
619 | | * The function returns nullptr when there are no more lines to generate |
620 | | * for this LAB entry. |
621 | | **********************************************************************/ |
622 | | const char *AVCE00GenLab(AVCE00GenInfo *psInfo, AVCLab *psLab, GBool bCont) |
623 | 0 | { |
624 | 0 | if (bCont == FALSE) |
625 | 0 | { |
626 | | /* Initialize the psInfo structure with info about the |
627 | | * current LAB. (numItems = Number of lines excluding header) |
628 | | */ |
629 | 0 | psInfo->iCurItem = 0; |
630 | 0 | if (psInfo->nPrecision == AVC_DOUBLE_PREC) |
631 | 0 | psInfo->numItems = 2; |
632 | 0 | else |
633 | 0 | psInfo->numItems = 1; |
634 | | |
635 | | /* And return the LAB header line. |
636 | | */ |
637 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d", psLab->nValue, |
638 | 0 | psLab->nPolyId); |
639 | |
|
640 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
641 | 0 | AVCFileLAB, psLab->sCoord1.x); |
642 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
643 | 0 | AVCFileLAB, psLab->sCoord1.y); |
644 | 0 | } |
645 | 0 | else if (psInfo->iCurItem < psInfo->numItems) |
646 | 0 | { |
647 | | /* Return next Label coordinates... |
648 | | */ |
649 | 0 | if (psInfo->nPrecision != AVC_DOUBLE_PREC) |
650 | 0 | { |
651 | | /* Single precision, all on the same line |
652 | | */ |
653 | 0 | psInfo->pszBuf[0] = '\0'; |
654 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
655 | 0 | psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.x); |
656 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
657 | 0 | psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.y); |
658 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
659 | 0 | psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.x); |
660 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
661 | 0 | psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.y); |
662 | 0 | } |
663 | 0 | else if (psInfo->iCurItem == 0) |
664 | 0 | { |
665 | | /* 2nd line, in a double precision coverage |
666 | | */ |
667 | 0 | psInfo->pszBuf[0] = '\0'; |
668 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
669 | 0 | psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.x); |
670 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
671 | 0 | psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.y); |
672 | 0 | } |
673 | 0 | else |
674 | 0 | { |
675 | | /* 3rd line, in a double precision coverage |
676 | | */ |
677 | 0 | psInfo->pszBuf[0] = '\0'; |
678 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
679 | 0 | psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.x); |
680 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
681 | 0 | psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.y); |
682 | 0 | } |
683 | |
|
684 | 0 | psInfo->iCurItem++; |
685 | 0 | } |
686 | 0 | else |
687 | 0 | { |
688 | | /* No more lines to generate for this LAB. |
689 | | */ |
690 | 0 | return nullptr; |
691 | 0 | } |
692 | | |
693 | 0 | return psInfo->pszBuf; |
694 | 0 | } |
695 | | |
696 | | /*===================================================================== |
697 | | TOL stuff |
698 | | =====================================================================*/ |
699 | | |
700 | | /********************************************************************** |
701 | | * AVCE00GenTol() |
702 | | * |
703 | | * Generate the next line of an E00 TOL (Tolerance) entry. |
704 | | * |
705 | | * This function should be called once with bCont=FALSE to get the |
706 | | * first E00 line for the current TOL, and then call with bCont=TRUE |
707 | | * to get all the other lines for this TOL. |
708 | | * |
709 | | * The function returns nullptr when there are no more lines to generate |
710 | | * for this TOL entry. |
711 | | **********************************************************************/ |
712 | | const char *AVCE00GenTol(AVCE00GenInfo *psInfo, AVCTol *psTol, GBool bCont) |
713 | 0 | { |
714 | 0 | if (bCont == TRUE) |
715 | 0 | { |
716 | | /*--------------------------------------------------------- |
717 | | * TOL entries are only 1 line, we support the bCont flag |
718 | | * only for compatibility with the other AVCE00Gen*() functions. |
719 | | *--------------------------------------------------------*/ |
720 | 0 | return nullptr; |
721 | 0 | } |
722 | | |
723 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d", psTol->nIndex, |
724 | 0 | psTol->nFlag); |
725 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
726 | 0 | AVCFileTOL, psTol->dValue); |
727 | |
|
728 | 0 | return psInfo->pszBuf; |
729 | 0 | } |
730 | | |
731 | | /*===================================================================== |
732 | | PRJ stuff |
733 | | =====================================================================*/ |
734 | | |
735 | | /********************************************************************** |
736 | | * AVCE00GenPrj() |
737 | | * |
738 | | * Generate the next line of an E00 PRJ (Projection) section. |
739 | | * |
740 | | * This function should be called once with bCont=FALSE to get the |
741 | | * first E00 line for the current PRJ, and then call with bCont=TRUE |
742 | | * to get all the other lines for this PRJ. |
743 | | * |
744 | | * The function returns nullptr when there are no more lines to generate |
745 | | * for this PRJ entry. |
746 | | **********************************************************************/ |
747 | | const char *AVCE00GenPrj(AVCE00GenInfo *psInfo, char **papszPrj, GBool bCont) |
748 | 0 | { |
749 | 0 | if (bCont == FALSE) |
750 | 0 | { |
751 | | /*--------------------------------------------------------- |
752 | | * Initialize the psInfo structure with info about the |
753 | | * current PRJ. (numItems = Number of lines to output) |
754 | | *--------------------------------------------------------*/ |
755 | 0 | psInfo->iCurItem = 0; |
756 | 0 | psInfo->numItems = CSLCount(papszPrj) * 2; |
757 | 0 | } |
758 | |
|
759 | 0 | if (psInfo->iCurItem < psInfo->numItems) |
760 | 0 | { |
761 | | /*--------------------------------------------------------- |
762 | | * Return the next PRJ section line. Note that every |
763 | | * second line of the output is only a "~". |
764 | | *--------------------------------------------------------*/ |
765 | |
|
766 | 0 | if (psInfo->iCurItem % 2 == 0) |
767 | 0 | { |
768 | | /*----------------------------------------------------- |
769 | | * In theory we should split lines longer than 80 chars on |
770 | | * several lines, but I won't do it for now since I never |
771 | | * saw any projection line longer than 80 chars. |
772 | | *----------------------------------------------------*/ |
773 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%s", |
774 | 0 | papszPrj[psInfo->iCurItem / 2]); |
775 | 0 | } |
776 | 0 | else |
777 | 0 | { |
778 | | /*----------------------------------------------------- |
779 | | * Every second line in a PRJ section contains only a "~", |
780 | | * this is a way to tell that the previous line was complete. |
781 | | *----------------------------------------------------*/ |
782 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "~"); |
783 | 0 | } |
784 | |
|
785 | 0 | psInfo->iCurItem++; |
786 | 0 | } |
787 | 0 | else |
788 | 0 | { |
789 | | /* No more lines to generate for this PRJ. |
790 | | */ |
791 | 0 | return nullptr; |
792 | 0 | } |
793 | | |
794 | 0 | return psInfo->pszBuf; |
795 | 0 | } |
796 | | |
797 | | /*===================================================================== |
798 | | TXT stuff |
799 | | =====================================================================*/ |
800 | | |
801 | | /********************************************************************** |
802 | | * AVCE00GenTxt() |
803 | | * |
804 | | * Generate the next line of an E00 TXT (Annotation) entry. |
805 | | * |
806 | | * This function should be called once with bCont=FALSE to get the |
807 | | * first E00 line for the current TXT, and then call with bCont=TRUE |
808 | | * to get all the other lines for this TXT. |
809 | | * |
810 | | * The function returns nullptr when there are no more lines to generate |
811 | | * for this TXT entry. |
812 | | **********************************************************************/ |
813 | | const char *AVCE00GenTxt(AVCE00GenInfo *psInfo, AVCTxt *psTxt, GBool bCont) |
814 | 0 | { |
815 | 0 | int numFixedLines; |
816 | | |
817 | | /* numFixedLines is the number of lines to generate before the line(s) |
818 | | * with the text string |
819 | | */ |
820 | 0 | if (psInfo->nPrecision == AVC_SINGLE_PREC) |
821 | 0 | numFixedLines = 4; |
822 | 0 | else |
823 | 0 | numFixedLines = 6; |
824 | |
|
825 | 0 | if (bCont == FALSE) |
826 | 0 | { |
827 | | /*------------------------------------------------------------- |
828 | | * Initialize the psInfo structure with info about the |
829 | | * current TXT. (numItems = Number of lines excluding header) |
830 | | *------------------------------------------------------------*/ |
831 | 0 | psInfo->iCurItem = 0; |
832 | 0 | psInfo->numItems = numFixedLines + ((psTxt->numChars - 1) / 80 + 1); |
833 | | |
834 | | /* And return the TXT header line. |
835 | | */ |
836 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d%10d%10d%10d", |
837 | 0 | psTxt->nLevel, psTxt->numVerticesLine - 1, |
838 | 0 | psTxt->numVerticesArrow, psTxt->nSymbol, psTxt->numChars); |
839 | 0 | } |
840 | 0 | else if (psInfo->iCurItem < psInfo->numItems && |
841 | 0 | psInfo->iCurItem < numFixedLines - 1) |
842 | 0 | { |
843 | | /*------------------------------------------------------------- |
844 | | * Return next line of coordinates... start by placing the coord. |
845 | | * values in the order that they should appear, and then generate the |
846 | | * current line |
847 | | * (This is a little bit less efficient, but will give much easier |
848 | | * code to read ;-) |
849 | | *------------------------------------------------------------*/ |
850 | 0 | double dXY[15] = {0.0}; |
851 | 0 | int i, nFirstValue, numValuesPerLine; |
852 | |
|
853 | 0 | dXY[14] = psTxt->dHeight; |
854 | | |
855 | | /* note that the first vertex in the vertices list is never exported |
856 | | */ |
857 | 0 | for (i = 0; i < 4 && i < (psTxt->numVerticesLine - 1); i++) |
858 | 0 | { |
859 | 0 | dXY[i] = psTxt->pasVertices[i + 1].x; |
860 | 0 | dXY[i + 4] = psTxt->pasVertices[i + 1].y; |
861 | 0 | } |
862 | 0 | for (i = 0; i < 3 && i < std::abs(psTxt->numVerticesArrow); i++) |
863 | 0 | { |
864 | 0 | dXY[i + 8] = psTxt->pasVertices[i + psTxt->numVerticesLine].x; |
865 | 0 | dXY[i + 11] = psTxt->pasVertices[i + psTxt->numVerticesLine].y; |
866 | 0 | } |
867 | | |
868 | | /* OK, now that we prepared the coord. values, return the next line |
869 | | * of coordinates. The only difference between double and single |
870 | | * precision is the number of coordinates per line. |
871 | | */ |
872 | 0 | if (psInfo->nPrecision != AVC_DOUBLE_PREC) |
873 | 0 | { |
874 | | /* Single precision |
875 | | */ |
876 | 0 | numValuesPerLine = 5; |
877 | 0 | } |
878 | 0 | else |
879 | 0 | { |
880 | | /* Double precision |
881 | | */ |
882 | 0 | numValuesPerLine = 3; |
883 | 0 | } |
884 | |
|
885 | 0 | nFirstValue = psInfo->iCurItem * numValuesPerLine; |
886 | 0 | psInfo->pszBuf[0] = '\0'; |
887 | 0 | for (i = 0; i < numValuesPerLine; i++) |
888 | 0 | { |
889 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
890 | 0 | psInfo->nPrecision, AVCFileTXT, |
891 | 0 | dXY[nFirstValue + i]); |
892 | 0 | } |
893 | |
|
894 | 0 | psInfo->iCurItem++; |
895 | 0 | } |
896 | 0 | else if (psInfo->iCurItem < psInfo->numItems && |
897 | 0 | psInfo->iCurItem == numFixedLines - 1) |
898 | 0 | { |
899 | | /*------------------------------------------------------------- |
900 | | * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!! |
901 | | *------------------------------------------------------------*/ |
902 | 0 | psInfo->pszBuf[0] = '\0'; |
903 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, AVC_SINGLE_PREC, |
904 | 0 | AVCFileTXT, psTxt->f_1e2); |
905 | 0 | psInfo->iCurItem++; |
906 | 0 | } |
907 | 0 | else if (psInfo->iCurItem < psInfo->numItems && |
908 | 0 | psInfo->iCurItem >= numFixedLines) |
909 | 0 | { |
910 | | /*------------------------------------------------------------- |
911 | | * Last line, contains the text string |
912 | | * Strings longer than 80 chars have to be in 80 chars chunks |
913 | | *------------------------------------------------------------*/ |
914 | 0 | int numLines, iLine; |
915 | 0 | numLines = (psTxt->numChars - 1) / 80 + 1; |
916 | 0 | iLine = numLines - (psInfo->numItems - psInfo->iCurItem); |
917 | |
|
918 | 0 | if ((int)strlen((char *)psTxt->pszText) > (iLine * 80)) |
919 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%-.80s", |
920 | 0 | psTxt->pszText + (iLine * 80)); |
921 | 0 | else |
922 | 0 | psInfo->pszBuf[0] = '\0'; |
923 | |
|
924 | 0 | psInfo->iCurItem++; |
925 | 0 | } |
926 | 0 | else |
927 | 0 | { |
928 | | /* No more lines to generate for this TXT. |
929 | | */ |
930 | 0 | return nullptr; |
931 | 0 | } |
932 | | |
933 | 0 | return psInfo->pszBuf; |
934 | 0 | } |
935 | | |
936 | | /*===================================================================== |
937 | | TX6 stuff |
938 | | =====================================================================*/ |
939 | | |
940 | | /********************************************************************** |
941 | | * AVCE00GenTx6() |
942 | | * |
943 | | * Generate the next line of an E00 TX6 (Annotation) entry. |
944 | | * |
945 | | * This function should be called once with bCont=FALSE to get the |
946 | | * first E00 line for the current TX6, and then call with bCont=TRUE |
947 | | * to get all the other lines for this TX6. |
948 | | * |
949 | | * Note that E00 files can also contain TX7 sections, they seem identical |
950 | | * to TX6 sections, except for one value in each entry, and it was |
951 | | * impossible to find where this value comes from... so we will always |
952 | | * generate TX6 sections and not bother with TX7. |
953 | | * |
954 | | * The function returns nullptr when there are no more lines to generate |
955 | | * for this TX6 entry. |
956 | | **********************************************************************/ |
957 | | const char *AVCE00GenTx6(AVCE00GenInfo *psInfo, AVCTxt *psTxt, GBool bCont) |
958 | 0 | { |
959 | 0 | if (bCont == FALSE) |
960 | 0 | { |
961 | | /*------------------------------------------------------------- |
962 | | * Initialize the psInfo structure with info about the |
963 | | * current TX6. (numItems = Number of lines excluding header) |
964 | | *------------------------------------------------------------*/ |
965 | 0 | psInfo->iCurItem = 0; |
966 | 0 | psInfo->numItems = 8 + psTxt->numVerticesLine + |
967 | 0 | std::abs(psTxt->numVerticesArrow) + |
968 | 0 | ((psTxt->numChars - 1) / 80 + 1); |
969 | | |
970 | | /* And return the TX6 header line. |
971 | | */ |
972 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
973 | 0 | "%10d%10d%10d%10d%10d%10d%10d", psTxt->nUserId, psTxt->nLevel, |
974 | 0 | psTxt->numVerticesLine, psTxt->numVerticesArrow, |
975 | 0 | psTxt->nSymbol, psTxt->n28, psTxt->numChars); |
976 | 0 | } |
977 | 0 | else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem < 6) |
978 | 0 | { |
979 | | /*------------------------------------------------------------- |
980 | | * Text Justification stuff... 2 sets of 20 int16 values. |
981 | | *------------------------------------------------------------*/ |
982 | 0 | GInt16 *pValue; |
983 | |
|
984 | 0 | if (psInfo->iCurItem == 0 || psInfo->iCurItem == 1) |
985 | 0 | { |
986 | 0 | pValue = psTxt->anJust2 + psInfo->iCurItem * 7; |
987 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
988 | 0 | "%10d%10d%10d%10d%10d%10d%10d", pValue[0], pValue[1], |
989 | 0 | pValue[2], pValue[3], pValue[4], pValue[5], pValue[6]); |
990 | 0 | } |
991 | 0 | else if (psInfo->iCurItem == 2) |
992 | 0 | { |
993 | 0 | pValue = psTxt->anJust2 + psInfo->iCurItem * 7; |
994 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
995 | 0 | "%10d%10d%10d%10d%10d%10d", pValue[0], pValue[1], |
996 | 0 | pValue[2], pValue[3], pValue[4], pValue[5]); |
997 | 0 | } |
998 | 0 | else if (psInfo->iCurItem == 3) |
999 | 0 | { |
1000 | 0 | pValue = psTxt->anJust1 + (psInfo->iCurItem - 3) * 7; |
1001 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
1002 | 0 | "%10d%10d%10d%10d%10d%10d%10d", pValue[0], pValue[1], |
1003 | 0 | pValue[2], pValue[3], pValue[4], pValue[5], pValue[6]); |
1004 | 0 | } |
1005 | 0 | else if (psInfo->iCurItem == 4) |
1006 | 0 | { |
1007 | 0 | pValue = psTxt->anJust1 + (psInfo->iCurItem - 3) * 7; |
1008 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
1009 | 0 | "%10d%10d%10d%10d%10d%10d%10d", pValue[0], pValue[1], |
1010 | 0 | pValue[2], pValue[3], pValue[4], pValue[5], pValue[6]); |
1011 | 0 | } |
1012 | 0 | else |
1013 | 0 | { |
1014 | 0 | assert(psInfo->iCurItem == 5); |
1015 | 0 | pValue = psTxt->anJust1 + (psInfo->iCurItem - 3) * 7; |
1016 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
1017 | 0 | "%10d%10d%10d%10d%10d%10d", pValue[0], pValue[1], |
1018 | 0 | pValue[2], pValue[3], pValue[4], pValue[5]); |
1019 | 0 | } |
1020 | | |
1021 | 0 | psInfo->iCurItem++; |
1022 | 0 | } |
1023 | 0 | else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == 6) |
1024 | 0 | { |
1025 | | /*------------------------------------------------------------- |
1026 | | * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!! |
1027 | | *------------------------------------------------------------*/ |
1028 | 0 | psInfo->pszBuf[0] = '\0'; |
1029 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, AVC_SINGLE_PREC, |
1030 | 0 | AVCFileTX6, psTxt->f_1e2); |
1031 | 0 | psInfo->iCurItem++; |
1032 | 0 | } |
1033 | 0 | else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == 7) |
1034 | 0 | { |
1035 | | /*------------------------------------------------------------- |
1036 | | * Line with 3 values, 1st value is probably text height. |
1037 | | *------------------------------------------------------------*/ |
1038 | 0 | psInfo->pszBuf[0] = '\0'; |
1039 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
1040 | 0 | AVCFileTX6, psTxt->dHeight); |
1041 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
1042 | 0 | AVCFileTX6, psTxt->dV2); |
1043 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
1044 | 0 | AVCFileTX6, psTxt->dV3); |
1045 | 0 | psInfo->iCurItem++; |
1046 | 0 | } |
1047 | 0 | else if (psInfo->iCurItem < |
1048 | 0 | psInfo->numItems - ((psTxt->numChars - 1) / 80 + 1)) |
1049 | 0 | { |
1050 | | /*------------------------------------------------------------- |
1051 | | * One line for each pair of X,Y coordinates |
1052 | | *------------------------------------------------------------*/ |
1053 | 0 | psInfo->pszBuf[0] = '\0'; |
1054 | |
|
1055 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
1056 | 0 | AVCFileTX6, |
1057 | 0 | psTxt->pasVertices[psInfo->iCurItem - 8].x); |
1058 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
1059 | 0 | AVCFileTX6, |
1060 | 0 | psTxt->pasVertices[psInfo->iCurItem - 8].y); |
1061 | |
|
1062 | 0 | psInfo->iCurItem++; |
1063 | 0 | } |
1064 | 0 | else if (psInfo->iCurItem < psInfo->numItems /* && |
1065 | 0 | psInfo->iCurItem >= psInfo->numItems-((psTxt->numChars-1)/80 + 1) */ ) |
1066 | 0 | { |
1067 | | /*------------------------------------------------------------- |
1068 | | * Last line, contains the text string |
1069 | | * Strings longer than 80 chars have to be in 80 chars chunks |
1070 | | *------------------------------------------------------------*/ |
1071 | 0 | int numLines, iLine; |
1072 | 0 | numLines = (psTxt->numChars - 1) / 80 + 1; |
1073 | 0 | iLine = numLines - (psInfo->numItems - psInfo->iCurItem); |
1074 | |
|
1075 | 0 | if ((int)strlen((char *)psTxt->pszText) > (iLine * 80)) |
1076 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%-.80s", |
1077 | 0 | psTxt->pszText + (iLine * 80)); |
1078 | 0 | else |
1079 | 0 | psInfo->pszBuf[0] = '\0'; |
1080 | |
|
1081 | 0 | psInfo->iCurItem++; |
1082 | 0 | } |
1083 | 0 | else |
1084 | 0 | { |
1085 | | /* No more lines to generate for this TX6. |
1086 | | */ |
1087 | 0 | return nullptr; |
1088 | 0 | } |
1089 | | |
1090 | 0 | return psInfo->pszBuf; |
1091 | 0 | } |
1092 | | |
1093 | | /*===================================================================== |
1094 | | RXP stuff |
1095 | | =====================================================================*/ |
1096 | | |
1097 | | /********************************************************************** |
1098 | | * AVCE00GenRxp() |
1099 | | * |
1100 | | * Generate the next line of an E00 RXP entry (RXPs are related to regions). |
1101 | | * |
1102 | | * This function should be called once with bCont=FALSE to get the |
1103 | | * first E00 line for the current RXP, and then call with bCont=TRUE |
1104 | | * to get all the other lines for this RXP. |
1105 | | * |
1106 | | * The function returns nullptr when there are no more lines to generate |
1107 | | * for this RXP entry. |
1108 | | **********************************************************************/ |
1109 | | const char *AVCE00GenRxp(AVCE00GenInfo *psInfo, AVCRxp *psRxp, GBool bCont) |
1110 | 0 | { |
1111 | 0 | if (bCont == TRUE) |
1112 | 0 | { |
1113 | | /*--------------------------------------------------------- |
1114 | | * RXP entries are only 1 line, we support the bCont flag |
1115 | | * only for compatibility with the other AVCE00Gen*() functions. |
1116 | | *--------------------------------------------------------*/ |
1117 | 0 | return nullptr; |
1118 | 0 | } |
1119 | | |
1120 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d", psRxp->n1, |
1121 | 0 | psRxp->n2); |
1122 | |
|
1123 | 0 | return psInfo->pszBuf; |
1124 | 0 | } |
1125 | | |
1126 | | /*===================================================================== |
1127 | | TABLE stuff |
1128 | | =====================================================================*/ |
1129 | | |
1130 | | /********************************************************************** |
1131 | | * AVCE00GenTableHdr() |
1132 | | * |
1133 | | * Generate the next line of an E00 Table header. |
1134 | | * |
1135 | | * This function should be called once with bCont=FALSE to get the |
1136 | | * first E00 line for the current table header, and then call with |
1137 | | * bCont=TRUE to get all the other lines. |
1138 | | * |
1139 | | * The function returns nullptr when there are no more lines to generate. |
1140 | | **********************************************************************/ |
1141 | | const char *AVCE00GenTableHdr(AVCE00GenInfo *psInfo, AVCTableDef *psDef, |
1142 | | GBool bCont) |
1143 | 0 | { |
1144 | 0 | if (bCont == FALSE) |
1145 | 0 | { |
1146 | 0 | int nRecSize; |
1147 | | /* Initialize the psInfo structure with info about the |
1148 | | * current Table Header |
1149 | | */ |
1150 | 0 | psInfo->iCurItem = 0; |
1151 | 0 | psInfo->numItems = psDef->numFields; |
1152 | |
|
1153 | 0 | nRecSize = psDef->nRecSize; |
1154 | | #ifdef AVC_MAP_TYPE40_TO_DOUBLE |
1155 | | { |
1156 | | /* Adjust Table record size if we're remapping type 40 fields */ |
1157 | | int i; |
1158 | | for (i = 0; i < psDef->numFields; i++) |
1159 | | { |
1160 | | if (psDef->pasFieldDef[i].nType1 * 10 == AVC_FT_FIXNUM && |
1161 | | psDef->pasFieldDef[i].nSize > 8) |
1162 | | { |
1163 | | nRecSize -= psDef->pasFieldDef[i].nSize; |
1164 | | nRecSize += 8; |
1165 | | } |
1166 | | } |
1167 | | nRecSize = ((nRecSize + 1) / 2) * 2; |
1168 | | } |
1169 | | #endif |
1170 | | |
1171 | | /* And return the header's header line(!). |
1172 | | */ |
1173 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%-32.32s%s%4d%4d%4d%10d", |
1174 | 0 | psDef->szTableName, psDef->szExternal, psDef->numFields, |
1175 | 0 | psDef->numFields, nRecSize, psDef->numRecords); |
1176 | 0 | } |
1177 | 0 | else if (psInfo->iCurItem < psInfo->numItems) |
1178 | 0 | { |
1179 | 0 | int nSize, nType, nOffset; |
1180 | |
|
1181 | 0 | nSize = psDef->pasFieldDef[psInfo->iCurItem].nSize; |
1182 | 0 | nType = psDef->pasFieldDef[psInfo->iCurItem].nType1 * 10; |
1183 | 0 | nOffset = psDef->pasFieldDef[psInfo->iCurItem].nOffset; |
1184 | |
|
1185 | | #ifdef AVC_MAP_TYPE40_TO_DOUBLE |
1186 | | /* Type 40 fields with more than 12 digits written to E00 by Arc/Info |
1187 | | * will lose some digits of precision (and we starts losing them at 8 |
1188 | | * with the way AVC lib writes type 40). This (optional) hack will |
1189 | | * remap type 40 fields with more than 8 digits to double precision |
1190 | | * floats which can carry up to 18 digits of precision. (bug 599) |
1191 | | */ |
1192 | | if (nType == AVC_FT_FIXNUM && nSize > 8) |
1193 | | { |
1194 | | /* Remap to double-precision float */ |
1195 | | nType = AVC_FT_BINFLOAT; |
1196 | | nSize = 8; |
1197 | | } |
1198 | | |
1199 | | /* Adjust field offset if this field is preceded by any type40 fields |
1200 | | * that were remapped. |
1201 | | */ |
1202 | | { |
1203 | | int i; |
1204 | | for (i = 0; i < psInfo->iCurItem; i++) |
1205 | | { |
1206 | | if (psDef->pasFieldDef[i].nType1 * 10 == AVC_FT_FIXNUM && |
1207 | | psDef->pasFieldDef[i].nSize > 8) |
1208 | | { |
1209 | | nOffset -= psDef->pasFieldDef[i].nSize; |
1210 | | nOffset += 8; |
1211 | | } |
1212 | | } |
1213 | | } |
1214 | | #endif |
1215 | | /* Return next Field definition line |
1216 | | */ |
1217 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
1218 | 0 | "%-16.16s%3d%2d%4d%1d%2d%4d%2d%3d%2d%4d%4d%2d%-16.16s%4d-", |
1219 | 0 | psDef->pasFieldDef[psInfo->iCurItem].szName, nSize, |
1220 | 0 | psDef->pasFieldDef[psInfo->iCurItem].v2, nOffset, |
1221 | 0 | psDef->pasFieldDef[psInfo->iCurItem].v4, |
1222 | 0 | psDef->pasFieldDef[psInfo->iCurItem].v5, |
1223 | 0 | psDef->pasFieldDef[psInfo->iCurItem].nFmtWidth, |
1224 | 0 | psDef->pasFieldDef[psInfo->iCurItem].nFmtPrec, nType, |
1225 | 0 | psDef->pasFieldDef[psInfo->iCurItem].v10, |
1226 | 0 | psDef->pasFieldDef[psInfo->iCurItem].v11, |
1227 | 0 | psDef->pasFieldDef[psInfo->iCurItem].v12, |
1228 | 0 | psDef->pasFieldDef[psInfo->iCurItem].v13, |
1229 | 0 | psDef->pasFieldDef[psInfo->iCurItem].szAltName, |
1230 | 0 | psDef->pasFieldDef[psInfo->iCurItem].nIndex); |
1231 | |
|
1232 | 0 | psInfo->iCurItem++; |
1233 | 0 | } |
1234 | 0 | else |
1235 | 0 | { |
1236 | | /* No more lines to generate. |
1237 | | */ |
1238 | 0 | return nullptr; |
1239 | 0 | } |
1240 | | |
1241 | 0 | return psInfo->pszBuf; |
1242 | 0 | } |
1243 | | |
1244 | | /********************************************************************** |
1245 | | * AVCE00GenTableRec() |
1246 | | * |
1247 | | * Generate the next line of an E00 Table Data Record. |
1248 | | * |
1249 | | * This function should be called once with bCont=FALSE to get the |
1250 | | * first E00 line for the current table record, and then call with |
1251 | | * bCont=TRUE to get all the other lines. |
1252 | | * |
1253 | | * The function returns nullptr when there are no more lines to generate. |
1254 | | **********************************************************************/ |
1255 | | const char *AVCE00GenTableRec(AVCE00GenInfo *psInfo, int numFields, |
1256 | | AVCFieldInfo *pasDef, AVCField *pasFields, |
1257 | | GBool bCont) |
1258 | 0 | { |
1259 | 0 | int i, nSize, nType, nLen; |
1260 | 0 | char *pszBuf2; |
1261 | |
|
1262 | 0 | if (bCont == FALSE) |
1263 | 0 | { |
1264 | | /*------------------------------------------------------------- |
1265 | | * Initialize the psInfo structure to be ready to process this |
1266 | | * new Table Record |
1267 | | *------------------------------------------------------------*/ |
1268 | 0 | psInfo->iCurItem = 0; |
1269 | | #ifdef AVC_MAP_TYPE40_TO_DOUBLE |
1270 | | psInfo->numItems = _AVCE00ComputeRecSize(numFields, pasDef, TRUE); |
1271 | | #else |
1272 | 0 | psInfo->numItems = _AVCE00ComputeRecSize(numFields, pasDef, FALSE); |
1273 | 0 | #endif |
1274 | | |
1275 | | /*------------------------------------------------------------- |
1276 | | * First, we need to make sure that the output buffer is big |
1277 | | * enough to hold the whole record, plus 81 chars to hold |
1278 | | * the line that we'll return to the caller. |
1279 | | *------------------------------------------------------------*/ |
1280 | 0 | nSize = psInfo->numItems + 1 + 81; |
1281 | |
|
1282 | 0 | if (psInfo->nBufSize < nSize) |
1283 | 0 | { |
1284 | 0 | psInfo->pszBuf = |
1285 | 0 | (char *)CPLRealloc(psInfo->pszBuf, nSize * sizeof(char)); |
1286 | 0 | psInfo->nBufSize = nSize; |
1287 | 0 | } |
1288 | | |
1289 | | /*------------------------------------------------------------- |
1290 | | * Generate the whole record now, and we'll return it to the |
1291 | | * caller by chunks of 80 chars. |
1292 | | * The first 80 chars of the buffer will be used to return |
1293 | | * one line at a time, and the rest of the buffer is used to |
1294 | | * hold the whole record. |
1295 | | *------------------------------------------------------------*/ |
1296 | 0 | pszBuf2 = psInfo->pszBuf + 81; |
1297 | |
|
1298 | 0 | for (i = 0; i < numFields; i++) |
1299 | 0 | { |
1300 | 0 | nType = pasDef[i].nType1 * 10; |
1301 | 0 | nSize = pasDef[i].nSize; |
1302 | |
|
1303 | 0 | if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR || |
1304 | 0 | nType == AVC_FT_FIXINT) |
1305 | 0 | { |
1306 | 0 | memcpy(pszBuf2, pasFields[i].pszStr, nSize * sizeof(char)); |
1307 | 0 | pszBuf2 += nSize; |
1308 | 0 | } |
1309 | | #ifdef AVC_MAP_TYPE40_TO_DOUBLE |
1310 | | /* See explanation in AVCE00GenTableHdr() about this hack to remap |
1311 | | * type 40 fields to double precision floats. |
1312 | | */ |
1313 | | else if (nType == AVC_FT_FIXNUM && nSize > 8) |
1314 | | { |
1315 | | pszBuf2[0] = '\0'; |
1316 | | /* NOTE: The E00 representation for a binary float is |
1317 | | * defined by its binary size, not by the coverage's |
1318 | | * precision. |
1319 | | */ |
1320 | | nLen = AVCPrintRealValue( |
1321 | | pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf), |
1322 | | AVC_DOUBLE_PREC, AVCFileTABLE, |
1323 | | CPLAtof((char *)pasFields[i].pszStr)); |
1324 | | pszBuf2 += nLen; |
1325 | | } |
1326 | | #endif |
1327 | 0 | else if (nType == AVC_FT_FIXNUM) |
1328 | 0 | { |
1329 | | /* TYPE 40 attributes are stored with 1 byte per digit |
1330 | | * in binary format, and as single precision floats in |
1331 | | * E00 tables, even in double precision coverages. |
1332 | | */ |
1333 | 0 | pszBuf2[0] = '\0'; |
1334 | 0 | nLen = AVCPrintRealValue( |
1335 | 0 | pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf), |
1336 | 0 | AVC_SINGLE_PREC, AVCFileTABLE, |
1337 | 0 | CPLAtof((char *)pasFields[i].pszStr)); |
1338 | 0 | pszBuf2 += nLen; |
1339 | 0 | } |
1340 | 0 | else if (nType == AVC_FT_BININT && nSize == 4) |
1341 | 0 | { |
1342 | 0 | snprintf(pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf), |
1343 | 0 | "%11d", pasFields[i].nInt32); |
1344 | 0 | pszBuf2 += 11; |
1345 | 0 | } |
1346 | 0 | else if (nType == AVC_FT_BININT && nSize == 2) |
1347 | 0 | { |
1348 | 0 | snprintf(pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf), |
1349 | 0 | "%6d", pasFields[i].nInt16); |
1350 | 0 | pszBuf2 += 6; |
1351 | 0 | } |
1352 | 0 | else if (nType == AVC_FT_BINFLOAT && nSize == 4) |
1353 | 0 | { |
1354 | 0 | pszBuf2[0] = '\0'; |
1355 | | /* NOTE: The E00 representation for a binary float is |
1356 | | * defined by its binary size, not by the coverage's |
1357 | | * precision. |
1358 | | */ |
1359 | 0 | nLen = AVCPrintRealValue( |
1360 | 0 | pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf), |
1361 | 0 | AVC_SINGLE_PREC, AVCFileTABLE, pasFields[i].fFloat); |
1362 | 0 | pszBuf2 += nLen; |
1363 | 0 | } |
1364 | 0 | else if (nType == AVC_FT_BINFLOAT && nSize == 8) |
1365 | 0 | { |
1366 | 0 | pszBuf2[0] = '\0'; |
1367 | | /* NOTE: The E00 representation for a binary float is |
1368 | | * defined by its binary size, not by the coverage's |
1369 | | * precision. |
1370 | | */ |
1371 | 0 | nLen = AVCPrintRealValue( |
1372 | 0 | pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf), |
1373 | 0 | AVC_DOUBLE_PREC, AVCFileTABLE, pasFields[i].dDouble); |
1374 | 0 | pszBuf2 += nLen; |
1375 | 0 | } |
1376 | 0 | else |
1377 | 0 | { |
1378 | | /*----------------------------------------------------- |
1379 | | * Hummm... unsupported field type... |
1380 | | *----------------------------------------------------*/ |
1381 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
1382 | 0 | "Unsupported field type: (type=%d, size=%d)", nType, |
1383 | 0 | nSize); |
1384 | 0 | return nullptr; |
1385 | 0 | } |
1386 | 0 | } |
1387 | | |
1388 | 0 | *pszBuf2 = '\0'; |
1389 | | |
1390 | | /* Make sure that we remove any embedded NUL characters from the |
1391 | | * data line before returning it, otherwise we may be accidentally |
1392 | | * truncating results. |
1393 | | */ |
1394 | 0 | while (--pszBuf2 >= psInfo->pszBuf + 81) |
1395 | 0 | { |
1396 | 0 | if (*pszBuf2 == '\0') |
1397 | 0 | { |
1398 | 0 | *pszBuf2 = ' '; |
1399 | 0 | } |
1400 | 0 | } |
1401 | 0 | } |
1402 | | |
1403 | 0 | if (psInfo->iCurItem < psInfo->numItems) |
1404 | 0 | { |
1405 | | /*------------------------------------------------------------- |
1406 | | * Return the next 80 chars chunk. |
1407 | | * The first 80 chars of the buffer is used to return |
1408 | | * one line at a time, and the rest of the buffer (chars 81+) |
1409 | | * is used to hold the whole record. |
1410 | | *------------------------------------------------------------*/ |
1411 | 0 | nLen = psInfo->numItems - psInfo->iCurItem; |
1412 | |
|
1413 | 0 | if (nLen > 80) |
1414 | 0 | nLen = 80; |
1415 | |
|
1416 | 0 | strncpy(psInfo->pszBuf, psInfo->pszBuf + (81 + psInfo->iCurItem), nLen); |
1417 | 0 | psInfo->pszBuf[nLen] = '\0'; |
1418 | |
|
1419 | 0 | psInfo->iCurItem += nLen; |
1420 | | |
1421 | | /*------------------------------------------------------------- |
1422 | | * Arc/Info removes spaces at the end of the lines... let's |
1423 | | * remove them as well since it can reduce the E00 file size. |
1424 | | *------------------------------------------------------------*/ |
1425 | 0 | nLen--; |
1426 | 0 | while (nLen >= 0 && psInfo->pszBuf[nLen] == ' ') |
1427 | 0 | { |
1428 | 0 | psInfo->pszBuf[nLen] = '\0'; |
1429 | 0 | nLen--; |
1430 | 0 | } |
1431 | 0 | } |
1432 | 0 | else |
1433 | 0 | { |
1434 | | /* No more lines to generate. |
1435 | | */ |
1436 | 0 | return nullptr; |
1437 | 0 | } |
1438 | | |
1439 | 0 | return psInfo->pszBuf; |
1440 | 0 | } |