1 : /**********************************************************************
2 : * $Id: mitab_mapheaderblock.cpp,v 1.33 2008-02-01 19:36:31 dmorissette Exp $
3 : *
4 : * Name: mitab_mapheaderblock.cpp
5 : * Project: MapInfo TAB Read/Write library
6 : * Language: C++
7 : * Purpose: Implementation of the TABHeaderBlock class used to handle
8 : * reading/writing of the .MAP files' header block
9 : * Author: Daniel Morissette, dmorissette@dmsolutions.ca
10 : *
11 : **********************************************************************
12 : * Copyright (c) 1999-2002, Daniel Morissette
13 : *
14 : * Permission is hereby granted, free of charge, to any person obtaining a
15 : * copy of this software and associated documentation files (the "Software"),
16 : * to deal in the Software without restriction, including without limitation
17 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 : * and/or sell copies of the Software, and to permit persons to whom the
19 : * Software is furnished to do so, subject to the following conditions:
20 : *
21 : * The above copyright notice and this permission notice shall be included
22 : * in all copies or substantial portions of the Software.
23 : *
24 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 : * DEALINGS IN THE SOFTWARE.
31 : **********************************************************************
32 : *
33 : * $Log: mitab_mapheaderblock.cpp,v $
34 : * Revision 1.33 2008-02-01 19:36:31 dmorissette
35 : * Initial support for V800 REGION and MULTIPLINE (bug 1496)
36 : *
37 : * Revision 1.32 2006/11/28 18:49:08 dmorissette
38 : * Completed changes to split TABMAPObjectBlocks properly and produce an
39 : * optimal spatial index (bug 1585)
40 : *
41 : * Revision 1.31 2005/09/29 20:16:54 dmorissette
42 : * Support for writing affine projection params in .MAP header (AJD, bug 1155)
43 : *
44 : * Revision 1.30 2005/05/12 20:46:15 dmorissette
45 : * Initialize m_sProj.nDatumId in InitNewBlock(). (hss/geh)
46 : *
47 : * Revision 1.29 2005/03/22 23:24:54 dmorissette
48 : * Added support for datum id in .MAP header (bug 910)
49 : *
50 : * Revision 1.28 2004/12/15 22:52:49 dmorissette
51 : * Revert back to using doubles for range check in CoordSys2Int(). Hopefully
52 : * I got it right this time. (bug 894)
53 : *
54 : * Revision 1.27 2004/12/08 23:27:35 dmorissette
55 : * Fixed coordinates rounding error in Coordsys2Int() (bug 894)
56 : *
57 : * Revision 1.26 2004/06/30 20:29:04 dmorissette
58 : * Fixed refs to old address danmo@videotron.ca
59 : *
60 : * Revision 1.25 2003/08/12 23:17:21 dmorissette
61 : * Added reading of v500+ coordsys affine params (Anthony D. - Encom)
62 : *
63 : * Revision 1.24 2002/06/28 18:32:37 julien
64 : * Add SetSpatialFilter() in TABSeamless class (Bug 164, MapServer)
65 : * Use double for comparison in Coordsys2Int() in mitab_mapheaderblock.cpp
66 : *
67 : * Revision 1.23 2002/04/25 16:05:24 julien
68 : * Disabled the overflow warning in SetCoordFilter() by adding bIgnoreOverflow
69 : * variable in Coordsys2Int of the TABMAPFile class and TABMAPHeaderBlock class
70 : *
71 : * Revision 1.22 2002/03/26 01:48:40 daniel
72 : * Added Multipoint object type (V650)
73 : *
74 : * Revision 1.21 2001/12/05 22:23:06 daniel
75 : * Can't use rint() on Windows... replace rint() with (int)(val+0.5)
76 : *
77 : * Revision 1.20 2001/12/05 21:56:15 daniel
78 : * Mod. CoordSys2Int() to use rint() for double to integer coord. conversion.
79 : *
80 : * Revision 1.19 2001/11/19 15:05:42 daniel
81 : * Prevent writing of coordinates outside of the +/-1e9 integer bounds.
82 : *
83 : * Revision 1.18 2000/12/07 03:58:20 daniel
84 : * Pass first arg of pow() as double
85 : *
86 : * Revision 1.17 2000/09/19 19:35:53 daniel
87 : * Set default scale/displacement when reading V100 headers
88 : *
89 : * Revision 1.16 2000/07/10 14:56:52 daniel
90 : * Handle m_nOriginQuadrant==0 as quadrant 3 (reverse x and y axis)
91 : *
92 : * Revision 1.15 2000/03/13 05:59:25 daniel
93 : * Switch from V400 to V500 .MAP header (1024 bytes)
94 : *
95 : * Revision 1.14 2000/02/28 17:01:05 daniel
96 : * Use a #define for header version number
97 : *
98 : * Revision 1.13 2000/02/07 18:09:10 daniel
99 : * OOpppps ... test on version number was reversed!
100 : *
101 : * Revision 1.12 2000/02/07 17:41:02 daniel
102 : * Ignore the values of 5 last datum params in version=200 headers
103 : *
104 : * Revision 1.11 2000/01/15 22:30:44 daniel
105 : * Switch to MIT/X-Consortium OpenSource license
106 : *
107 : * Revision 1.10 2000/01/15 05:37:47 daniel
108 : * Use a #define for default quadrant value in new files
109 : *
110 : * Revision 1.9 1999/10/19 16:27:10 warmerda
111 : * Default unitsid to 7 (meters) instead of 0 (miles).
112 : *
113 : * Revision 1.8 1999/10/19 06:05:35 daniel
114 : * Removed obsolete code segments in the coord. conversion functions.
115 : *
116 : * Revision 1.7 1999/10/06 13:21:37 daniel
117 : * Reworked int<->coordsys coords. conversion... hopefully it's OK this time!
118 : *
119 : * Revision 1.6 1999/10/01 03:47:38 daniel
120 : * Better defaults for header fields, and more complete Dump() for debugging
121 : *
122 : * Revision 1.5 1999/09/29 04:25:03 daniel
123 : * Set default scale so that default coord range is +/-1000000.000
124 : *
125 : * Revision 1.4 1999/09/26 14:59:36 daniel
126 : * Implemented write support
127 : *
128 : * Revision 1.3 1999/09/21 03:36:33 warmerda
129 : * slight modification to dump precision
130 : *
131 : * Revision 1.2 1999/09/16 02:39:16 daniel
132 : * Completed read support for most feature types
133 : *
134 : * Revision 1.1 1999/07/12 04:18:24 daniel
135 : * Initial checkin
136 : *
137 : **********************************************************************/
138 :
139 : #include "mitab.h"
140 :
141 : /*---------------------------------------------------------------------
142 : * Set various constants used in generating the header block.
143 : *--------------------------------------------------------------------*/
144 : #define HDR_MAGIC_COOKIE 42424242
145 : #define HDR_VERSION_NUMBER 500
146 : #define HDR_DATA_BLOCK_SIZE 512
147 :
148 : #define HDR_DEF_ORG_QUADRANT 1 // N-E Quadrant
149 : #define HDR_DEF_REFLECTXAXIS 0
150 :
151 : /*---------------------------------------------------------------------
152 : * The header block starts with an array of map object lenght constants.
153 : *--------------------------------------------------------------------*/
154 : #define HDR_OBJ_LEN_ARRAY_SIZE 73
155 : static GByte gabyObjLenArray[ HDR_OBJ_LEN_ARRAY_SIZE ] = {
156 : 0x00,0x0a,0x0e,0x15,0x0e,0x16,0x1b,0xa2,
157 : 0xa6,0xab,0x1a,0x2a,0x2f,0xa5,0xa9,0xb5,
158 : 0xa7,0xb5,0xd9,0x0f,0x17,0x23,0x13,0x1f,
159 : 0x2b,0x0f,0x17,0x23,0x4f,0x57,0x63,0x9c,
160 : 0xa4,0xa9,0xa0,0xa8,0xad,0xa4,0xa8,0xad,
161 : 0x16,0x1a,0x39,0x0d,0x11,0x37,0xa5,0xa9,
162 : 0xb5,0xa4,0xa8,0xad,0xb2,0xb6,0xdc,0xbd,
163 : 0xbd,0xf4,0x2b,0x2f,0x55,0xc8,0xcc,0xd8,
164 : 0xc7,0xcb,0xd0,0xd3,0xd7,0xfd,0xc2,0xc2,
165 : 0xf9};
166 :
167 :
168 :
169 : /*=====================================================================
170 : * class TABMAPHeaderBlock
171 : *====================================================================*/
172 :
173 :
174 : /**********************************************************************
175 : * TABMAPHeaderBlock::TABMAPHeaderBlock()
176 : *
177 : * Constructor.
178 : **********************************************************************/
179 18 : TABMAPHeaderBlock::TABMAPHeaderBlock(TABAccess eAccessMode /*= TABRead*/):
180 18 : TABRawBinBlock(eAccessMode, TRUE)
181 : {
182 : int i;
183 :
184 : /*-----------------------------------------------------------------
185 : * Set acceptable default values for member vars.
186 : *----------------------------------------------------------------*/
187 18 : m_nMAPVersionNumber = HDR_VERSION_NUMBER;
188 18 : m_nBlockSize = HDR_DATA_BLOCK_SIZE;
189 :
190 18 : m_dCoordsys2DistUnits = 1.0;
191 18 : m_nXMin = -1000000000;
192 18 : m_nYMin = -1000000000;
193 18 : m_nXMax = 1000000000;
194 18 : m_nYMax = 1000000000;
195 18 : m_bIntBoundsOverflow = FALSE;
196 :
197 18 : m_nFirstIndexBlock = 0;
198 18 : m_nFirstGarbageBlock = 0;
199 18 : m_nFirstToolBlock = 0;
200 :
201 18 : m_numPointObjects = 0;
202 18 : m_numLineObjects = 0;
203 18 : m_numRegionObjects = 0;
204 18 : m_numTextObjects = 0;
205 18 : m_nMaxCoordBufSize = 0;
206 :
207 18 : m_nDistUnitsCode = 7; // Meters
208 18 : m_nMaxSpIndexDepth = 0;
209 18 : m_nCoordPrecision = 3; // ??? 3 Digits of precision
210 18 : m_nCoordOriginQuadrant = HDR_DEF_ORG_QUADRANT; // ???
211 18 : m_nReflectXAxisCoord = HDR_DEF_REFLECTXAXIS;
212 18 : m_nMaxObjLenArrayId = HDR_OBJ_LEN_ARRAY_SIZE-1; // See gabyObjLenArray[]
213 18 : m_numPenDefs = 0;
214 18 : m_numBrushDefs = 0;
215 18 : m_numSymbolDefs = 0;
216 18 : m_numFontDefs = 0;
217 18 : m_numMapToolBlocks = 0;
218 :
219 18 : m_sProj.nProjId = 0;
220 18 : m_sProj.nEllipsoidId = 0;
221 18 : m_sProj.nUnitsId = 7;
222 18 : m_XScale = 1000.0; // Default coord range (before SetCoordSysBounds())
223 18 : m_YScale = 1000.0; // will be [-1000000.000 .. 1000000.000]
224 18 : m_XDispl = 0.0;
225 18 : m_YDispl = 0.0;
226 :
227 126 : for(i=0; i<6; i++)
228 108 : m_sProj.adProjParams[i] = 0.0;
229 :
230 18 : m_sProj.dDatumShiftX = 0.0;
231 18 : m_sProj.dDatumShiftY = 0.0;
232 18 : m_sProj.dDatumShiftZ = 0.0;
233 108 : for(i=0; i<5; i++)
234 90 : m_sProj.adDatumParams[i] = 0.0;
235 :
236 18 : m_sProj.nAffineFlag = 0; // Only in version 500 and up
237 18 : m_sProj.nAffineUnits = 7;
238 18 : m_sProj.dAffineParamA = 0.0;
239 18 : m_sProj.dAffineParamB = 0.0;
240 18 : m_sProj.dAffineParamC = 0.0;
241 18 : m_sProj.dAffineParamD = 0.0;
242 18 : m_sProj.dAffineParamE = 0.0;
243 18 : m_sProj.dAffineParamF = 0.0;
244 18 : }
245 :
246 : /**********************************************************************
247 : * TABMAPHeaderBlock::~TABMAPHeaderBlock()
248 : *
249 : * Destructor.
250 : **********************************************************************/
251 18 : TABMAPHeaderBlock::~TABMAPHeaderBlock()
252 : {
253 :
254 18 : }
255 :
256 :
257 : /**********************************************************************
258 : * TABMAPHeaderBlock::InitBlockFromData()
259 : *
260 : * Perform some initialization on the block after its binary data has
261 : * been set or changed (or loaded from a file).
262 : *
263 : * Returns 0 if succesful or -1 if an error happened, in which case
264 : * CPLError() will have been called.
265 : **********************************************************************/
266 12 : int TABMAPHeaderBlock::InitBlockFromData(GByte *pabyBuf,
267 : int nBlockSize, int nSizeUsed,
268 : GBool bMakeCopy /* = TRUE */,
269 : FILE *fpSrc /* = NULL */,
270 : int nOffset /* = 0 */)
271 : {
272 : int i, nStatus;
273 : GInt32 nMagicCookie;
274 :
275 : /*-----------------------------------------------------------------
276 : * First of all, we must call the base class' InitBlockFromData()
277 : *----------------------------------------------------------------*/
278 : nStatus = TABRawBinBlock::InitBlockFromData(pabyBuf,
279 : nBlockSize, nSizeUsed,
280 : bMakeCopy,
281 12 : fpSrc, nOffset);
282 12 : if (nStatus != 0)
283 0 : return nStatus;
284 :
285 : /*-----------------------------------------------------------------
286 : * Validate block type
287 : * Header blocks have a magic cookie at byte 0x100
288 : *----------------------------------------------------------------*/
289 12 : GotoByteInBlock(0x100);
290 12 : nMagicCookie = ReadInt32();
291 12 : if (nMagicCookie != HDR_MAGIC_COOKIE)
292 : {
293 : CPLError(CE_Failure, CPLE_FileIO,
294 : "ReadFromFile(): Invalid Magic Cookie: got %d expected %d",
295 0 : nMagicCookie, HDR_MAGIC_COOKIE);
296 0 : CPLFree(m_pabyBuf);
297 0 : m_pabyBuf = NULL;
298 0 : return -1;
299 : }
300 :
301 : /*-----------------------------------------------------------------
302 : * Init member variables
303 : * Instead of having over 30 get/set methods, we'll make all data
304 : * members public and we will initialize them here.
305 : * For this reason, this class should be used with care.
306 : *----------------------------------------------------------------*/
307 12 : GotoByteInBlock(0x104);
308 12 : m_nMAPVersionNumber = ReadInt16();
309 12 : m_nBlockSize = ReadInt16();
310 :
311 12 : m_dCoordsys2DistUnits = ReadDouble();
312 12 : m_nXMin = ReadInt32();
313 12 : m_nYMin = ReadInt32();
314 12 : m_nXMax = ReadInt32();
315 12 : m_nYMax = ReadInt32();
316 :
317 12 : GotoByteInBlock(0x130); // Skip 16 unknown bytes
318 :
319 12 : m_nFirstIndexBlock = ReadInt32();
320 12 : m_nFirstGarbageBlock = ReadInt32();
321 12 : m_nFirstToolBlock = ReadInt32();
322 :
323 12 : m_numPointObjects = ReadInt32();
324 12 : m_numLineObjects = ReadInt32();
325 12 : m_numRegionObjects = ReadInt32();
326 12 : m_numTextObjects = ReadInt32();
327 12 : m_nMaxCoordBufSize = ReadInt32();
328 :
329 12 : GotoByteInBlock(0x15e); // Skip 14 unknown bytes
330 :
331 12 : m_nDistUnitsCode = ReadByte();
332 12 : m_nMaxSpIndexDepth = ReadByte();
333 12 : m_nCoordPrecision = ReadByte();
334 12 : m_nCoordOriginQuadrant = ReadByte();
335 12 : m_nReflectXAxisCoord = ReadByte();
336 12 : m_nMaxObjLenArrayId = ReadByte(); // See gabyObjLenArray[]
337 12 : m_numPenDefs = ReadByte();
338 12 : m_numBrushDefs = ReadByte();
339 12 : m_numSymbolDefs = ReadByte();
340 12 : m_numFontDefs = ReadByte();
341 12 : m_numMapToolBlocks = ReadInt16();
342 :
343 : /* DatumId was never set (always 0) until MapInfo 7.8. See bug 910
344 : * MAP Version Number is 500 in this case.
345 : */
346 12 : if (m_nMAPVersionNumber >= 500)
347 12 : m_sProj.nDatumId = ReadInt16();
348 : else
349 : {
350 0 : ReadInt16(); // Skip.
351 0 : m_sProj.nDatumId = 0;
352 : }
353 12 : ReadByte(); // Skip unknown byte
354 12 : m_sProj.nProjId = ReadByte();
355 12 : m_sProj.nEllipsoidId = ReadByte();
356 12 : m_sProj.nUnitsId = ReadByte();
357 12 : m_XScale = ReadDouble();
358 12 : m_YScale = ReadDouble();
359 12 : m_XDispl = ReadDouble();
360 12 : m_YDispl = ReadDouble();
361 :
362 : /* In V.100 files, the scale and displacement do not appear to be set.
363 : * we'll use m_nCoordPrecision to define the scale factor instead.
364 : */
365 12 : if (m_nMAPVersionNumber <= 100)
366 : {
367 0 : m_XScale = m_YScale = pow(10.0, m_nCoordPrecision);
368 0 : m_XDispl = m_YDispl = 0.0;
369 : }
370 :
371 84 : for(i=0; i<6; i++)
372 72 : m_sProj.adProjParams[i] = ReadDouble();
373 :
374 12 : m_sProj.dDatumShiftX = ReadDouble();
375 12 : m_sProj.dDatumShiftY = ReadDouble();
376 12 : m_sProj.dDatumShiftZ = ReadDouble();
377 72 : for(i=0; i<5; i++)
378 : {
379 : /* In V.200 files, the next 5 datum params are unused and they
380 : * sometimes contain junk bytes... in this case we set adDatumParams[]
381 : * to 0 for the rest of the lib to be happy.
382 : */
383 60 : m_sProj.adDatumParams[i] = ReadDouble();
384 60 : if (m_nMAPVersionNumber <= 200)
385 0 : m_sProj.adDatumParams[i] = 0.0;
386 : }
387 :
388 12 : m_sProj.nAffineFlag = 0;
389 12 : if (m_nMAPVersionNumber >= 500 && m_nSizeUsed > 512)
390 : {
391 : // Read Affine parameters A,B,C,D,E,F
392 : // only if version 500+ and block is larger than 512 bytes
393 6 : int nInUse = ReadByte();
394 6 : if (nInUse)
395 : {
396 0 : m_sProj.nAffineFlag = 1;
397 0 : m_sProj.nAffineUnits = ReadByte();
398 0 : GotoByteInBlock(0x0208); // Skip unused bytes
399 0 : m_sProj.dAffineParamA = ReadDouble();
400 0 : m_sProj.dAffineParamB = ReadDouble();
401 0 : m_sProj.dAffineParamC = ReadDouble();
402 0 : m_sProj.dAffineParamD = ReadDouble();
403 0 : m_sProj.dAffineParamE = ReadDouble();
404 0 : m_sProj.dAffineParamF = ReadDouble();
405 : }
406 : }
407 :
408 12 : return 0;
409 : }
410 :
411 :
412 : /**********************************************************************
413 : * TABMAPHeaderBlock::Int2Coordsys()
414 : *
415 : * Convert from long integer (internal) to coordinates system units
416 : * as defined in the file's coordsys clause.
417 : *
418 : * Note that the false easting/northing and the conversion factor from
419 : * datum to coordsys units are not included in the calculation.
420 : *
421 : * Returns 0 on success, -1 on error.
422 : **********************************************************************/
423 2834 : int TABMAPHeaderBlock::Int2Coordsys(GInt32 nX, GInt32 nY,
424 : double &dX, double &dY)
425 : {
426 2834 : if (m_pabyBuf == NULL)
427 0 : return -1;
428 :
429 : // For some obscure reason, some guy decided that it would be
430 : // more fun to be able to define our own origin quadrant!
431 : //
432 : // In version 100 .tab files (version 400 .map), it is possible to have
433 : // a quadrant 0 and it should be treated the same way as quadrant 3
434 :
435 2834 : if (m_nCoordOriginQuadrant==2 || m_nCoordOriginQuadrant==3 ||
436 : m_nCoordOriginQuadrant==0 )
437 0 : dX = -1.0 * (nX + m_XDispl) / m_XScale;
438 : else
439 2834 : dX = (nX - m_XDispl) / m_XScale;
440 :
441 2834 : if (m_nCoordOriginQuadrant==3 || m_nCoordOriginQuadrant==4||
442 : m_nCoordOriginQuadrant==0)
443 0 : dY = -1.0 * (nY + m_YDispl) / m_YScale;
444 : else
445 2834 : dY = (nY - m_YDispl) / m_YScale;
446 :
447 : //printf("Int2Coordsys: (%d, %d) -> (%.10g, %.10g)\n", nX, nY, dX, dY);
448 :
449 2834 : return 0;
450 : }
451 :
452 : /**********************************************************************
453 : * TABMAPHeaderBlock::Coordsys2Int()
454 : *
455 : * Convert from coordinates system units as defined in the file's
456 : * coordsys clause to long integer (internal) coordinates.
457 : *
458 : * Note that the false easting/northing and the conversion factor from
459 : * datum to coordsys units are not included in the calculation.
460 : *
461 : * Returns 0 on success, -1 on error.
462 : **********************************************************************/
463 622 : int TABMAPHeaderBlock::Coordsys2Int(double dX, double dY,
464 : GInt32 &nX, GInt32 &nY,
465 : GBool bIgnoreOverflow /*=FALSE*/)
466 : {
467 622 : if (m_pabyBuf == NULL)
468 0 : return -1;
469 :
470 : // For some obscure reason, some guy decided that it would be
471 : // more fun to be able to define our own origin quadrant!
472 : //
473 : // In version 100 .tab files (version 400 .map), it is possible to have
474 : // a quadrant 0 and it should be treated the same way as quadrant 3
475 :
476 : /*-----------------------------------------------------------------
477 : * NOTE: double values must be used here, the limit of integer value
478 : * have been reached some times due to the very big numbers used here.
479 : *----------------------------------------------------------------*/
480 : double dTempX, dTempY;
481 :
482 622 : if (m_nCoordOriginQuadrant==2 || m_nCoordOriginQuadrant==3 ||
483 : m_nCoordOriginQuadrant==0 )
484 0 : dTempX = (double)(-1.0*dX*m_XScale - m_XDispl);
485 : else
486 622 : dTempX = (double)(dX*m_XScale + m_XDispl);
487 :
488 622 : if (m_nCoordOriginQuadrant==3 || m_nCoordOriginQuadrant==4 ||
489 : m_nCoordOriginQuadrant==0 )
490 0 : dTempY = (double)(-1.0*dY*m_YScale - m_YDispl);
491 : else
492 622 : dTempY = (double)(dY*m_YScale + m_YDispl);
493 :
494 : /*-----------------------------------------------------------------
495 : * Make sure we'll never output coordinates outside of the valid
496 : * integer coordinates range: (-1e9, -1e9) - (1e9, 1e9)
497 : * Integer coordinates outside of that range will confuse MapInfo.
498 : *----------------------------------------------------------------*/
499 622 : GBool bIntBoundsOverflow = FALSE;
500 622 : if (dTempX < -1000000000)
501 : {
502 0 : dTempX = -1000000000;
503 0 : bIntBoundsOverflow = TRUE;
504 : }
505 622 : if (dTempX > 1000000000)
506 : {
507 0 : dTempX = 1000000000;
508 0 : bIntBoundsOverflow = TRUE;
509 : }
510 622 : if (dTempY < -1000000000)
511 : {
512 0 : dTempY = -1000000000;
513 0 : bIntBoundsOverflow = TRUE;
514 : }
515 622 : if (dTempY > 1000000000)
516 : {
517 0 : dTempY = 1000000000;
518 0 : bIntBoundsOverflow = TRUE;
519 : }
520 :
521 622 : nX = (GInt32) ROUND_INT(dTempX);
522 622 : nY = (GInt32) ROUND_INT(dTempY);
523 :
524 622 : if (bIntBoundsOverflow && !bIgnoreOverflow)
525 : {
526 0 : m_bIntBoundsOverflow = TRUE;
527 : #ifdef DEBUG
528 : CPLError(CE_Warning, TAB_WarningBoundsOverflow,
529 : "Integer bounds overflow: (%f, %f) -> (%d, %d)\n",
530 0 : dX, dY, nX, nY);
531 : #endif
532 : }
533 :
534 622 : return 0;
535 : }
536 :
537 : /**********************************************************************
538 : * TABMAPHeaderBlock::ComprInt2Coordsys()
539 : *
540 : * Convert from compressed integer (internal) to coordinates system units
541 : * as defined in the file's coordsys clause.
542 : * The difference between long integer and compressed integer coords is
543 : * that compressed coordinates are scaled displacement relative to an
544 : * object centroid.
545 : *
546 : * Note that the false easting/northing and the conversion factor from
547 : * datum to coordsys units are not included in the calculation.
548 : *
549 : * Returns 0 on success, -1 on error.
550 : **********************************************************************/
551 0 : int TABMAPHeaderBlock::ComprInt2Coordsys(GInt32 nCenterX, GInt32 nCenterY,
552 : int nDeltaX, int nDeltaY,
553 : double &dX, double &dY)
554 : {
555 0 : if (m_pabyBuf == NULL)
556 0 : return -1;
557 :
558 0 : return Int2Coordsys(nCenterX+nDeltaX, nCenterY+nDeltaY, dX, dY);
559 : }
560 :
561 :
562 : /**********************************************************************
563 : * TABMAPHeaderBlock::Int2CoordsysDist()
564 : *
565 : * Convert a pair of X and Y size (or distance) value from long integer
566 : * (internal) to coordinates system units as defined in the file's
567 : * coordsys clause.
568 : *
569 : * The difference with Int2Coordsys() is that this function only applies
570 : * the scaling factor: it does not apply the displacement.
571 : *
572 : * Since the calculations on the X and Y values are independent, either
573 : * one can be omitted (i.e. passed as 0)
574 : *
575 : * Returns 0 on success, -1 on error.
576 : **********************************************************************/
577 0 : int TABMAPHeaderBlock::Int2CoordsysDist(GInt32 nX, GInt32 nY,
578 : double &dX, double &dY)
579 : {
580 0 : if (m_pabyBuf == NULL)
581 0 : return -1;
582 :
583 0 : dX = nX / m_XScale;
584 0 : dY = nY / m_YScale;
585 :
586 0 : return 0;
587 : }
588 :
589 : /**********************************************************************
590 : * TABMAPHeaderBlock::Coordsys2IntDist()
591 : *
592 : * Convert a pair of X and Y size (or distance) values from coordinates
593 : * system units as defined in the file's coordsys clause to long integer
594 : * (internal) coordinates.
595 : *
596 : * The difference with Coordsys2Int() is that this function only applies
597 : * the scaling factor: it does not apply the displacement.
598 : *
599 : * Since the calculations on the X and Y values are independent, either
600 : * one can be omitted (i.e. passed as 0)
601 : *
602 : * Returns 0 on success, -1 on error.
603 : **********************************************************************/
604 0 : int TABMAPHeaderBlock::Coordsys2IntDist(double dX, double dY,
605 : GInt32 &nX, GInt32 &nY)
606 : {
607 0 : if (m_pabyBuf == NULL)
608 0 : return -1;
609 :
610 0 : nX = (GInt32)(dX*m_XScale);
611 0 : nY = (GInt32)(dY*m_YScale);
612 :
613 0 : return 0;
614 : }
615 :
616 :
617 : /**********************************************************************
618 : * TABMAPHeaderBlock::SetCoordsysBounds()
619 : *
620 : * Take projection coordinates bounds of the newly created dataset and
621 : * compute new values for the X/Y Scales and X/Y displacement.
622 : *
623 : * This function must be called after creating a new dataset and before any
624 : * of the coordinates conversion functions can be used.
625 : *
626 : * Returns 0 on success, -1 on error.
627 : **********************************************************************/
628 6 : int TABMAPHeaderBlock::SetCoordsysBounds(double dXMin, double dYMin,
629 : double dXMax, double dYMax)
630 : {
631 : //printf("SetCoordsysBounds(%10g, %10g, %10g, %10g)\n", dXMin, dYMin, dXMax, dYMax);
632 : /*-----------------------------------------------------------------
633 : * Check for 0-width or 0-height bounds
634 : *----------------------------------------------------------------*/
635 6 : if (dXMax == dXMin)
636 : {
637 0 : dXMin -= 1.0;
638 0 : dXMax += 1.0;
639 : }
640 :
641 6 : if (dYMax == dYMin)
642 : {
643 0 : dYMin -= 1.0;
644 0 : dYMax += 1.0;
645 : }
646 :
647 : /*-----------------------------------------------------------------
648 : * X and Y scales are used to map coordsys coordinates to integer
649 : * internal coordinates. We want to find the scale and displacement
650 : * values that will result in an integer coordinate range of
651 : * (-1e9, -1e9) - (1e9, 1e9)
652 : *
653 : * Note that we ALWAYS generate datasets with the OriginQuadrant = 1
654 : * so that we avoid reverted X/Y axis complications, etc.
655 : *----------------------------------------------------------------*/
656 6 : m_XScale = 2e9 / (dXMax - dXMin);
657 6 : m_YScale = 2e9 / (dYMax - dYMin);
658 :
659 6 : m_XDispl = -1.0 * m_XScale * (dXMax + dXMin) / 2;
660 6 : m_YDispl = -1.0 * m_YScale * (dYMax + dYMin) / 2;
661 :
662 6 : m_nXMin = -1000000000;
663 6 : m_nYMin = -1000000000;
664 6 : m_nXMax = 1000000000;
665 6 : m_nYMax = 1000000000;
666 :
667 6 : return 0;
668 : }
669 :
670 : /**********************************************************************
671 : * TABMAPHeaderBlock::GetMapObjectSize()
672 : *
673 : * Return the size of the object body for the specified object type.
674 : * The value is looked up in the first 256 bytes of the header.
675 : **********************************************************************/
676 44 : int TABMAPHeaderBlock::GetMapObjectSize(int nObjType)
677 : {
678 44 : if (m_pabyBuf == NULL)
679 : {
680 : CPLError(CE_Failure, CPLE_AssertionFailed,
681 0 : "Block has not been initialized yet!");
682 0 : return -1;
683 : }
684 :
685 44 : if (nObjType < 0 || nObjType > 255)
686 : {
687 : CPLError(CE_Failure, CPLE_IllegalArg,
688 0 : "Invalid object type %d", nObjType);
689 0 : return -1;
690 : }
691 :
692 : // Byte 0x80 is set for objects that have coordinates inside type 3 blocks
693 44 : return (m_pabyBuf[nObjType] & 0x7f);
694 : }
695 :
696 : /**********************************************************************
697 : * TABMAPHeaderBlock::MapObjectUsesCoordBlock()
698 : *
699 : * Return TRUE if the specified map object type has coordinates stored
700 : * inside type 3 coordinate blocks.
701 : * The info is looked up in the first 256 bytes of the header.
702 : **********************************************************************/
703 24 : GBool TABMAPHeaderBlock::MapObjectUsesCoordBlock(int nObjType)
704 : {
705 24 : if (m_pabyBuf == NULL)
706 : {
707 : CPLError(CE_Failure, CPLE_AssertionFailed,
708 0 : "Block has not been initialized yet!");
709 0 : return FALSE;
710 : }
711 :
712 24 : if (nObjType < 0 || nObjType > 255)
713 : {
714 : CPLError(CE_Failure, CPLE_IllegalArg,
715 0 : "Invalid object type %d", nObjType);
716 0 : return FALSE;
717 : }
718 :
719 : // Byte 0x80 is set for objects that have coordinates inside type 3 blocks
720 :
721 24 : return ((m_pabyBuf[nObjType] & 0x80) != 0) ? TRUE: FALSE;
722 : }
723 :
724 :
725 : /**********************************************************************
726 : * TABMAPHeaderBlock::GetProjInfo()
727 : *
728 : * Fill the psProjInfo structure with the projection parameters previously
729 : * read from this header block.
730 : *
731 : * Returns 0 on success, -1 on error.
732 : **********************************************************************/
733 2 : int TABMAPHeaderBlock::GetProjInfo(TABProjInfo *psProjInfo)
734 : {
735 2 : if (m_pabyBuf == NULL)
736 : {
737 : CPLError(CE_Failure, CPLE_AssertionFailed,
738 0 : "Block has not been initialized yet!");
739 0 : return -1;
740 : }
741 :
742 2 : if (psProjInfo)
743 2 : *psProjInfo = m_sProj;
744 :
745 2 : return 0;
746 : }
747 :
748 : /**********************************************************************
749 : * TABMAPHeaderBlock::SetProjInfo()
750 : *
751 : * Set the projection parameters for this dataset.
752 : *
753 : * Returns 0 on success, -1 on error.
754 : **********************************************************************/
755 2 : int TABMAPHeaderBlock::SetProjInfo(TABProjInfo *psProjInfo)
756 : {
757 2 : if (m_pabyBuf == NULL)
758 : {
759 : CPLError(CE_Failure, CPLE_AssertionFailed,
760 0 : "Block has not been initialized yet!");
761 0 : return -1;
762 : }
763 :
764 2 : if (psProjInfo)
765 2 : m_sProj = *psProjInfo;
766 :
767 2 : return 0;
768 : }
769 :
770 :
771 : /**********************************************************************
772 : * TABMAPHeaderBlock::CommitToFile()
773 : *
774 : * Commit the current state of the binary block to the file to which
775 : * it has been previously attached.
776 : *
777 : * This method makes sure all values are properly set in the header
778 : * block buffer and then calls TABRawBinBlock::CommitToFile() to do
779 : * the actual writing to disk.
780 : *
781 : * Returns 0 if succesful or -1 if an error happened, in which case
782 : * CPLError() will have been called.
783 : **********************************************************************/
784 6 : int TABMAPHeaderBlock::CommitToFile()
785 : {
786 6 : int i, nStatus = 0;
787 :
788 6 : if ( m_pabyBuf == NULL || m_nBlockSize != HDR_DATA_BLOCK_SIZE )
789 : {
790 : CPLError(CE_Failure, CPLE_AssertionFailed,
791 0 : "TABRawBinBlock::CommitToFile(): Block has not been initialized yet!");
792 0 : return -1;
793 : }
794 :
795 : /*-----------------------------------------------------------------
796 : * Reconstruct header to make sure it is in sync with members variables.
797 : *----------------------------------------------------------------*/
798 6 : GotoByteInBlock(0x000);
799 6 : WriteBytes(HDR_OBJ_LEN_ARRAY_SIZE, gabyObjLenArray);
800 6 : m_nMaxObjLenArrayId = HDR_OBJ_LEN_ARRAY_SIZE-1;
801 :
802 6 : GotoByteInBlock(0x100);
803 6 : WriteInt32(HDR_MAGIC_COOKIE);
804 :
805 6 : if (m_sProj.nAffineFlag && m_nMAPVersionNumber<500)
806 : {
807 : // Must be at least version 500 to support affine params
808 : // Default value for HDR_VERSION_NUMBER is 500 so this error should
809 : // never happen unless the caller changed the value, in which case they
810 : // deserve to get a failure
811 : CPLError(CE_Failure, CPLE_AssertionFailed,
812 : "TABRawBinBlock::CommitToFile(): .MAP version 500 or more is "
813 0 : "required for affine projection parameter support.");
814 0 : return -1;
815 : }
816 :
817 6 : WriteInt16(m_nMAPVersionNumber);
818 :
819 6 : WriteInt16(HDR_DATA_BLOCK_SIZE);
820 :
821 6 : WriteDouble(m_dCoordsys2DistUnits);
822 6 : WriteInt32(m_nXMin);
823 6 : WriteInt32(m_nYMin);
824 6 : WriteInt32(m_nXMax);
825 6 : WriteInt32(m_nYMax);
826 :
827 6 : WriteZeros(16); // ???
828 :
829 6 : WriteInt32(m_nFirstIndexBlock);
830 6 : WriteInt32(m_nFirstGarbageBlock);
831 6 : WriteInt32(m_nFirstToolBlock);
832 :
833 6 : WriteInt32(m_numPointObjects);
834 6 : WriteInt32(m_numLineObjects);
835 6 : WriteInt32(m_numRegionObjects);
836 6 : WriteInt32(m_numTextObjects);
837 6 : WriteInt32(m_nMaxCoordBufSize);
838 :
839 6 : WriteZeros(14); // ???
840 :
841 6 : WriteByte(m_nDistUnitsCode);
842 6 : WriteByte(m_nMaxSpIndexDepth);
843 6 : WriteByte(m_nCoordPrecision);
844 6 : WriteByte(m_nCoordOriginQuadrant);
845 6 : WriteByte(m_nReflectXAxisCoord);
846 6 : WriteByte(m_nMaxObjLenArrayId); // See gabyObjLenArray[]
847 6 : WriteByte(m_numPenDefs);
848 6 : WriteByte(m_numBrushDefs);
849 6 : WriteByte(m_numSymbolDefs);
850 6 : WriteByte(m_numFontDefs);
851 6 : WriteInt16(m_numMapToolBlocks);
852 :
853 6 : WriteInt16(m_sProj.nDatumId);
854 6 : WriteZeros(1); // ???
855 :
856 6 : WriteByte(m_sProj.nProjId);
857 6 : WriteByte(m_sProj.nEllipsoidId);
858 6 : WriteByte(m_sProj.nUnitsId);
859 6 : WriteDouble(m_XScale);
860 6 : WriteDouble(m_YScale);
861 6 : WriteDouble(m_XDispl);
862 6 : WriteDouble(m_YDispl);
863 :
864 42 : for(i=0; i<6; i++)
865 36 : WriteDouble(m_sProj.adProjParams[i]);
866 :
867 6 : WriteDouble(m_sProj.dDatumShiftX);
868 6 : WriteDouble(m_sProj.dDatumShiftY);
869 6 : WriteDouble(m_sProj.dDatumShiftZ);
870 36 : for(i=0; i<5; i++)
871 30 : WriteDouble(m_sProj.adDatumParams[i]);
872 :
873 6 : if (m_sProj.nAffineFlag)
874 : {
875 0 : WriteByte(1); // In Use Flag
876 0 : WriteByte(m_sProj.nAffineUnits);
877 0 : WriteZeros(6);
878 0 : WriteDouble(m_sProj.dAffineParamA);
879 0 : WriteDouble(m_sProj.dAffineParamB);
880 0 : WriteDouble(m_sProj.dAffineParamC);
881 0 : WriteDouble(m_sProj.dAffineParamD);
882 0 : WriteDouble(m_sProj.dAffineParamE);
883 0 : WriteDouble(m_sProj.dAffineParamF);
884 :
885 0 : WriteZeros(456); // Pad rest of block with zeros (Bounds info here ?)
886 : }
887 :
888 : /*-----------------------------------------------------------------
889 : * OK, call the base class to write the block to disk.
890 : *----------------------------------------------------------------*/
891 6 : if (nStatus == 0)
892 6 : nStatus = TABRawBinBlock::CommitToFile();
893 :
894 6 : return nStatus;
895 : }
896 :
897 : /**********************************************************************
898 : * TABMAPHeaderBlock::InitNewBlock()
899 : *
900 : * Initialize a newly created block so that it knows to which file it
901 : * is attached, its block size, etc . and then perform any specific
902 : * initialization for this block type, including writing a default
903 : * block header, etc. and leave the block ready to receive data.
904 : *
905 : * This is an alternative to calling ReadFromFile() or InitBlockFromData()
906 : * that puts the block in a stable state without loading any initial
907 : * data in it.
908 : *
909 : * Returns 0 if succesful or -1 if an error happened, in which case
910 : * CPLError() will have been called.
911 : **********************************************************************/
912 6 : int TABMAPHeaderBlock::InitNewBlock(FILE *fpSrc, int nBlockSize,
913 : int nFileOffset /* = 0*/)
914 : {
915 : int i;
916 : /*-----------------------------------------------------------------
917 : * Start with the default initialisation
918 : *----------------------------------------------------------------*/
919 6 : if ( TABRawBinBlock::InitNewBlock(fpSrc, nBlockSize, nFileOffset) != 0)
920 0 : return -1;
921 :
922 : /*-----------------------------------------------------------------
923 : * Set acceptable default values for member vars.
924 : *----------------------------------------------------------------*/
925 6 : m_nMAPVersionNumber = HDR_VERSION_NUMBER;
926 6 : m_nBlockSize = HDR_DATA_BLOCK_SIZE;
927 :
928 6 : m_dCoordsys2DistUnits = 1.0;
929 6 : m_nXMin = -1000000000;
930 6 : m_nYMin = -1000000000;
931 6 : m_nXMax = 1000000000;
932 6 : m_nYMax = 1000000000;
933 :
934 6 : m_nFirstIndexBlock = 0;
935 6 : m_nFirstGarbageBlock = 0;
936 6 : m_nFirstToolBlock = 0;
937 :
938 6 : m_numPointObjects = 0;
939 6 : m_numLineObjects = 0;
940 6 : m_numRegionObjects = 0;
941 6 : m_numTextObjects = 0;
942 6 : m_nMaxCoordBufSize = 0;
943 :
944 6 : m_nDistUnitsCode = 7; // Meters
945 6 : m_nMaxSpIndexDepth = 0;
946 6 : m_nCoordPrecision = 3; // ??? 3 digits of precision
947 6 : m_nCoordOriginQuadrant = HDR_DEF_ORG_QUADRANT; // ??? N-E quadrant
948 6 : m_nReflectXAxisCoord = HDR_DEF_REFLECTXAXIS;
949 6 : m_nMaxObjLenArrayId = HDR_OBJ_LEN_ARRAY_SIZE-1; // See gabyObjLenArray[]
950 6 : m_numPenDefs = 0;
951 6 : m_numBrushDefs = 0;
952 6 : m_numSymbolDefs = 0;
953 6 : m_numFontDefs = 0;
954 6 : m_numMapToolBlocks = 0;
955 :
956 6 : m_sProj.nProjId = 0;
957 6 : m_sProj.nEllipsoidId = 0;
958 6 : m_sProj.nUnitsId = 7;
959 6 : m_sProj.nDatumId = 0;
960 6 : m_XScale = 1000.0; // Default coord range (before SetCoordSysBounds())
961 6 : m_YScale = 1000.0; // will be [-1000000.000 .. 1000000.000]
962 6 : m_XDispl = 0.0;
963 6 : m_YDispl = 0.0;
964 :
965 42 : for(i=0; i<6; i++)
966 36 : m_sProj.adProjParams[i] = 0.0;
967 :
968 6 : m_sProj.dDatumShiftX = 0.0;
969 6 : m_sProj.dDatumShiftY = 0.0;
970 6 : m_sProj.dDatumShiftZ = 0.0;
971 36 : for(i=0; i<5; i++)
972 30 : m_sProj.adDatumParams[i] = 0.0;
973 :
974 6 : m_sProj.nAffineFlag = 0;
975 :
976 : /*-----------------------------------------------------------------
977 : * And Set the map object length array in the buffer...
978 : *----------------------------------------------------------------*/
979 6 : if (m_eAccess != TABRead)
980 : {
981 6 : GotoByteInBlock(0x000);
982 6 : WriteBytes(HDR_OBJ_LEN_ARRAY_SIZE, gabyObjLenArray);
983 : }
984 :
985 6 : if (CPLGetLastErrorNo() != 0)
986 0 : return -1;
987 :
988 6 : return 0;
989 : }
990 :
991 :
992 : /**********************************************************************
993 : * TABMAPHeaderBlock::Dump()
994 : *
995 : * Dump block contents... available only in DEBUG mode.
996 : **********************************************************************/
997 : #ifdef DEBUG
998 :
999 0 : void TABMAPHeaderBlock::Dump(FILE *fpOut /*=NULL*/)
1000 : {
1001 : int i;
1002 :
1003 0 : if (fpOut == NULL)
1004 0 : fpOut = stdout;
1005 :
1006 0 : fprintf(fpOut, "----- TABMAPHeaderBlock::Dump() -----\n");
1007 :
1008 0 : if (m_pabyBuf == NULL)
1009 : {
1010 0 : fprintf(fpOut, "Block has not been initialized yet.");
1011 : }
1012 : else
1013 : {
1014 0 : fprintf(fpOut,"Version %d header block.\n", m_nMAPVersionNumber);
1015 0 : fprintf(fpOut," m_nBlockSize = %d\n", m_nBlockSize);
1016 0 : fprintf(fpOut," m_nFirstIndexBlock = %d\n", m_nFirstIndexBlock);
1017 0 : fprintf(fpOut," m_nFirstGarbageBlock = %d\n", m_nFirstGarbageBlock);
1018 0 : fprintf(fpOut," m_nFirstToolBlock = %d\n", m_nFirstToolBlock);
1019 0 : fprintf(fpOut," m_numPointObjects = %d\n", m_numPointObjects);
1020 0 : fprintf(fpOut," m_numLineObjects = %d\n", m_numLineObjects);
1021 0 : fprintf(fpOut," m_numRegionObjects = %d\n", m_numRegionObjects);
1022 0 : fprintf(fpOut," m_numTextObjects = %d\n", m_numTextObjects);
1023 0 : fprintf(fpOut," m_nMaxCoordBufSize = %d\n", m_nMaxCoordBufSize);
1024 :
1025 0 : fprintf(fpOut,"\n");
1026 0 : fprintf(fpOut," m_dCoordsys2DistUnits = %g\n", m_dCoordsys2DistUnits);
1027 0 : fprintf(fpOut," m_nXMin = %d\n", m_nXMin);
1028 0 : fprintf(fpOut," m_nYMin = %d\n", m_nYMin);
1029 0 : fprintf(fpOut," m_nXMax = %d\n", m_nXMax);
1030 0 : fprintf(fpOut," m_nYMax = %d\n", m_nYMax);
1031 0 : fprintf(fpOut," m_XScale = %g\n", m_XScale);
1032 0 : fprintf(fpOut," m_YScale = %g\n", m_YScale);
1033 0 : fprintf(fpOut," m_XDispl = %g\n", m_XDispl);
1034 0 : fprintf(fpOut," m_YDispl = %g\n", m_YDispl);
1035 :
1036 0 : fprintf(fpOut,"\n");
1037 0 : fprintf(fpOut," m_nDistUnistCode = %d\n", m_nDistUnitsCode);
1038 0 : fprintf(fpOut," m_nMaxSpIndexDepth = %d\n", m_nMaxSpIndexDepth);
1039 0 : fprintf(fpOut," m_nCoordPrecision = %d\n", m_nCoordPrecision);
1040 0 : fprintf(fpOut," m_nCoordOriginQuadrant= %d\n",m_nCoordOriginQuadrant);
1041 0 : fprintf(fpOut," m_nReflecXAxisCoord = %d\n", m_nReflectXAxisCoord);
1042 0 : fprintf(fpOut," m_nMaxObjLenArrayId = %d\n", m_nMaxObjLenArrayId);
1043 0 : fprintf(fpOut," m_numPenDefs = %d\n", m_numPenDefs);
1044 0 : fprintf(fpOut," m_numBrushDefs = %d\n", m_numBrushDefs);
1045 0 : fprintf(fpOut," m_numSymbolDefs = %d\n", m_numSymbolDefs);
1046 0 : fprintf(fpOut," m_numFontDefs = %d\n", m_numFontDefs);
1047 0 : fprintf(fpOut," m_numMapToolBlocks = %d\n", m_numMapToolBlocks);
1048 :
1049 0 : fprintf(fpOut,"\n");
1050 0 : fprintf(fpOut," m_sProj.nDatumId = %d\n", m_sProj.nDatumId);
1051 0 : fprintf(fpOut," m_sProj.nProjId = %d\n", (int)m_sProj.nProjId);
1052 : fprintf(fpOut," m_sProj.nEllipsoidId = %d\n",
1053 0 : (int)m_sProj.nEllipsoidId);
1054 0 : fprintf(fpOut," m_sProj.nUnitsId = %d\n", (int)m_sProj.nUnitsId);
1055 0 : fprintf(fpOut," m_sProj.adProjParams =");
1056 0 : for(i=0; i<6; i++)
1057 0 : fprintf(fpOut, " %g", m_sProj.adProjParams[i]);
1058 0 : fprintf(fpOut,"\n");
1059 :
1060 0 : fprintf(fpOut," m_sProj.dDatumShiftX = %.15g\n", m_sProj.dDatumShiftX);
1061 0 : fprintf(fpOut," m_sProj.dDatumShiftY = %.15g\n", m_sProj.dDatumShiftY);
1062 0 : fprintf(fpOut," m_sProj.dDatumShiftZ = %.15g\n", m_sProj.dDatumShiftZ);
1063 0 : fprintf(fpOut," m_sProj.adDatumParams =");
1064 0 : for(i=0; i<5; i++)
1065 0 : fprintf(fpOut, " %.15g", m_sProj.adDatumParams[i]);
1066 0 : fprintf(fpOut,"\n");
1067 :
1068 : // Dump array of map object lengths... optional
1069 0 : if (FALSE)
1070 : {
1071 : fprintf(fpOut, "-- Header bytes 00-FF: Array of map object lenghts --\n");
1072 : for(i=0; i<256; i++)
1073 : {
1074 : fprintf(fpOut, "0x%2.2x", (int)m_pabyBuf[i]);
1075 : if (i != 255)
1076 : fprintf(fpOut, ",");
1077 : if ((i+1)%16 == 0)
1078 : fprintf(fpOut, "\n");
1079 : }
1080 : }
1081 :
1082 : }
1083 :
1084 0 : fflush(fpOut);
1085 0 : }
1086 :
1087 : #endif // DEBUG
|