1 : /******************************************************************************
2 : * $Id: dgnread.cpp 10645 2007-01-18 02:22:39Z warmerdam $
3 : *
4 : * Project: Microstation DGN Access Library
5 : * Purpose: DGN Access Library element reading code.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2000, Avenza Systems Inc, http://www.avenza.com/
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "dgnlibp.h"
31 :
32 : CPL_CVSID("$Id: dgnread.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
33 :
34 : static DGNElemCore *DGNParseTCB( DGNInfo * );
35 : static DGNElemCore *DGNParseColorTable( DGNInfo * );
36 : static DGNElemCore *DGNParseTagSet( DGNInfo * );
37 :
38 :
39 : /************************************************************************/
40 : /* DGNGotoElement() */
41 : /************************************************************************/
42 :
43 : /**
44 : * Seek to indicated element.
45 : *
46 : * Changes what element will be read on the next call to DGNReadElement().
47 : * Note that this function requires and index, and one will be built if
48 : * not already available.
49 : *
50 : * @param hDGN the file to affect.
51 : * @param element_id the element to seek to. These values are sequentially
52 : * ordered starting at zero for the first element.
53 : *
54 : * @return returns TRUE on success or FALSE on failure.
55 : */
56 :
57 17 : int DGNGotoElement( DGNHandle hDGN, int element_id )
58 :
59 : {
60 17 : DGNInfo *psDGN = (DGNInfo *) hDGN;
61 :
62 17 : DGNBuildIndex( psDGN );
63 :
64 17 : if( element_id < 0 || element_id >= psDGN->element_count )
65 0 : return FALSE;
66 :
67 17 : if( VSIFSeek( psDGN->fp, psDGN->element_index[element_id].offset,
68 : SEEK_SET ) != 0 )
69 0 : return FALSE;
70 :
71 17 : psDGN->next_element_id = element_id;
72 17 : psDGN->in_complex_group = FALSE;
73 :
74 17 : return TRUE;
75 : }
76 :
77 : /************************************************************************/
78 : /* DGNLoadRawElement() */
79 : /************************************************************************/
80 :
81 178 : int DGNLoadRawElement( DGNInfo *psDGN, int *pnType, int *pnLevel )
82 :
83 : {
84 : /* -------------------------------------------------------------------- */
85 : /* Read the first four bytes to get the level, type, and word */
86 : /* count. */
87 : /* -------------------------------------------------------------------- */
88 : int nType, nWords, nLevel;
89 :
90 178 : if( VSIFRead( psDGN->abyElem, 1, 4, psDGN->fp ) != 4 )
91 2 : return FALSE;
92 :
93 : /* Is this an 0xFFFF endof file marker? */
94 176 : if( psDGN->abyElem[0] == 0xff && psDGN->abyElem[1] == 0xff )
95 6 : return FALSE;
96 :
97 170 : nWords = psDGN->abyElem[2] + psDGN->abyElem[3]*256;
98 170 : nType = psDGN->abyElem[1] & 0x7f;
99 170 : nLevel = psDGN->abyElem[0] & 0x3f;
100 :
101 : /* -------------------------------------------------------------------- */
102 : /* Read the rest of the element data into the working buffer. */
103 : /* -------------------------------------------------------------------- */
104 : CPLAssert( nWords * 2 + 4 <= (int) sizeof(psDGN->abyElem) );
105 :
106 170 : if( (int) VSIFRead( psDGN->abyElem + 4, 2, nWords, psDGN->fp ) != nWords )
107 0 : return FALSE;
108 :
109 170 : psDGN->nElemBytes = nWords * 2 + 4;
110 :
111 170 : psDGN->next_element_id++;
112 :
113 : /* -------------------------------------------------------------------- */
114 : /* Return requested info. */
115 : /* -------------------------------------------------------------------- */
116 170 : if( pnType != NULL )
117 170 : *pnType = nType;
118 :
119 170 : if( pnLevel != NULL )
120 170 : *pnLevel = nLevel;
121 :
122 170 : return TRUE;
123 : }
124 :
125 :
126 : /************************************************************************/
127 : /* DGNGetRawExtents() */
128 : /* */
129 : /* Returns FALSE if the element type does not have reconisable */
130 : /* element extents, other TRUE and the extents will be updated. */
131 : /* */
132 : /* It is assumed the raw element data has been loaded into the */
133 : /* working area by DGNLoadRawElement(). */
134 : /************************************************************************/
135 :
136 : static int
137 63 : DGNGetRawExtents( DGNInfo *psDGN, int nType, unsigned char *pabyRawData,
138 : GUInt32 *pnXMin, GUInt32 *pnYMin, GUInt32 *pnZMin,
139 : GUInt32 *pnXMax, GUInt32 *pnYMax, GUInt32 *pnZMax )
140 :
141 : {
142 63 : if( pabyRawData == NULL )
143 61 : pabyRawData = psDGN->abyElem + 0;
144 :
145 63 : switch( nType )
146 : {
147 : case DGNT_LINE:
148 : case DGNT_LINE_STRING:
149 : case DGNT_SHAPE:
150 : case DGNT_CURVE:
151 : case DGNT_BSPLINE_POLE:
152 : case DGNT_BSPLINE_SURFACE_HEADER:
153 : case DGNT_BSPLINE_CURVE_HEADER:
154 : case DGNT_ELLIPSE:
155 : case DGNT_ARC:
156 : case DGNT_TEXT:
157 : case DGNT_TEXT_NODE:
158 : case DGNT_COMPLEX_CHAIN_HEADER:
159 : case DGNT_COMPLEX_SHAPE_HEADER:
160 : case DGNT_CONE:
161 : case DGNT_3DSURFACE_HEADER:
162 : case DGNT_3DSOLID_HEADER:
163 17 : *pnXMin = DGN_INT32( pabyRawData + 4 );
164 17 : *pnYMin = DGN_INT32( pabyRawData + 8 );
165 17 : if( pnZMin != NULL )
166 13 : *pnZMin = DGN_INT32( pabyRawData + 12 );
167 :
168 17 : *pnXMax = DGN_INT32( pabyRawData + 16 );
169 17 : *pnYMax = DGN_INT32( pabyRawData + 20 );
170 17 : if( pnZMax != NULL )
171 13 : *pnZMax = DGN_INT32( pabyRawData + 24 );
172 17 : return TRUE;
173 :
174 : default:
175 46 : return FALSE;
176 : }
177 : }
178 :
179 :
180 : /************************************************************************/
181 : /* DGNGetElementExtents() */
182 : /************************************************************************/
183 :
184 : /**
185 : * Fetch extents of an element.
186 : *
187 : * This function will return the extents of the passed element if possible.
188 : * The extents are extracted from the element header if it contains them,
189 : * and transformed into master georeferenced format. Some element types
190 : * do not have extents at all and will fail.
191 : *
192 : * This call will also fail if the extents raw data for the element is not
193 : * available. This will occur if it was not the most recently read element,
194 : * and if the raw_data field is not loaded.
195 : *
196 : * @param hDGN the handle of the file to read from.
197 : *
198 : * @param psElement the element to extract extents from.
199 : *
200 : * @param psMin structure loaded with X, Y and Z minimum values for the
201 : * extent.
202 : *
203 : * @param psMax structure loaded with X, Y and Z maximum values for the
204 : * extent.
205 : *
206 : * @return TRUE on success of FALSE if extracting extents fails.
207 : */
208 :
209 2 : int DGNGetElementExtents( DGNHandle hDGN, DGNElemCore *psElement,
210 : DGNPoint *psMin, DGNPoint *psMax )
211 :
212 : {
213 2 : DGNInfo *psDGN = (DGNInfo *) hDGN;
214 : GUInt32 anMin[3], anMax[3];
215 : int bResult;
216 :
217 : /* -------------------------------------------------------------------- */
218 : /* Get the extents if we have raw data in the element, or */
219 : /* loaded in the file buffer. */
220 : /* -------------------------------------------------------------------- */
221 2 : if( psElement->raw_data != NULL )
222 : bResult = DGNGetRawExtents( psDGN, psElement->type,
223 : psElement->raw_data,
224 : anMin + 0, anMin + 1, anMin + 2,
225 2 : anMax + 0, anMax + 1, anMax + 2 );
226 0 : else if( psElement->element_id == psDGN->next_element_id - 1 )
227 : bResult = DGNGetRawExtents( psDGN, psElement->type,
228 : psDGN->abyElem + 0,
229 : anMin + 0, anMin + 1, anMin + 2,
230 0 : anMax + 0, anMax + 1, anMax + 2 );
231 : else
232 : {
233 : CPLError(CE_Warning, CPLE_AppDefined,
234 : "DGNGetElementExtents() fails because the requested element\n"
235 0 : " does not have raw data available." );
236 0 : return FALSE;
237 : }
238 :
239 2 : if( !bResult )
240 0 : return FALSE;
241 :
242 : /* -------------------------------------------------------------------- */
243 : /* Transform to user coordinate system and return. The offset */
244 : /* is to convert from "binary offset" form to twos complement. */
245 : /* -------------------------------------------------------------------- */
246 2 : psMin->x = anMin[0] - 2147483648.0;
247 2 : psMin->y = anMin[1] - 2147483648.0;
248 2 : psMin->z = anMin[2] - 2147483648.0;
249 :
250 2 : psMax->x = anMax[0] - 2147483648.0;
251 2 : psMax->y = anMax[1] - 2147483648.0;
252 2 : psMax->z = anMax[2] - 2147483648.0;
253 :
254 2 : DGNTransformPoint( psDGN, psMin );
255 2 : DGNTransformPoint( psDGN, psMax );
256 :
257 2 : return TRUE;
258 : }
259 :
260 : /************************************************************************/
261 : /* DGNProcessElement() */
262 : /* */
263 : /* Assumes the raw element data has already been loaded, and */
264 : /* tries to convert it into an element structure. */
265 : /************************************************************************/
266 :
267 101 : static DGNElemCore *DGNProcessElement( DGNInfo *psDGN, int nType, int nLevel )
268 :
269 : {
270 101 : DGNElemCore *psElement = NULL;
271 :
272 : /* -------------------------------------------------------------------- */
273 : /* Handle based on element type. */
274 : /* -------------------------------------------------------------------- */
275 101 : switch( nType )
276 : {
277 : case DGNT_CELL_HEADER:
278 : {
279 : DGNElemCellHeader *psCell;
280 :
281 : psCell = (DGNElemCellHeader *)
282 0 : CPLCalloc(sizeof(DGNElemCellHeader),1);
283 0 : psElement = (DGNElemCore *) psCell;
284 0 : psElement->stype = DGNST_CELL_HEADER;
285 0 : DGNParseCore( psDGN, psElement );
286 :
287 0 : psCell->totlength = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
288 :
289 0 : DGNRad50ToAscii( psDGN->abyElem[38] + psDGN->abyElem[39] * 256,
290 0 : psCell->name + 0 );
291 0 : DGNRad50ToAscii( psDGN->abyElem[40] + psDGN->abyElem[41] * 256,
292 0 : psCell->name + 3 );
293 :
294 0 : psCell->cclass = psDGN->abyElem[42] + psDGN->abyElem[43] * 256;
295 0 : psCell->levels[0] = psDGN->abyElem[44] + psDGN->abyElem[45] * 256;
296 0 : psCell->levels[1] = psDGN->abyElem[46] + psDGN->abyElem[47] * 256;
297 0 : psCell->levels[2] = psDGN->abyElem[48] + psDGN->abyElem[49] * 256;
298 0 : psCell->levels[3] = psDGN->abyElem[50] + psDGN->abyElem[51] * 256;
299 :
300 0 : if( psDGN->dimension == 2 )
301 : {
302 0 : psCell->rnglow.x = DGN_INT32( psDGN->abyElem + 52 );
303 0 : psCell->rnglow.y = DGN_INT32( psDGN->abyElem + 56 );
304 0 : psCell->rnghigh.x = DGN_INT32( psDGN->abyElem + 60 );
305 0 : psCell->rnghigh.y = DGN_INT32( psDGN->abyElem + 64 );
306 :
307 : psCell->trans[0] =
308 0 : 1.0 * DGN_INT32( psDGN->abyElem + 68 ) / (1<<31);
309 : psCell->trans[1] =
310 0 : 1.0 * DGN_INT32( psDGN->abyElem + 72 ) / (1<<31);
311 : psCell->trans[2] =
312 0 : 1.0 * DGN_INT32( psDGN->abyElem + 76 ) / (1<<31);
313 : psCell->trans[3] =
314 0 : 1.0 * DGN_INT32( psDGN->abyElem + 80 ) / (1<<31);
315 :
316 0 : psCell->origin.x = DGN_INT32( psDGN->abyElem + 84 );
317 0 : psCell->origin.y = DGN_INT32( psDGN->abyElem + 88 );
318 :
319 : {
320 : double a, b, c, d, a2, c2;
321 0 : a = DGN_INT32( psDGN->abyElem + 68 );
322 0 : b = DGN_INT32( psDGN->abyElem + 72 );
323 0 : c = DGN_INT32( psDGN->abyElem + 76 );
324 0 : d = DGN_INT32( psDGN->abyElem + 80 );
325 0 : a2 = a * a;
326 0 : c2 = c * c;
327 :
328 0 : psCell->xscale = sqrt(a2 + c2) / 214748;
329 0 : psCell->yscale = sqrt(b*b + d*d) / 214748;
330 0 : if( (a2 + c2) <= 0.0 )
331 0 : psCell->rotation = 0.0;
332 : else
333 0 : psCell->rotation = acos(a / sqrt(a2 + c2));
334 :
335 0 : if (b <= 0)
336 0 : psCell->rotation = psCell->rotation * 180 / PI;
337 : else
338 0 : psCell->rotation = 360 - psCell->rotation * 180 / PI;
339 : }
340 : }
341 : else
342 : {
343 0 : psCell->rnglow.x = DGN_INT32( psDGN->abyElem + 52 );
344 0 : psCell->rnglow.y = DGN_INT32( psDGN->abyElem + 56 );
345 0 : psCell->rnglow.z = DGN_INT32( psDGN->abyElem + 60 );
346 0 : psCell->rnghigh.x = DGN_INT32( psDGN->abyElem + 64 );
347 0 : psCell->rnghigh.y = DGN_INT32( psDGN->abyElem + 68 );
348 0 : psCell->rnghigh.z = DGN_INT32( psDGN->abyElem + 72 );
349 :
350 : psCell->trans[0] =
351 0 : 1.0 * DGN_INT32( psDGN->abyElem + 76 ) / (1<<31);
352 : psCell->trans[1] =
353 0 : 1.0 * DGN_INT32( psDGN->abyElem + 80 ) / (1<<31);
354 : psCell->trans[2] =
355 0 : 1.0 * DGN_INT32( psDGN->abyElem + 84 ) / (1<<31);
356 : psCell->trans[3] =
357 0 : 1.0 * DGN_INT32( psDGN->abyElem + 88 ) / (1<<31);
358 : psCell->trans[4] =
359 0 : 1.0 * DGN_INT32( psDGN->abyElem + 92 ) / (1<<31);
360 : psCell->trans[5] =
361 0 : 1.0 * DGN_INT32( psDGN->abyElem + 96 ) / (1<<31);
362 : psCell->trans[6] =
363 0 : 1.0 * DGN_INT32( psDGN->abyElem + 100 ) / (1<<31);
364 : psCell->trans[7] =
365 0 : 1.0 * DGN_INT32( psDGN->abyElem + 104 ) / (1<<31);
366 : psCell->trans[8] =
367 0 : 1.0 * DGN_INT32( psDGN->abyElem + 108 ) / (1<<31);
368 :
369 0 : psCell->origin.x = DGN_INT32( psDGN->abyElem + 112 );
370 0 : psCell->origin.y = DGN_INT32( psDGN->abyElem + 116 );
371 0 : psCell->origin.z = DGN_INT32( psDGN->abyElem + 120 );
372 : }
373 :
374 0 : DGNTransformPoint( psDGN, &(psCell->rnglow) );
375 0 : DGNTransformPoint( psDGN, &(psCell->rnghigh) );
376 0 : DGNTransformPoint( psDGN, &(psCell->origin) );
377 : }
378 0 : break;
379 :
380 : case DGNT_CELL_LIBRARY:
381 : {
382 : DGNElemCellLibrary *psCell;
383 : int iWord;
384 :
385 : psCell = (DGNElemCellLibrary *)
386 0 : CPLCalloc(sizeof(DGNElemCellLibrary),1);
387 0 : psElement = (DGNElemCore *) psCell;
388 0 : psElement->stype = DGNST_CELL_LIBRARY;
389 0 : DGNParseCore( psDGN, psElement );
390 :
391 0 : DGNRad50ToAscii( psDGN->abyElem[32] + psDGN->abyElem[33] * 256,
392 0 : psCell->name + 0 );
393 0 : DGNRad50ToAscii( psDGN->abyElem[34] + psDGN->abyElem[35] * 256,
394 0 : psCell->name + 3 );
395 :
396 0 : psElement->properties = psDGN->abyElem[38]
397 0 : + psDGN->abyElem[39] * 256;
398 :
399 0 : psCell->dispsymb = psDGN->abyElem[40] + psDGN->abyElem[41] * 256;
400 :
401 0 : psCell->cclass = psDGN->abyElem[42] + psDGN->abyElem[43] * 256;
402 0 : psCell->levels[0] = psDGN->abyElem[44] + psDGN->abyElem[45] * 256;
403 0 : psCell->levels[1] = psDGN->abyElem[46] + psDGN->abyElem[47] * 256;
404 0 : psCell->levels[2] = psDGN->abyElem[48] + psDGN->abyElem[49] * 256;
405 0 : psCell->levels[3] = psDGN->abyElem[50] + psDGN->abyElem[51] * 256;
406 :
407 0 : psCell->numwords = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
408 :
409 0 : memset( psCell->description, 0, sizeof(psCell->description) );
410 :
411 0 : for( iWord = 0; iWord < 9; iWord++ )
412 : {
413 0 : int iOffset = 52 + iWord * 2;
414 :
415 0 : DGNRad50ToAscii( psDGN->abyElem[iOffset]
416 0 : + psDGN->abyElem[iOffset+1] * 256,
417 0 : psCell->description + iWord * 3 );
418 : }
419 : }
420 0 : break;
421 :
422 : case DGNT_LINE:
423 : {
424 : DGNElemMultiPoint *psLine;
425 :
426 : psLine = (DGNElemMultiPoint *)
427 3 : CPLCalloc(sizeof(DGNElemMultiPoint),1);
428 3 : psElement = (DGNElemCore *) psLine;
429 3 : psElement->stype = DGNST_MULTIPOINT;
430 3 : DGNParseCore( psDGN, psElement );
431 :
432 3 : psLine->num_vertices = 2;
433 3 : if( psDGN->dimension == 2 )
434 : {
435 3 : psLine->vertices[0].x = DGN_INT32( psDGN->abyElem + 36 );
436 3 : psLine->vertices[0].y = DGN_INT32( psDGN->abyElem + 40 );
437 3 : psLine->vertices[1].x = DGN_INT32( psDGN->abyElem + 44 );
438 3 : psLine->vertices[1].y = DGN_INT32( psDGN->abyElem + 48 );
439 : }
440 : else
441 : {
442 0 : psLine->vertices[0].x = DGN_INT32( psDGN->abyElem + 36 );
443 0 : psLine->vertices[0].y = DGN_INT32( psDGN->abyElem + 40 );
444 0 : psLine->vertices[0].z = DGN_INT32( psDGN->abyElem + 44 );
445 0 : psLine->vertices[1].x = DGN_INT32( psDGN->abyElem + 48 );
446 0 : psLine->vertices[1].y = DGN_INT32( psDGN->abyElem + 52 );
447 0 : psLine->vertices[1].z = DGN_INT32( psDGN->abyElem + 56 );
448 : }
449 3 : DGNTransformPoint( psDGN, psLine->vertices + 0 );
450 3 : DGNTransformPoint( psDGN, psLine->vertices + 1 );
451 : }
452 3 : break;
453 :
454 : case DGNT_LINE_STRING:
455 : case DGNT_SHAPE:
456 : case DGNT_CURVE:
457 : case DGNT_BSPLINE_POLE:
458 : {
459 : DGNElemMultiPoint *psLine;
460 : int i, count;
461 7 : int pntsize = psDGN->dimension * 4;
462 :
463 7 : count = psDGN->abyElem[36] + psDGN->abyElem[37]*256;
464 : psLine = (DGNElemMultiPoint *)
465 7 : CPLCalloc(sizeof(DGNElemMultiPoint)+(count-2)*sizeof(DGNPoint),1);
466 7 : psElement = (DGNElemCore *) psLine;
467 7 : psElement->stype = DGNST_MULTIPOINT;
468 7 : DGNParseCore( psDGN, psElement );
469 :
470 7 : if( psDGN->nElemBytes < 38 + count * pntsize )
471 : {
472 : CPLError( CE_Warning, CPLE_AppDefined,
473 : "Trimming multipoint vertices to %d from %d because\n"
474 : "element is short.\n",
475 : (psDGN->nElemBytes - 38) / pntsize,
476 0 : count );
477 0 : count = (psDGN->nElemBytes - 38) / pntsize;
478 : }
479 7 : psLine->num_vertices = count;
480 106 : for( i = 0; i < psLine->num_vertices; i++ )
481 : {
482 : psLine->vertices[i].x =
483 99 : DGN_INT32( psDGN->abyElem + 38 + i*pntsize );
484 : psLine->vertices[i].y =
485 99 : DGN_INT32( psDGN->abyElem + 42 + i*pntsize );
486 99 : if( psDGN->dimension == 3 )
487 : psLine->vertices[i].z =
488 0 : DGN_INT32( psDGN->abyElem + 46 + i*pntsize );
489 :
490 99 : DGNTransformPoint( psDGN, psLine->vertices + i );
491 : }
492 : }
493 7 : break;
494 :
495 : case DGNT_TEXT_NODE:
496 : {
497 : DGNElemTextNode *psNode;
498 :
499 0 : psNode = (DGNElemTextNode *) CPLCalloc(sizeof(DGNElemTextNode),1);
500 0 : psElement = (DGNElemCore *) psNode;
501 0 : psElement->stype = DGNST_TEXT_NODE;
502 0 : DGNParseCore( psDGN, psElement );
503 :
504 0 : psNode->totlength = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
505 0 : psNode->numelems = psDGN->abyElem[38] + psDGN->abyElem[39] * 256;
506 :
507 0 : psNode->node_number = psDGN->abyElem[40] + psDGN->abyElem[41] * 256;
508 0 : psNode->max_length = psDGN->abyElem[42];
509 0 : psNode->max_used = psDGN->abyElem[43];
510 0 : psNode->font_id = psDGN->abyElem[44];
511 0 : psNode->justification = psDGN->abyElem[45];
512 0 : psNode->length_mult = (DGN_INT32( psDGN->abyElem + 50 ))
513 0 : * psDGN->scale * 6.0 / 1000.0;
514 0 : psNode->height_mult = (DGN_INT32( psDGN->abyElem + 54 ))
515 0 : * psDGN->scale * 6.0 / 1000.0;
516 :
517 0 : if( psDGN->dimension == 2 )
518 : {
519 0 : psNode->rotation = DGN_INT32( psDGN->abyElem + 58 ) / 360000.0;
520 :
521 0 : psNode->origin.x = DGN_INT32( psDGN->abyElem + 62 );
522 0 : psNode->origin.y = DGN_INT32( psDGN->abyElem + 66 );
523 : }
524 : else
525 : {
526 : /* leave quaternion for later */
527 :
528 0 : psNode->origin.x = DGN_INT32( psDGN->abyElem + 74 );
529 0 : psNode->origin.y = DGN_INT32( psDGN->abyElem + 78 );
530 0 : psNode->origin.z = DGN_INT32( psDGN->abyElem + 82 );
531 : }
532 0 : DGNTransformPoint( psDGN, &(psNode->origin) );
533 :
534 : }
535 0 : break;
536 :
537 : case DGNT_GROUP_DATA:
538 5 : if( nLevel == DGN_GDL_COLOR_TABLE )
539 : {
540 0 : psElement = DGNParseColorTable( psDGN );
541 : }
542 : else
543 : {
544 5 : psElement = (DGNElemCore *) CPLCalloc(sizeof(DGNElemCore),1);
545 5 : psElement->stype = DGNST_CORE;
546 5 : DGNParseCore( psDGN, psElement );
547 : }
548 5 : break;
549 :
550 : case DGNT_ELLIPSE:
551 : {
552 : DGNElemArc *psEllipse;
553 :
554 5 : psEllipse = (DGNElemArc *) CPLCalloc(sizeof(DGNElemArc),1);
555 5 : psElement = (DGNElemCore *) psEllipse;
556 5 : psElement->stype = DGNST_ARC;
557 5 : DGNParseCore( psDGN, psElement );
558 :
559 5 : memcpy( &(psEllipse->primary_axis), psDGN->abyElem + 36, 8 );
560 5 : DGN2IEEEDouble( &(psEllipse->primary_axis) );
561 5 : psEllipse->primary_axis *= psDGN->scale;
562 :
563 5 : memcpy( &(psEllipse->secondary_axis), psDGN->abyElem + 44, 8 );
564 5 : DGN2IEEEDouble( &(psEllipse->secondary_axis) );
565 5 : psEllipse->secondary_axis *= psDGN->scale;
566 :
567 5 : if( psDGN->dimension == 2 )
568 : {
569 5 : psEllipse->rotation = DGN_INT32( psDGN->abyElem + 52 );
570 5 : psEllipse->rotation = psEllipse->rotation / 360000.0;
571 :
572 5 : memcpy( &(psEllipse->origin.x), psDGN->abyElem + 56, 8 );
573 5 : DGN2IEEEDouble( &(psEllipse->origin.x) );
574 :
575 5 : memcpy( &(psEllipse->origin.y), psDGN->abyElem + 64, 8 );
576 5 : DGN2IEEEDouble( &(psEllipse->origin.y) );
577 : }
578 : else
579 : {
580 : /* leave quaternion for later */
581 :
582 0 : memcpy( &(psEllipse->origin.x), psDGN->abyElem + 68, 8 );
583 0 : DGN2IEEEDouble( &(psEllipse->origin.x) );
584 :
585 0 : memcpy( &(psEllipse->origin.y), psDGN->abyElem + 76, 8 );
586 0 : DGN2IEEEDouble( &(psEllipse->origin.y) );
587 :
588 0 : memcpy( &(psEllipse->origin.z), psDGN->abyElem + 84, 8 );
589 0 : DGN2IEEEDouble( &(psEllipse->origin.z) );
590 :
591 0 : psEllipse->quat[0] = DGN_INT32( psDGN->abyElem + 52 );
592 0 : psEllipse->quat[1] = DGN_INT32( psDGN->abyElem + 56 );
593 0 : psEllipse->quat[2] = DGN_INT32( psDGN->abyElem + 60 );
594 0 : psEllipse->quat[3] = DGN_INT32( psDGN->abyElem + 64 );
595 : }
596 :
597 5 : DGNTransformPoint( psDGN, &(psEllipse->origin) );
598 :
599 5 : psEllipse->startang = 0.0;
600 5 : psEllipse->sweepang = 360.0;
601 : }
602 5 : break;
603 :
604 : case DGNT_ARC:
605 : {
606 : DGNElemArc *psEllipse;
607 : GInt32 nSweepVal;
608 :
609 0 : psEllipse = (DGNElemArc *) CPLCalloc(sizeof(DGNElemArc),1);
610 0 : psElement = (DGNElemCore *) psEllipse;
611 0 : psElement->stype = DGNST_ARC;
612 0 : DGNParseCore( psDGN, psElement );
613 :
614 0 : psEllipse->startang = DGN_INT32( psDGN->abyElem + 36 );
615 0 : psEllipse->startang = psEllipse->startang / 360000.0;
616 0 : if( psDGN->abyElem[41] & 0x80 )
617 : {
618 0 : psDGN->abyElem[41] &= 0x7f;
619 0 : nSweepVal = -1 * DGN_INT32( psDGN->abyElem + 40 );
620 : }
621 : else
622 0 : nSweepVal = DGN_INT32( psDGN->abyElem + 40 );
623 :
624 0 : if( nSweepVal == 0 )
625 0 : psEllipse->sweepang = 360.0;
626 : else
627 0 : psEllipse->sweepang = nSweepVal / 360000.0;
628 :
629 0 : memcpy( &(psEllipse->primary_axis), psDGN->abyElem + 44, 8 );
630 0 : DGN2IEEEDouble( &(psEllipse->primary_axis) );
631 0 : psEllipse->primary_axis *= psDGN->scale;
632 :
633 0 : memcpy( &(psEllipse->secondary_axis), psDGN->abyElem + 52, 8 );
634 0 : DGN2IEEEDouble( &(psEllipse->secondary_axis) );
635 0 : psEllipse->secondary_axis *= psDGN->scale;
636 :
637 0 : if( psDGN->dimension == 2 )
638 : {
639 0 : psEllipse->rotation = DGN_INT32( psDGN->abyElem + 60 );
640 0 : psEllipse->rotation = psEllipse->rotation / 360000.0;
641 :
642 0 : memcpy( &(psEllipse->origin.x), psDGN->abyElem + 64, 8 );
643 0 : DGN2IEEEDouble( &(psEllipse->origin.x) );
644 :
645 0 : memcpy( &(psEllipse->origin.y), psDGN->abyElem + 72, 8 );
646 0 : DGN2IEEEDouble( &(psEllipse->origin.y) );
647 : }
648 : else
649 : {
650 : /* for now we don't try to handle quaternion */
651 0 : psEllipse->rotation = 0;
652 :
653 0 : memcpy( &(psEllipse->origin.x), psDGN->abyElem + 76, 8 );
654 0 : DGN2IEEEDouble( &(psEllipse->origin.x) );
655 :
656 0 : memcpy( &(psEllipse->origin.y), psDGN->abyElem + 84, 8 );
657 0 : DGN2IEEEDouble( &(psEllipse->origin.y) );
658 :
659 0 : memcpy( &(psEllipse->origin.z), psDGN->abyElem + 92, 8 );
660 0 : DGN2IEEEDouble( &(psEllipse->origin.z) );
661 :
662 0 : psEllipse->quat[0] = DGN_INT32( psDGN->abyElem + 60 );
663 0 : psEllipse->quat[1] = DGN_INT32( psDGN->abyElem + 64 );
664 0 : psEllipse->quat[2] = DGN_INT32( psDGN->abyElem + 68 );
665 0 : psEllipse->quat[3] = DGN_INT32( psDGN->abyElem + 72 );
666 : }
667 :
668 0 : DGNTransformPoint( psDGN, &(psEllipse->origin) );
669 : }
670 0 : break;
671 :
672 : case DGNT_TEXT:
673 : {
674 : DGNElemText *psText;
675 : int num_chars, text_off;
676 :
677 5 : if( psDGN->dimension == 2 )
678 5 : num_chars = psDGN->abyElem[58];
679 : else
680 0 : num_chars = psDGN->abyElem[74];
681 :
682 5 : psText = (DGNElemText *) CPLCalloc(sizeof(DGNElemText)+num_chars,1);
683 5 : psElement = (DGNElemCore *) psText;
684 5 : psElement->stype = DGNST_TEXT;
685 5 : DGNParseCore( psDGN, psElement );
686 :
687 5 : psText->font_id = psDGN->abyElem[36];
688 5 : psText->justification = psDGN->abyElem[37];
689 20 : psText->length_mult = (DGN_INT32( psDGN->abyElem + 38 ))
690 20 : * psDGN->scale * 6.0 / 1000.0;
691 20 : psText->height_mult = (DGN_INT32( psDGN->abyElem + 42 ))
692 20 : * psDGN->scale * 6.0 / 1000.0;
693 :
694 5 : if( psDGN->dimension == 2 )
695 : {
696 5 : psText->rotation = DGN_INT32( psDGN->abyElem + 46 );
697 5 : psText->rotation = psText->rotation / 360000.0;
698 :
699 5 : psText->origin.x = DGN_INT32( psDGN->abyElem + 50 );
700 5 : psText->origin.y = DGN_INT32( psDGN->abyElem + 54 );
701 5 : text_off = 60;
702 : }
703 : else
704 : {
705 : /* leave quaternion for later */
706 :
707 0 : psText->origin.x = DGN_INT32( psDGN->abyElem + 62 );
708 0 : psText->origin.y = DGN_INT32( psDGN->abyElem + 66 );
709 0 : psText->origin.z = DGN_INT32( psDGN->abyElem + 70 );
710 0 : text_off = 76;
711 : }
712 :
713 5 : DGNTransformPoint( psDGN, &(psText->origin) );
714 :
715 : /* experimental multibyte support from Ason Kang (hiska@netian.com)*/
716 5 : if (*(psDGN->abyElem + text_off) == 0xFF
717 : && *(psDGN->abyElem + text_off + 1) == 0xFD)
718 : {
719 0 : int n=0;
720 0 : for (int i=0;i<num_chars/2-1;i++) {
721 : unsigned short w;
722 0 : memcpy(&w,psDGN->abyElem + text_off + 2 + i*2 ,2);
723 0 : w = CPL_LSBWORD16(w);
724 0 : if (w<256) { // if alpa-numeric code area : Normal character
725 0 : *(psText->string + n) = (char) (w & 0xFF);
726 0 : n++; // skip 1 byte;
727 : }
728 : else { // if extend code area : 2 byte Korean character
729 0 : *(psText->string + n) = (char) (w >> 8); // hi
730 0 : *(psText->string + n + 1) = (char) (w & 0xFF); // lo
731 0 : n+=2; // 2 byte
732 : }
733 : }
734 0 : psText->string[n] = '\0'; // terminate C string
735 : }
736 : else
737 : {
738 5 : memcpy( psText->string, psDGN->abyElem + text_off, num_chars );
739 5 : psText->string[num_chars] = '\0';
740 : }
741 : }
742 5 : break;
743 :
744 : case DGNT_TCB:
745 13 : psElement = DGNParseTCB( psDGN );
746 13 : break;
747 :
748 : case DGNT_COMPLEX_CHAIN_HEADER:
749 : case DGNT_COMPLEX_SHAPE_HEADER:
750 : {
751 : DGNElemComplexHeader *psHdr;
752 :
753 : psHdr = (DGNElemComplexHeader *)
754 1 : CPLCalloc(sizeof(DGNElemComplexHeader),1);
755 1 : psElement = (DGNElemCore *) psHdr;
756 1 : psElement->stype = DGNST_COMPLEX_HEADER;
757 1 : DGNParseCore( psDGN, psElement );
758 :
759 1 : psHdr->totlength = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
760 1 : psHdr->numelems = psDGN->abyElem[38] + psDGN->abyElem[39] * 256;
761 : }
762 1 : break;
763 :
764 : case DGNT_TAG_VALUE:
765 : {
766 : DGNElemTagValue *psTag;
767 :
768 : psTag = (DGNElemTagValue *)
769 0 : CPLCalloc(sizeof(DGNElemTagValue),1);
770 0 : psElement = (DGNElemCore *) psTag;
771 0 : psElement->stype = DGNST_TAG_VALUE;
772 0 : DGNParseCore( psDGN, psElement );
773 :
774 0 : psTag->tagType = psDGN->abyElem[74] + psDGN->abyElem[75] * 256;
775 0 : memcpy( &(psTag->tagSet), psDGN->abyElem + 68, 4 );
776 0 : psTag->tagSet = CPL_LSBWORD32(psTag->tagSet);
777 0 : psTag->tagIndex = psDGN->abyElem[72] + psDGN->abyElem[73] * 256;
778 0 : psTag->tagLength = psDGN->abyElem[150] + psDGN->abyElem[151] * 256;
779 :
780 0 : if( psTag->tagType == 1 )
781 : {
782 : psTag->tagValue.string =
783 0 : CPLStrdup( (char *) psDGN->abyElem + 154 );
784 : }
785 0 : else if( psTag->tagType == 3 )
786 : {
787 : memcpy( &(psTag->tagValue.integer),
788 0 : psDGN->abyElem + 154, 4 );
789 : psTag->tagValue.integer =
790 0 : CPL_LSBWORD32( psTag->tagValue.integer );
791 : }
792 0 : else if( psTag->tagType == 4 )
793 : {
794 : memcpy( &(psTag->tagValue.real),
795 0 : psDGN->abyElem + 154, 8 );
796 0 : DGN2IEEEDouble( &(psTag->tagValue.real) );
797 : }
798 : }
799 0 : break;
800 :
801 : case DGNT_APPLICATION_ELEM:
802 48 : if( nLevel == 24 )
803 : {
804 0 : psElement = DGNParseTagSet( psDGN );
805 : }
806 : else
807 : {
808 48 : psElement = (DGNElemCore *) CPLCalloc(sizeof(DGNElemCore),1);
809 48 : psElement->stype = DGNST_CORE;
810 48 : DGNParseCore( psDGN, psElement );
811 : }
812 48 : break;
813 :
814 : case DGNT_CONE:
815 : {
816 : DGNElemCone *psCone;
817 :
818 0 : psCone = (DGNElemCone *) CPLCalloc(sizeof(DGNElemCone),1);
819 0 : psElement = (DGNElemCore *) psCone;
820 0 : psElement->stype = DGNST_CONE;
821 0 : DGNParseCore( psDGN, psElement );
822 :
823 : CPLAssert( psDGN->dimension == 3 );
824 0 : psCone->unknown = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
825 0 : psCone->quat[0] = DGN_INT32( psDGN->abyElem + 38 );
826 0 : psCone->quat[1] = DGN_INT32( psDGN->abyElem + 42 );
827 0 : psCone->quat[2] = DGN_INT32( psDGN->abyElem + 46 );
828 0 : psCone->quat[3] = DGN_INT32( psDGN->abyElem + 50 );
829 :
830 0 : memcpy( &(psCone->center_1.x), psDGN->abyElem + 54, 8 );
831 0 : DGN2IEEEDouble( &(psCone->center_1.x) );
832 0 : memcpy( &(psCone->center_1.y), psDGN->abyElem + 62, 8 );
833 0 : DGN2IEEEDouble( &(psCone->center_1.y) );
834 0 : memcpy( &(psCone->center_1.z), psDGN->abyElem + 70, 8 );
835 0 : DGN2IEEEDouble( &(psCone->center_1.z) );
836 0 : memcpy( &(psCone->radius_1), psDGN->abyElem + 78, 8 );
837 0 : DGN2IEEEDouble( &(psCone->radius_1) );
838 :
839 0 : memcpy( &(psCone->center_2.x), psDGN->abyElem + 86, 8 );
840 0 : DGN2IEEEDouble( &(psCone->center_2.x) );
841 0 : memcpy( &(psCone->center_2.y), psDGN->abyElem + 94, 8 );
842 0 : DGN2IEEEDouble( &(psCone->center_2.y) );
843 0 : memcpy( &(psCone->center_2.z), psDGN->abyElem + 102, 8 );
844 0 : DGN2IEEEDouble( &(psCone->center_2.z) );
845 0 : memcpy( &(psCone->radius_2), psDGN->abyElem + 110, 8 );
846 0 : DGN2IEEEDouble( &(psCone->radius_2) );
847 :
848 0 : psCone->radius_1 *= psDGN->scale;
849 0 : psCone->radius_2 *= psDGN->scale;
850 0 : DGNTransformPoint( psDGN, &psCone->center_1 );
851 0 : DGNTransformPoint( psDGN, &psCone->center_2 );
852 : }
853 0 : break;
854 :
855 : case DGNT_3DSURFACE_HEADER:
856 : case DGNT_3DSOLID_HEADER:
857 : {
858 : DGNElemComplexHeader *psShape;
859 :
860 : psShape =
861 0 : (DGNElemComplexHeader *) CPLCalloc(sizeof(DGNElemComplexHeader),1);
862 0 : psElement = (DGNElemCore *) psShape;
863 0 : psElement->stype = DGNST_COMPLEX_HEADER;
864 0 : DGNParseCore( psDGN, psElement );
865 :
866 : // Read complex header
867 0 : psShape->totlength = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
868 0 : psShape->numelems = psDGN->abyElem[38] + psDGN->abyElem[39] * 256;
869 0 : psShape->surftype = psDGN->abyElem[40];
870 0 : psShape->boundelms = psDGN->abyElem[41] + 1;
871 : }
872 0 : break;
873 : case DGNT_BSPLINE_SURFACE_HEADER:
874 : {
875 : DGNElemBSplineSurfaceHeader *psSpline;
876 :
877 : psSpline = (DGNElemBSplineSurfaceHeader *)
878 0 : CPLCalloc(sizeof(DGNElemBSplineSurfaceHeader), 1);
879 0 : psElement = (DGNElemCore *) psSpline;
880 0 : psElement->stype = DGNST_BSPLINE_SURFACE_HEADER;
881 0 : DGNParseCore( psDGN, psElement );
882 :
883 : // Read B-Spline surface header
884 0 : psSpline->desc_words = DGN_INT32(psDGN->abyElem + 36);
885 0 : psSpline->curve_type = psDGN->abyElem[41];
886 :
887 : // U
888 0 : psSpline->u_order = (psDGN->abyElem[40] & 0x0f) + 2;
889 0 : psSpline->u_properties = psDGN->abyElem[40] & 0xf0;
890 0 : psSpline->num_poles_u = psDGN->abyElem[42] + psDGN->abyElem[43]*256;
891 0 : psSpline->num_knots_u = psDGN->abyElem[44] + psDGN->abyElem[45]*256;
892 0 : psSpline->rule_lines_u = psDGN->abyElem[46] + psDGN->abyElem[47]*256;
893 :
894 : // V
895 0 : psSpline->v_order = (psDGN->abyElem[48] & 0x0f) + 2;
896 0 : psSpline->v_properties = psDGN->abyElem[48] & 0xf0;
897 0 : psSpline->num_poles_v = psDGN->abyElem[50] + psDGN->abyElem[51]*256;
898 0 : psSpline->num_knots_v = psDGN->abyElem[52] + psDGN->abyElem[53]*256;
899 0 : psSpline->rule_lines_v = psDGN->abyElem[54] + psDGN->abyElem[55]*256;
900 :
901 0 : psSpline->num_bounds = psDGN->abyElem[56] + psDGN->abyElem[57]*556;
902 : }
903 0 : break;
904 : case DGNT_BSPLINE_CURVE_HEADER:
905 : {
906 : DGNElemBSplineCurveHeader *psSpline;
907 :
908 : psSpline = (DGNElemBSplineCurveHeader *)
909 0 : CPLCalloc(sizeof(DGNElemBSplineCurveHeader), 1);
910 0 : psElement = (DGNElemCore *) psSpline;
911 0 : psElement->stype = DGNST_BSPLINE_CURVE_HEADER;
912 0 : DGNParseCore( psDGN, psElement );
913 :
914 : // Read B-Spline curve header
915 0 : psSpline->desc_words = DGN_INT32(psDGN->abyElem + 36);
916 :
917 : // flags
918 0 : psSpline->order = (psDGN->abyElem[40] & 0x0f) + 2;
919 0 : psSpline->properties = psDGN->abyElem[40] & 0xf0;
920 0 : psSpline->curve_type = psDGN->abyElem[41];
921 :
922 0 : psSpline->num_poles = psDGN->abyElem[42] + psDGN->abyElem[43]*256;
923 0 : psSpline->num_knots = psDGN->abyElem[44] + psDGN->abyElem[45]*256;
924 : }
925 0 : break;
926 : case DGNT_BSPLINE_SURFACE_BOUNDARY:
927 : {
928 : DGNElemBSplineSurfaceBoundary *psBounds;
929 0 : int numverts = psDGN->abyElem[38] + psDGN->abyElem[39]*256;
930 :
931 : psBounds = (DGNElemBSplineSurfaceBoundary *)
932 : CPLCalloc(sizeof(DGNElemBSplineSurfaceBoundary)+
933 0 : (numverts-1)*sizeof(DGNPoint), 1);
934 0 : psElement = (DGNElemCore *) psBounds;
935 0 : psElement->stype = DGNST_BSPLINE_SURFACE_BOUNDARY;
936 0 : DGNParseCore( psDGN, psElement );
937 :
938 : // Read B-Spline surface boundary
939 0 : psBounds->number = psDGN->abyElem[36] + psDGN->abyElem[37]*256;
940 0 : psBounds->numverts = numverts;
941 :
942 0 : for (int i=0;i<psBounds->numverts;i++) {
943 0 : psBounds->vertices[i].x = DGN_INT32( psDGN->abyElem + 40 + i*8 );
944 0 : psBounds->vertices[i].y = DGN_INT32( psDGN->abyElem + 44 + i*8 );
945 0 : psBounds->vertices[i].z = 0;
946 : }
947 : }
948 0 : break;
949 : case DGNT_BSPLINE_KNOT:
950 : case DGNT_BSPLINE_WEIGHT_FACTOR:
951 : {
952 : DGNElemKnotWeight *psArray;
953 : // FIXME: Is it OK to assume that the # of elements corresponds
954 : // directly to the element size? kintel 20051215.
955 : int attr_bytes = psDGN->nElemBytes -
956 0 : (psDGN->abyElem[30] + psDGN->abyElem[31]*256)*2 - 32;
957 0 : int numelems = (psDGN->nElemBytes - 36 - attr_bytes)/4;
958 :
959 : psArray = (DGNElemKnotWeight *)
960 0 : CPLCalloc(sizeof(DGNElemKnotWeight) + (numelems-1)*sizeof(float), 1);
961 :
962 0 : psElement = (DGNElemCore *) psArray;
963 0 : psElement->stype = DGNST_KNOT_WEIGHT;
964 0 : DGNParseCore( psDGN, psElement );
965 :
966 : // Read array
967 0 : for (int i=0;i<numelems;i++) {
968 0 : psArray->array[i] =
969 0 : 1.0f * DGN_INT32(psDGN->abyElem + 36 + i*4) / ((1L << 31) - 1);
970 : }
971 : }
972 0 : break;
973 : case DGNT_SHARED_CELL_DEFN:
974 : {
975 : DGNElemSharedCellDefn *psShared;
976 :
977 : psShared = (DGNElemSharedCellDefn *)
978 0 : CPLCalloc(sizeof(DGNElemSharedCellDefn),1);
979 0 : psElement = (DGNElemCore *) psShared;
980 0 : psElement->stype = DGNST_SHARED_CELL_DEFN;
981 0 : DGNParseCore( psDGN, psElement );
982 :
983 0 : psShared->totlength = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
984 : }
985 0 : break;
986 : default:
987 : {
988 14 : psElement = (DGNElemCore *) CPLCalloc(sizeof(DGNElemCore),1);
989 14 : psElement->stype = DGNST_CORE;
990 14 : DGNParseCore( psDGN, psElement );
991 : }
992 : break;
993 : }
994 :
995 : /* -------------------------------------------------------------------- */
996 : /* If the element structure type is "core" or if we are running */
997 : /* in "capture all" mode, record the complete binary image of */
998 : /* the element. */
999 : /* -------------------------------------------------------------------- */
1000 101 : if( psElement->stype == DGNST_CORE
1001 : || (psDGN->options & DGNO_CAPTURE_RAW_DATA) )
1002 : {
1003 68 : psElement->raw_bytes = psDGN->nElemBytes;
1004 68 : psElement->raw_data = (unsigned char *)CPLMalloc(psElement->raw_bytes);
1005 :
1006 68 : memcpy( psElement->raw_data, psDGN->abyElem, psElement->raw_bytes );
1007 : }
1008 :
1009 : /* -------------------------------------------------------------------- */
1010 : /* Collect some additional generic information. */
1011 : /* -------------------------------------------------------------------- */
1012 101 : psElement->element_id = psDGN->next_element_id - 1;
1013 :
1014 101 : psElement->offset = VSIFTell( psDGN->fp ) - psDGN->nElemBytes;
1015 101 : psElement->size = psDGN->nElemBytes;
1016 :
1017 101 : return psElement;
1018 : }
1019 :
1020 : /************************************************************************/
1021 : /* DGNReadElement() */
1022 : /************************************************************************/
1023 :
1024 : /**
1025 : * Read a DGN element.
1026 : *
1027 : * This function will return the next element in the file, starting with the
1028 : * first. It is affected by DGNGotoElement() calls.
1029 : *
1030 : * The element is read into a structure which includes the DGNElemCore
1031 : * structure. It is expected that applications will inspect the stype
1032 : * field of the returned DGNElemCore and use it to cast the pointer to the
1033 : * appropriate element structure type such as DGNElemMultiPoint.
1034 : *
1035 : * @param hDGN the handle of the file to read from.
1036 : *
1037 : * @return pointer to element structure, or NULL on EOF or processing error.
1038 : * The structure should be freed with DGNFreeElement() when no longer needed.
1039 : */
1040 :
1041 105 : DGNElemCore *DGNReadElement( DGNHandle hDGN )
1042 :
1043 : {
1044 105 : DGNInfo *psDGN = (DGNInfo *) hDGN;
1045 105 : DGNElemCore *psElement = NULL;
1046 : int nType, nLevel;
1047 : int bInsideFilter;
1048 :
1049 : /* -------------------------------------------------------------------- */
1050 : /* Load the element data into the current buffer. If a spatial */
1051 : /* filter is in effect, loop until we get something within our */
1052 : /* spatial constraints. */
1053 : /* -------------------------------------------------------------------- */
1054 104 : do {
1055 108 : bInsideFilter = TRUE;
1056 :
1057 108 : if( !DGNLoadRawElement( psDGN, &nType, &nLevel ) )
1058 4 : return NULL;
1059 :
1060 104 : if( psDGN->has_spatial_filter )
1061 : {
1062 : GUInt32 nXMin, nXMax, nYMin, nYMax;
1063 :
1064 15 : if( !psDGN->sf_converted_to_uor )
1065 0 : DGNSpatialFilterToUOR( psDGN );
1066 :
1067 15 : if( !DGNGetRawExtents( psDGN, nType, NULL,
1068 : &nXMin, &nYMin, NULL,
1069 : &nXMax, &nYMax, NULL ) )
1070 : {
1071 : /* If we don't have spatial characterists for the element
1072 : we will pass it through. */
1073 11 : bInsideFilter = TRUE;
1074 : }
1075 4 : else if( nXMin > psDGN->sf_max_x
1076 : || nYMin > psDGN->sf_max_y
1077 : || nXMax < psDGN->sf_min_x
1078 : || nYMax < psDGN->sf_min_y )
1079 3 : bInsideFilter = FALSE;
1080 :
1081 : /*
1082 : ** We want to select complex elements based on the extents of
1083 : ** the header, not the individual elements.
1084 : */
1085 15 : if( nType == DGNT_COMPLEX_CHAIN_HEADER
1086 : || nType == DGNT_COMPLEX_SHAPE_HEADER )
1087 : {
1088 0 : psDGN->in_complex_group = TRUE;
1089 0 : psDGN->select_complex_group = bInsideFilter;
1090 : }
1091 15 : else if( psDGN->abyElem[0] & 0x80 /* complex flag set */ )
1092 : {
1093 0 : if( psDGN->in_complex_group )
1094 0 : bInsideFilter = psDGN->select_complex_group;
1095 : }
1096 : else
1097 15 : psDGN->in_complex_group = FALSE;
1098 : }
1099 : } while( !bInsideFilter );
1100 :
1101 : /* -------------------------------------------------------------------- */
1102 : /* Convert into an element structure. */
1103 : /* -------------------------------------------------------------------- */
1104 101 : psElement = DGNProcessElement( psDGN, nType, nLevel );
1105 :
1106 101 : return psElement;
1107 : }
1108 :
1109 : /************************************************************************/
1110 : /* DGNElemTypeHasDispHdr() */
1111 : /************************************************************************/
1112 :
1113 : /**
1114 : * Does element type have display header.
1115 : *
1116 : * @param nElemType element type (0-63) to test.
1117 : *
1118 : * @return TRUE if elements of passed in type have a display header after the
1119 : * core element header, or FALSE otherwise.
1120 : */
1121 :
1122 119 : int DGNElemTypeHasDispHdr( int nElemType )
1123 :
1124 : {
1125 119 : switch( nElemType )
1126 : {
1127 : case 0:
1128 : case DGNT_TCB:
1129 : case DGNT_CELL_LIBRARY:
1130 : case DGNT_LEVEL_SYMBOLOGY:
1131 : case 32:
1132 : case 44:
1133 : case 48:
1134 : case 49:
1135 : case 50:
1136 : case 51:
1137 : case 57:
1138 : case 60:
1139 : case 61:
1140 : case 62:
1141 : case 63:
1142 26 : return FALSE;
1143 :
1144 : default:
1145 93 : return TRUE;
1146 : }
1147 : }
1148 :
1149 :
1150 : /************************************************************************/
1151 : /* DGNParseCore() */
1152 : /************************************************************************/
1153 :
1154 107 : int DGNParseCore( DGNInfo *psDGN, DGNElemCore *psElement )
1155 :
1156 : {
1157 107 : GByte *psData = psDGN->abyElem+0;
1158 :
1159 107 : psElement->level = psData[0] & 0x3f;
1160 107 : psElement->complex = psData[0] & 0x80;
1161 107 : psElement->deleted = psData[1] & 0x80;
1162 107 : psElement->type = psData[1] & 0x7f;
1163 :
1164 107 : if( psDGN->nElemBytes >= 36 && DGNElemTypeHasDispHdr( psElement->type ) )
1165 : {
1166 81 : psElement->graphic_group = psData[28] + psData[29] * 256;
1167 81 : psElement->properties = psData[32] + psData[33] * 256;
1168 81 : psElement->style = psData[34] & 0x7;
1169 81 : psElement->weight = (psData[34] & 0xf8) >> 3;
1170 81 : psElement->color = psData[35];
1171 : }
1172 : else
1173 : {
1174 26 : psElement->graphic_group = 0;
1175 26 : psElement->properties = 0;
1176 26 : psElement->style = 0;
1177 26 : psElement->weight = 0;
1178 26 : psElement->color = 0;
1179 : }
1180 :
1181 107 : if( psElement->properties & DGNPF_ATTRIBUTES )
1182 : {
1183 : int nAttIndex;
1184 :
1185 5 : nAttIndex = psData[30] + psData[31] * 256;
1186 :
1187 5 : psElement->attr_bytes = psDGN->nElemBytes - nAttIndex*2 - 32;
1188 5 : if( psElement->attr_bytes > 0 )
1189 : {
1190 : psElement->attr_data = (unsigned char *)
1191 5 : CPLMalloc(psElement->attr_bytes);
1192 : memcpy( psElement->attr_data, psData + nAttIndex * 2 + 32,
1193 5 : psElement->attr_bytes );
1194 : }
1195 : else
1196 : {
1197 : CPLError(
1198 : CE_Warning, CPLE_AppDefined,
1199 : "Computed %d bytes for attribute info on element,\n"
1200 : "perhaps this element type doesn't really have a disphdr?",
1201 0 : psElement->attr_bytes );
1202 0 : psElement->attr_bytes = 0;
1203 : }
1204 : }
1205 :
1206 107 : return TRUE;
1207 : }
1208 :
1209 : /************************************************************************/
1210 : /* DGNParseColorTable() */
1211 : /************************************************************************/
1212 :
1213 0 : static DGNElemCore *DGNParseColorTable( DGNInfo * psDGN )
1214 :
1215 : {
1216 : DGNElemCore *psElement;
1217 : DGNElemColorTable *psColorTable;
1218 :
1219 : psColorTable = (DGNElemColorTable *)
1220 0 : CPLCalloc(sizeof(DGNElemColorTable),1);
1221 0 : psElement = (DGNElemCore *) psColorTable;
1222 0 : psElement->stype = DGNST_COLORTABLE;
1223 :
1224 0 : DGNParseCore( psDGN, psElement );
1225 :
1226 : psColorTable->screen_flag =
1227 0 : psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
1228 :
1229 0 : memcpy( psColorTable->color_info[255], psDGN->abyElem+38, 3 );
1230 0 : memcpy( psColorTable->color_info, psDGN->abyElem+41, 765 );
1231 :
1232 : // We used to only install a color table as the default color
1233 : // table if it was the first in the file. But apparently we should
1234 : // really be using the last one. This doesn't necessarily accomplish
1235 : // that either if the elements are being read out of order but it will
1236 : // usually do better at least.
1237 0 : memcpy( psDGN->color_table, psColorTable->color_info, 768 );
1238 0 : psDGN->got_color_table = 1;
1239 :
1240 0 : return psElement;
1241 : }
1242 :
1243 : /************************************************************************/
1244 : /* DGNParseTagSet() */
1245 : /************************************************************************/
1246 :
1247 0 : static DGNElemCore *DGNParseTagSet( DGNInfo * psDGN )
1248 :
1249 : {
1250 : DGNElemCore *psElement;
1251 : DGNElemTagSet *psTagSet;
1252 : int nDataOffset, iTag;
1253 :
1254 0 : psTagSet = (DGNElemTagSet *) CPLCalloc(sizeof(DGNElemTagSet),1);
1255 0 : psElement = (DGNElemCore *) psTagSet;
1256 0 : psElement->stype = DGNST_TAG_SET;
1257 :
1258 0 : DGNParseCore( psDGN, psElement );
1259 :
1260 : /* -------------------------------------------------------------------- */
1261 : /* Parse the overall information. */
1262 : /* -------------------------------------------------------------------- */
1263 : psTagSet->tagCount =
1264 0 : psDGN->abyElem[44] + psDGN->abyElem[45] * 256;
1265 : psTagSet->flags =
1266 0 : psDGN->abyElem[46] + psDGN->abyElem[47] * 256;
1267 0 : psTagSet->tagSetName = CPLStrdup( (const char *) (psDGN->abyElem + 48) );
1268 :
1269 : /* -------------------------------------------------------------------- */
1270 : /* Get the tag set number out of the attributes, if available. */
1271 : /* -------------------------------------------------------------------- */
1272 0 : psTagSet->tagSet = -1;
1273 :
1274 0 : if( psElement->attr_bytes >= 8
1275 0 : && psElement->attr_data[0] == 0x03
1276 0 : && psElement->attr_data[1] == 0x10
1277 0 : && psElement->attr_data[2] == 0x2f
1278 0 : && psElement->attr_data[3] == 0x7d )
1279 0 : psTagSet->tagSet = psElement->attr_data[4]
1280 0 : + psElement->attr_data[5] * 256;
1281 :
1282 : /* -------------------------------------------------------------------- */
1283 : /* Parse each of the tag definitions. */
1284 : /* -------------------------------------------------------------------- */
1285 : psTagSet->tagList = (DGNTagDef *)
1286 0 : CPLMalloc(sizeof(DGNTagDef) * psTagSet->tagCount);
1287 :
1288 0 : nDataOffset = 48 + strlen(psTagSet->tagSetName) + 1 + 1;
1289 :
1290 0 : for( iTag = 0; iTag < psTagSet->tagCount; iTag++ )
1291 : {
1292 0 : DGNTagDef *tagDef = psTagSet->tagList + iTag;
1293 :
1294 : CPLAssert( nDataOffset < psDGN->nElemBytes );
1295 :
1296 : /* collect tag name. */
1297 0 : tagDef->name = CPLStrdup( (char *) psDGN->abyElem + nDataOffset );
1298 0 : nDataOffset += strlen(tagDef->name)+1;
1299 :
1300 : /* Get tag id */
1301 0 : tagDef->id = psDGN->abyElem[nDataOffset]
1302 0 : + psDGN->abyElem[nDataOffset+1] * 256;
1303 0 : nDataOffset += 2;
1304 :
1305 : /* Get User Prompt */
1306 0 : tagDef->prompt = CPLStrdup( (char *) psDGN->abyElem + nDataOffset );
1307 0 : nDataOffset += strlen(tagDef->prompt)+1;
1308 :
1309 :
1310 : /* Get type */
1311 0 : tagDef->type = psDGN->abyElem[nDataOffset]
1312 0 : + psDGN->abyElem[nDataOffset+1] * 256;
1313 0 : nDataOffset += 2;
1314 :
1315 : /* skip five zeros */
1316 0 : nDataOffset += 5;
1317 :
1318 : /* Get the default */
1319 0 : if( tagDef->type == 1 )
1320 : {
1321 : tagDef->defaultValue.string =
1322 0 : CPLStrdup( (char *) psDGN->abyElem + nDataOffset );
1323 0 : nDataOffset += strlen(tagDef->defaultValue.string)+1;
1324 : }
1325 0 : else if( tagDef->type == 3 || tagDef->type == 5 )
1326 : {
1327 : memcpy( &(tagDef->defaultValue.integer),
1328 0 : psDGN->abyElem + nDataOffset, 4 );
1329 : tagDef->defaultValue.integer =
1330 0 : CPL_LSBWORD32( tagDef->defaultValue.integer );
1331 0 : nDataOffset += 4;
1332 : }
1333 0 : else if( tagDef->type == 4 )
1334 : {
1335 : memcpy( &(tagDef->defaultValue.real),
1336 0 : psDGN->abyElem + nDataOffset, 8 );
1337 0 : DGN2IEEEDouble( &(tagDef->defaultValue.real) );
1338 0 : nDataOffset += 8;
1339 : }
1340 : else
1341 0 : nDataOffset += 4;
1342 : }
1343 0 : return psElement;
1344 : }
1345 :
1346 : /************************************************************************/
1347 : /* DGNParseTCB() */
1348 : /************************************************************************/
1349 :
1350 19 : static DGNElemCore *DGNParseTCB( DGNInfo * psDGN )
1351 :
1352 : {
1353 : DGNElemTCB *psTCB;
1354 : DGNElemCore *psElement;
1355 : int iView;
1356 :
1357 19 : psTCB = (DGNElemTCB *) CPLCalloc(sizeof(DGNElemTCB),1);
1358 19 : psElement = (DGNElemCore *) psTCB;
1359 19 : psElement->stype = DGNST_TCB;
1360 19 : DGNParseCore( psDGN, psElement );
1361 :
1362 19 : if( psDGN->abyElem[1214] & 0x40 )
1363 0 : psTCB->dimension = 3;
1364 : else
1365 19 : psTCB->dimension = 2;
1366 :
1367 19 : psTCB->subunits_per_master = DGN_INT32( psDGN->abyElem + 1112 );
1368 :
1369 19 : psTCB->master_units[0] = (char) psDGN->abyElem[1120];
1370 19 : psTCB->master_units[1] = (char) psDGN->abyElem[1121];
1371 19 : psTCB->master_units[2] = '\0';
1372 :
1373 19 : psTCB->uor_per_subunit = DGN_INT32( psDGN->abyElem + 1116 );
1374 :
1375 19 : psTCB->sub_units[0] = (char) psDGN->abyElem[1122];
1376 19 : psTCB->sub_units[1] = (char) psDGN->abyElem[1123];
1377 19 : psTCB->sub_units[2] = '\0';
1378 :
1379 : /* Get global origin */
1380 19 : memcpy( &(psTCB->origin_x), psDGN->abyElem+1240, 8 );
1381 19 : memcpy( &(psTCB->origin_y), psDGN->abyElem+1248, 8 );
1382 19 : memcpy( &(psTCB->origin_z), psDGN->abyElem+1256, 8 );
1383 :
1384 : /* Transform to IEEE */
1385 19 : DGN2IEEEDouble( &(psTCB->origin_x) );
1386 19 : DGN2IEEEDouble( &(psTCB->origin_y) );
1387 19 : DGN2IEEEDouble( &(psTCB->origin_z) );
1388 :
1389 : /* Convert from UORs to master units. */
1390 19 : if( psTCB->uor_per_subunit != 0
1391 : && psTCB->subunits_per_master != 0 )
1392 : {
1393 : psTCB->origin_x = psTCB->origin_x /
1394 12 : (psTCB->uor_per_subunit * psTCB->subunits_per_master);
1395 : psTCB->origin_y = psTCB->origin_y /
1396 12 : (psTCB->uor_per_subunit * psTCB->subunits_per_master);
1397 : psTCB->origin_z = psTCB->origin_z /
1398 12 : (psTCB->uor_per_subunit * psTCB->subunits_per_master);
1399 : }
1400 :
1401 19 : if( !psDGN->got_tcb )
1402 : {
1403 5 : psDGN->got_tcb = TRUE;
1404 5 : psDGN->dimension = psTCB->dimension;
1405 5 : psDGN->origin_x = psTCB->origin_x;
1406 5 : psDGN->origin_y = psTCB->origin_y;
1407 5 : psDGN->origin_z = psTCB->origin_z;
1408 :
1409 5 : if( psTCB->uor_per_subunit != 0
1410 : && psTCB->subunits_per_master != 0 )
1411 : psDGN->scale = 1.0
1412 5 : / (psTCB->uor_per_subunit * psTCB->subunits_per_master);
1413 : }
1414 :
1415 : /* Collect views */
1416 171 : for( iView = 0; iView < 8; iView++ )
1417 : {
1418 152 : unsigned char *pabyRawView = psDGN->abyElem + 46 + iView*118;
1419 152 : DGNViewInfo *psView = psTCB->views + iView;
1420 : int i;
1421 :
1422 152 : psView->flags = pabyRawView[0] + pabyRawView[1] * 256;
1423 152 : memcpy( psView->levels, pabyRawView + 2, 8 );
1424 :
1425 152 : psView->origin.x = DGN_INT32( pabyRawView + 10 );
1426 152 : psView->origin.y = DGN_INT32( pabyRawView + 14 );
1427 152 : psView->origin.z = DGN_INT32( pabyRawView + 18 );
1428 :
1429 152 : DGNTransformPoint( psDGN, &(psView->origin) );
1430 :
1431 152 : psView->delta.x = DGN_INT32( pabyRawView + 22 );
1432 152 : psView->delta.y = DGN_INT32( pabyRawView + 26 );
1433 152 : psView->delta.z = DGN_INT32( pabyRawView + 30 );
1434 :
1435 152 : psView->delta.x *= psDGN->scale;
1436 152 : psView->delta.y *= psDGN->scale;
1437 152 : psView->delta.z *= psDGN->scale;
1438 :
1439 152 : memcpy( psView->transmatrx, pabyRawView + 34, sizeof(double) * 9 );
1440 1520 : for( i = 0; i < 9; i++ )
1441 1368 : DGN2IEEEDouble( psView->transmatrx + i );
1442 :
1443 152 : memcpy( &(psView->conversion), pabyRawView + 106, sizeof(double) );
1444 152 : DGN2IEEEDouble( &(psView->conversion) );
1445 :
1446 152 : psView->activez = DGN_INT32( pabyRawView + 114 );
1447 : }
1448 :
1449 19 : return psElement;
1450 : }
1451 :
1452 : /************************************************************************/
1453 : /* DGNFreeElement() */
1454 : /************************************************************************/
1455 :
1456 : /**
1457 : * Free an element structure.
1458 : *
1459 : * This function will deallocate all resources associated with any element
1460 : * structure returned by DGNReadElement().
1461 : *
1462 : * @param hDGN handle to file from which the element was read.
1463 : * @param psElement the element structure returned by DGNReadElement().
1464 : */
1465 :
1466 124 : void DGNFreeElement( DGNHandle hDGN, DGNElemCore *psElement )
1467 :
1468 : {
1469 124 : if( psElement->attr_data != NULL )
1470 6 : VSIFree( psElement->attr_data );
1471 :
1472 124 : if( psElement->raw_data != NULL )
1473 85 : VSIFree( psElement->raw_data );
1474 :
1475 124 : if( psElement->stype == DGNST_TAG_SET )
1476 : {
1477 : int iTag;
1478 :
1479 0 : DGNElemTagSet *psTagSet = (DGNElemTagSet *) psElement;
1480 0 : CPLFree( psTagSet->tagSetName );
1481 :
1482 0 : for( iTag = 0; iTag < psTagSet->tagCount; iTag++ )
1483 : {
1484 0 : CPLFree( psTagSet->tagList[iTag].name );
1485 0 : CPLFree( psTagSet->tagList[iTag].prompt );
1486 :
1487 0 : if( psTagSet->tagList[iTag].type == 1 )
1488 0 : CPLFree( psTagSet->tagList[iTag].defaultValue.string );
1489 : }
1490 0 : CPLFree( psTagSet->tagList );
1491 : }
1492 124 : else if( psElement->stype == DGNST_TAG_VALUE )
1493 : {
1494 0 : if( ((DGNElemTagValue *) psElement)->tagType == 1 )
1495 0 : CPLFree( ((DGNElemTagValue *) psElement)->tagValue.string );
1496 : }
1497 :
1498 124 : CPLFree( psElement );
1499 124 : }
1500 :
1501 : /************************************************************************/
1502 : /* DGNRewind() */
1503 : /************************************************************************/
1504 :
1505 : /**
1506 : * Rewind element reading.
1507 : *
1508 : * Rewind the indicated DGN file, so the next element read with
1509 : * DGNReadElement() will be the first. Does not require indexing like
1510 : * the more general DGNReadElement() function.
1511 : *
1512 : * @param hDGN handle to file.
1513 : */
1514 :
1515 17 : void DGNRewind( DGNHandle hDGN )
1516 :
1517 : {
1518 17 : DGNInfo *psDGN = (DGNInfo *) hDGN;
1519 :
1520 17 : VSIRewind( psDGN->fp );
1521 :
1522 17 : psDGN->next_element_id = 0;
1523 17 : psDGN->in_complex_group = FALSE;
1524 17 : }
1525 :
1526 : /************************************************************************/
1527 : /* DGNTransformPoint() */
1528 : /************************************************************************/
1529 :
1530 271 : void DGNTransformPoint( DGNInfo *psDGN, DGNPoint *psPoint )
1531 :
1532 : {
1533 271 : psPoint->x = psPoint->x * psDGN->scale - psDGN->origin_x;
1534 271 : psPoint->y = psPoint->y * psDGN->scale - psDGN->origin_y;
1535 271 : psPoint->z = psPoint->z * psDGN->scale - psDGN->origin_z;
1536 271 : }
1537 :
1538 : /************************************************************************/
1539 : /* DGNInverseTransformPoint() */
1540 : /************************************************************************/
1541 :
1542 2 : void DGNInverseTransformPoint( DGNInfo *psDGN, DGNPoint *psPoint )
1543 :
1544 : {
1545 2 : psPoint->x = (psPoint->x + psDGN->origin_x) / psDGN->scale;
1546 2 : psPoint->y = (psPoint->y + psDGN->origin_y) / psDGN->scale;
1547 2 : psPoint->z = (psPoint->z + psDGN->origin_z) / psDGN->scale;
1548 :
1549 2 : psPoint->x = MAX(-2147483647,MIN(2147483647,psPoint->x));
1550 2 : psPoint->y = MAX(-2147483647,MIN(2147483647,psPoint->y));
1551 2 : psPoint->z = MAX(-2147483647,MIN(2147483647,psPoint->z));
1552 2 : }
1553 :
1554 : /************************************************************************/
1555 : /* DGNInverseTransformPointToInt() */
1556 : /************************************************************************/
1557 :
1558 94 : void DGNInverseTransformPointToInt( DGNInfo *psDGN, DGNPoint *psPoint,
1559 : unsigned char *pabyTarget )
1560 :
1561 : {
1562 : double adfCT[3];
1563 : int i;
1564 :
1565 94 : adfCT[0] = (psPoint->x + psDGN->origin_x) / psDGN->scale;
1566 94 : adfCT[1] = (psPoint->y + psDGN->origin_y) / psDGN->scale;
1567 94 : adfCT[2] = (psPoint->z + psDGN->origin_z) / psDGN->scale;
1568 :
1569 282 : for( i = 0; i < psDGN->dimension; i++ )
1570 : {
1571 : GInt32 nCTI;
1572 188 : unsigned char *pabyCTI = (unsigned char *) &nCTI;
1573 :
1574 188 : nCTI = (GInt32) MAX(-2147483647,MIN(2147483647,adfCT[i]));
1575 :
1576 : #ifdef WORDS_BIGENDIAN
1577 : pabyTarget[i*4+0] = pabyCTI[1];
1578 : pabyTarget[i*4+1] = pabyCTI[0];
1579 : pabyTarget[i*4+2] = pabyCTI[3];
1580 : pabyTarget[i*4+3] = pabyCTI[2];
1581 : #else
1582 188 : pabyTarget[i*4+3] = pabyCTI[1];
1583 188 : pabyTarget[i*4+2] = pabyCTI[0];
1584 188 : pabyTarget[i*4+1] = pabyCTI[3];
1585 188 : pabyTarget[i*4+0] = pabyCTI[2];
1586 : #endif
1587 : }
1588 94 : }
1589 :
1590 : /************************************************************************/
1591 : /* DGNLoadTCB() */
1592 : /************************************************************************/
1593 :
1594 : /**
1595 : * Load TCB if not already loaded.
1596 : *
1597 : * This function will load the TCB element if it is not already loaded.
1598 : * It is used primarily to ensure the TCB is loaded before doing any operations
1599 : * that require TCB values (like creating new elements).
1600 : *
1601 : * @return FALSE on failure or TRUE on success.
1602 : */
1603 :
1604 18 : int DGNLoadTCB( DGNHandle hDGN )
1605 :
1606 : {
1607 18 : DGNInfo *psDGN = (DGNInfo *) hDGN;
1608 :
1609 18 : if( psDGN->got_tcb )
1610 17 : return TRUE;
1611 :
1612 3 : while( !psDGN->got_tcb )
1613 : {
1614 1 : DGNElemCore *psElem = DGNReadElement( hDGN );
1615 1 : if( psElem == NULL )
1616 : {
1617 : CPLError( CE_Failure, CPLE_AppDefined,
1618 0 : "DGNLoadTCB() - unable to find TCB in file." );
1619 0 : return FALSE;
1620 : }
1621 1 : DGNFreeElement( hDGN, psElem );
1622 : }
1623 :
1624 1 : return TRUE;
1625 : }
1626 :
1627 : /************************************************************************/
1628 : /* DGNGetElementIndex() */
1629 : /************************************************************************/
1630 :
1631 : /**
1632 : * Fetch element index.
1633 : *
1634 : * This function will return an array with brief information about every
1635 : * element in a DGN file. It requires one pass through the entire file to
1636 : * generate (this is not repeated on subsequent calls).
1637 : *
1638 : * The returned array of DGNElementInfo structures contain the level, type,
1639 : * stype, and other flags for each element in the file. This can facilitate
1640 : * application level code representing the number of elements of various types
1641 : * effeciently.
1642 : *
1643 : * Note that while building the index requires one pass through the whole file,
1644 : * it does not generally request much processing for each element.
1645 : *
1646 : * @param hDGN the file to get an index for.
1647 : * @param pnElementCount the integer to put the total element count into.
1648 : *
1649 : * @return a pointer to an internal array of DGNElementInfo structures (there
1650 : * will be *pnElementCount entries in the array), or NULL on failure. The
1651 : * returned array should not be modified or freed, and will last only as long
1652 : * as the DGN file remains open.
1653 : */
1654 :
1655 16 : const DGNElementInfo *DGNGetElementIndex( DGNHandle hDGN, int *pnElementCount )
1656 :
1657 : {
1658 16 : DGNInfo *psDGN = (DGNInfo *) hDGN;
1659 :
1660 16 : DGNBuildIndex( psDGN );
1661 :
1662 16 : if( pnElementCount != NULL )
1663 0 : *pnElementCount = psDGN->element_count;
1664 :
1665 16 : return psDGN->element_index;
1666 : }
1667 :
1668 : /************************************************************************/
1669 : /* DGNGetExtents() */
1670 : /************************************************************************/
1671 :
1672 : /**
1673 : * Fetch overall file extents.
1674 : *
1675 : * The extents are collected for each element while building an index, so
1676 : * if an index has not already been built, it will be built when
1677 : * DGNGetExtents() is called.
1678 : *
1679 : * The Z min/max values are generally meaningless (0 and 0xffffffff in uor
1680 : * space).
1681 : *
1682 : * @param hDGN the file to get extents for.
1683 : * @param padfExtents pointer to an array of six doubles into which are loaded
1684 : * the values xmin, ymin, zmin, xmax, ymax, and zmax.
1685 : *
1686 : * @return TRUE on success or FALSE on failure.
1687 : */
1688 :
1689 0 : int DGNGetExtents( DGNHandle hDGN, double * padfExtents )
1690 :
1691 : {
1692 0 : DGNInfo *psDGN = (DGNInfo *) hDGN;
1693 : DGNPoint sMin, sMax;
1694 :
1695 0 : DGNBuildIndex( psDGN );
1696 :
1697 0 : if( !psDGN->got_bounds )
1698 0 : return FALSE;
1699 :
1700 0 : sMin.x = psDGN->min_x - 2147483648.0;
1701 0 : sMin.y = psDGN->min_y - 2147483648.0;
1702 0 : sMin.z = psDGN->min_z - 2147483648.0;
1703 :
1704 0 : DGNTransformPoint( psDGN, &sMin );
1705 :
1706 0 : padfExtents[0] = sMin.x;
1707 0 : padfExtents[1] = sMin.y;
1708 0 : padfExtents[2] = sMin.z;
1709 :
1710 0 : sMax.x = psDGN->max_x - 2147483648.0;
1711 0 : sMax.y = psDGN->max_y - 2147483648.0;
1712 0 : sMax.z = psDGN->max_z - 2147483648.0;
1713 :
1714 0 : DGNTransformPoint( psDGN, &sMax );
1715 :
1716 0 : padfExtents[3] = sMax.x;
1717 0 : padfExtents[4] = sMax.y;
1718 0 : padfExtents[5] = sMax.z;
1719 :
1720 0 : return TRUE;
1721 : }
1722 :
1723 : /************************************************************************/
1724 : /* DGNBuildIndex() */
1725 : /************************************************************************/
1726 :
1727 34 : void DGNBuildIndex( DGNInfo *psDGN )
1728 :
1729 : {
1730 : int nMaxElements, nType, nLevel;
1731 : long nLastOffset;
1732 : GUInt32 anRegion[6];
1733 :
1734 34 : if( psDGN->index_built )
1735 30 : return;
1736 :
1737 4 : psDGN->index_built = TRUE;
1738 :
1739 4 : DGNRewind( psDGN );
1740 :
1741 4 : nMaxElements = 0;
1742 :
1743 4 : nLastOffset = VSIFTell( psDGN->fp );
1744 57 : while( DGNLoadRawElement( psDGN, &nType, &nLevel ) )
1745 : {
1746 : DGNElementInfo *psEI;
1747 :
1748 49 : if( psDGN->element_count == nMaxElements )
1749 : {
1750 4 : nMaxElements = (int) (nMaxElements * 1.5) + 500;
1751 :
1752 : psDGN->element_index = (DGNElementInfo *)
1753 : CPLRealloc( psDGN->element_index,
1754 4 : nMaxElements * sizeof(DGNElementInfo) );
1755 : }
1756 :
1757 49 : psEI = psDGN->element_index + psDGN->element_count;
1758 49 : psEI->level = (unsigned char) nLevel;
1759 49 : psEI->type = (unsigned char) nType;
1760 49 : psEI->flags = 0;
1761 49 : psEI->offset = (long) nLastOffset;
1762 :
1763 49 : if( psDGN->abyElem[0] & 0x80 )
1764 3 : psEI->flags |= DGNEIF_COMPLEX;
1765 :
1766 49 : if( psDGN->abyElem[1] & 0x80 )
1767 0 : psEI->flags |= DGNEIF_DELETED;
1768 :
1769 57 : if( nType == DGNT_LINE || nType == DGNT_LINE_STRING
1770 : || nType == DGNT_SHAPE || nType == DGNT_CURVE
1771 : || nType == DGNT_BSPLINE_POLE )
1772 8 : psEI->stype = DGNST_MULTIPOINT;
1773 :
1774 41 : else if( nType == DGNT_GROUP_DATA && nLevel == DGN_GDL_COLOR_TABLE )
1775 : {
1776 0 : DGNElemCore *psCT = DGNParseColorTable( psDGN );
1777 0 : DGNFreeElement( (DGNHandle) psDGN, psCT );
1778 0 : psEI->stype = DGNST_COLORTABLE;
1779 : }
1780 43 : else if( nType == DGNT_ELLIPSE || nType == DGNT_ARC )
1781 2 : psEI->stype = DGNST_ARC;
1782 :
1783 40 : else if( nType == DGNT_COMPLEX_SHAPE_HEADER
1784 : || nType == DGNT_COMPLEX_CHAIN_HEADER
1785 : || nType == DGNT_3DSURFACE_HEADER
1786 : || nType == DGNT_3DSOLID_HEADER)
1787 1 : psEI->stype = DGNST_COMPLEX_HEADER;
1788 :
1789 38 : else if( nType == DGNT_TEXT )
1790 3 : psEI->stype = DGNST_TEXT;
1791 :
1792 35 : else if( nType == DGNT_TAG_VALUE )
1793 0 : psEI->stype = DGNST_TAG_VALUE;
1794 :
1795 35 : else if( nType == DGNT_APPLICATION_ELEM )
1796 : {
1797 21 : if( nLevel == 24 )
1798 0 : psEI->stype = DGNST_TAG_SET;
1799 : else
1800 21 : psEI->stype = DGNST_CORE;
1801 : }
1802 14 : else if( nType == DGNT_TCB )
1803 : {
1804 6 : DGNElemCore *psTCB = DGNParseTCB( psDGN );
1805 6 : DGNFreeElement( (DGNHandle) psDGN, psTCB );
1806 6 : psEI->stype = DGNST_TCB;
1807 : }
1808 8 : else if( nType == DGNT_CONE )
1809 0 : psEI->stype = DGNST_CONE;
1810 : else
1811 8 : psEI->stype = DGNST_CORE;
1812 :
1813 49 : if( !(psEI->flags & DGNEIF_DELETED)
1814 : && !(psEI->flags & DGNEIF_COMPLEX)
1815 : && DGNGetRawExtents( psDGN, nType, NULL,
1816 : anRegion+0, anRegion+1, anRegion+2,
1817 : anRegion+3, anRegion+4, anRegion+5 ) )
1818 : {
1819 : #ifdef notdef
1820 : printf( "panRegion[%d]=%.1f,%.1f,%.1f,%.1f,%.1f,%.1f\n",
1821 : psDGN->element_count,
1822 : anRegion[0] - 2147483648.0,
1823 : anRegion[1] - 2147483648.0,
1824 : anRegion[2] - 2147483648.0,
1825 : anRegion[3] - 2147483648.0,
1826 : anRegion[4] - 2147483648.0,
1827 : anRegion[5] - 2147483648.0 );
1828 : #endif
1829 11 : if( psDGN->got_bounds )
1830 : {
1831 8 : psDGN->min_x = MIN(psDGN->min_x, anRegion[0]);
1832 8 : psDGN->min_y = MIN(psDGN->min_y, anRegion[1]);
1833 8 : psDGN->min_z = MIN(psDGN->min_z, anRegion[2]);
1834 8 : psDGN->max_x = MAX(psDGN->max_x, anRegion[3]);
1835 8 : psDGN->max_y = MAX(psDGN->max_y, anRegion[4]);
1836 8 : psDGN->max_z = MAX(psDGN->max_z, anRegion[5]);
1837 : }
1838 : else
1839 : {
1840 3 : memcpy( &(psDGN->min_x), anRegion, sizeof(GInt32) * 6 );
1841 3 : psDGN->got_bounds = TRUE;
1842 : }
1843 : }
1844 :
1845 49 : psDGN->element_count++;
1846 :
1847 49 : nLastOffset = VSIFTell( psDGN->fp );
1848 : }
1849 :
1850 4 : DGNRewind( psDGN );
1851 :
1852 4 : psDGN->max_element_count = nMaxElements;
1853 : }
1854 :
|