1 : /******************************************************************************
2 : * $Id: dgnhelp.cpp 15591 2008-10-24 19:43:56Z warmerdam $
3 : *
4 : * Project: Microstation DGN Access Library
5 : * Purpose: Application visible helper functions for parsing DGN information.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2002, 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: dgnhelp.cpp 15591 2008-10-24 19:43:56Z warmerdam $");
33 :
34 : static unsigned char abyDefaultPCT[256][3] =
35 : {
36 : {255,255,255},
37 : {0,0,255},
38 : {0,255,0},
39 : {255,0,0},
40 : {255,255,0},
41 : {255,0,255},
42 : {255,127,0},
43 : {0,255,255},
44 : {64,64,64},
45 : {192,192,192},
46 : {254,0,96},
47 : {160,224,0},
48 : {0,254,160},
49 : {128,0,160},
50 : {176,176,176},
51 : {0,240,240},
52 : {240,240,240},
53 : {0,0,240},
54 : {0,240,0},
55 : {240,0,0},
56 : {240,240,0},
57 : {240,0,240},
58 : {240,122,0},
59 : {0,240,240},
60 : {240,240,240},
61 : {0,0,240},
62 : {0,240,0},
63 : {240,0,0},
64 : {240,240,0},
65 : {240,0,240},
66 : {240,122,0},
67 : {0,225,225},
68 : {225,225,225},
69 : {0,0,225},
70 : {0,225,0},
71 : {225,0,0},
72 : {225,225,0},
73 : {225,0,225},
74 : {225,117,0},
75 : {0,225,225},
76 : {225,225,225},
77 : {0,0,225},
78 : {0,225,0},
79 : {225,0,0},
80 : {225,225,0},
81 : {225,0,225},
82 : {225,117,0},
83 : {0,210,210},
84 : {210,210,210},
85 : {0,0,210},
86 : {0,210,0},
87 : {210,0,0},
88 : {210,210,0},
89 : {210,0,210},
90 : {210,112,0},
91 : {0,210,210},
92 : {210,210,210},
93 : {0,0,210},
94 : {0,210,0},
95 : {210,0,0},
96 : {210,210,0},
97 : {210,0,210},
98 : {210,112,0},
99 : {0,195,195},
100 : {195,195,195},
101 : {0,0,195},
102 : {0,195,0},
103 : {195,0,0},
104 : {195,195,0},
105 : {195,0,195},
106 : {195,107,0},
107 : {0,195,195},
108 : {195,195,195},
109 : {0,0,195},
110 : {0,195,0},
111 : {195,0,0},
112 : {195,195,0},
113 : {195,0,195},
114 : {195,107,0},
115 : {0,180,180},
116 : {180,180,180},
117 : {0,0,180},
118 : {0,180,0},
119 : {180,0,0},
120 : {180,180,0},
121 : {180,0,180},
122 : {180,102,0},
123 : {0,180,180},
124 : {180,180,180},
125 : {0,0,180},
126 : {0,180,0},
127 : {180,0,0},
128 : {180,180,0},
129 : {180,0,180},
130 : {180,102,0},
131 : {0,165,165},
132 : {165,165,165},
133 : {0,0,165},
134 : {0,165,0},
135 : {165,0,0},
136 : {165,165,0},
137 : {165,0,165},
138 : {165,97,0},
139 : {0,165,165},
140 : {165,165,165},
141 : {0,0,165},
142 : {0,165,0},
143 : {165,0,0},
144 : {165,165,0},
145 : {165,0,165},
146 : {165,97,0},
147 : {0,150,150},
148 : {150,150,150},
149 : {0,0,150},
150 : {0,150,0},
151 : {150,0,0},
152 : {150,150,0},
153 : {150,0,150},
154 : {150,92,0},
155 : {0,150,150},
156 : {150,150,150},
157 : {0,0,150},
158 : {0,150,0},
159 : {150,0,0},
160 : {150,150,0},
161 : {150,0,150},
162 : {150,92,0},
163 : {0,135,135},
164 : {135,135,135},
165 : {0,0,135},
166 : {0,135,0},
167 : {135,0,0},
168 : {135,135,0},
169 : {135,0,135},
170 : {135,87,0},
171 : {0,135,135},
172 : {135,135,135},
173 : {0,0,135},
174 : {0,135,0},
175 : {135,0,0},
176 : {135,135,0},
177 : {135,0,135},
178 : {135,87,0},
179 : {0,120,120},
180 : {120,120,120},
181 : {0,0,120},
182 : {0,120,0},
183 : {120,0,0},
184 : {120,120,0},
185 : {120,0,120},
186 : {120,82,0},
187 : {0,120,120},
188 : {120,120,120},
189 : {0,0,120},
190 : {0,120,0},
191 : {120,0,0},
192 : {120,120,0},
193 : {120,0,120},
194 : {120,82,0},
195 : {0,105,105},
196 : {105,105,105},
197 : {0,0,105},
198 : {0,105,0},
199 : {105,0,0},
200 : {105,105,0},
201 : {105,0,105},
202 : {105,77,0},
203 : {0,105,105},
204 : {105,105,105},
205 : {0,0,105},
206 : {0,105,0},
207 : {105,0,0},
208 : {105,105,0},
209 : {105,0,105},
210 : {105,77,0},
211 : {0,90,90},
212 : {90,90,90},
213 : {0,0,90},
214 : {0,90,0},
215 : {90,0,0},
216 : {90,90,0},
217 : {90,0,90},
218 : {90,72,0},
219 : {0,90,90},
220 : {90,90,90},
221 : {0,0,90},
222 : {0,90,0},
223 : {90,0,0},
224 : {90,90,0},
225 : {90,0,90},
226 : {90,72,0},
227 : {0,75,75},
228 : {75,75,75},
229 : {0,0,75},
230 : {0,75,0},
231 : {75,0,0},
232 : {75,75,0},
233 : {75,0,75},
234 : {75,67,0},
235 : {0,75,75},
236 : {75,75,75},
237 : {0,0,75},
238 : {0,75,0},
239 : {75,0,0},
240 : {75,75,0},
241 : {75,0,75},
242 : {75,67,0},
243 : {0,60,60},
244 : {60,60,60},
245 : {0,0,60},
246 : {0,60,0},
247 : {60,0,0},
248 : {60,60,0},
249 : {60,0,60},
250 : {60,62,0},
251 : {0,60,60},
252 : {60,60,60},
253 : {0,0,60},
254 : {0,60,0},
255 : {60,0,0},
256 : {60,60,0},
257 : {60,0,60},
258 : {60,62,0},
259 : {0,45,45},
260 : {45,45,45},
261 : {0,0,45},
262 : {0,45,0},
263 : {45,0,0},
264 : {45,45,0},
265 : {45,0,45},
266 : {45,57,0},
267 : {0,45,45},
268 : {45,45,45},
269 : {0,0,45},
270 : {0,45,0},
271 : {45,0,0},
272 : {45,45,0},
273 : {45,0,45},
274 : {45,57,0},
275 : {0,30,30},
276 : {30,30,30},
277 : {0,0,30},
278 : {0,30,0},
279 : {30,0,0},
280 : {30,30,0},
281 : {30,0,30},
282 : {30,52,0},
283 : {0,30,30},
284 : {30,30,30},
285 : {0,0,30},
286 : {0,30,0},
287 : {30,0,0},
288 : {30,30,0},
289 : {30,0,30},
290 : {192,192,192},
291 : {28,0,100}
292 : };
293 :
294 :
295 : /************************************************************************/
296 : /* DGNLookupColor() */
297 : /************************************************************************/
298 :
299 : /**
300 : * Translate color index into RGB values.
301 : *
302 : * If no color table has yet been encountered in the file a hard-coded
303 : * "default" color table will be used. This seems to be what Microstation
304 : * uses as a color table when there isn't one in a DGN file but I am not
305 : * absolutely convinced it is appropriate.
306 : *
307 : * @param hDGN the file.
308 : * @param color_index the color index to lookup.
309 : * @param red location to put red component.
310 : * @param green location to put green component.
311 : * @param blue location to put blue component.
312 : *
313 : * @return TRUE on success or FALSE on failure. May fail if color_index is
314 : * out of range.
315 : */
316 :
317 92 : int DGNLookupColor( DGNHandle hDGN, int color_index,
318 : int * red, int * green, int * blue )
319 :
320 : {
321 92 : DGNInfo *psDGN = (DGNInfo *) hDGN;
322 :
323 92 : if( color_index < 0 || color_index > 255 )
324 0 : return FALSE;
325 :
326 92 : if( !psDGN->got_color_table )
327 : {
328 92 : *red = abyDefaultPCT[color_index][0];
329 92 : *green = abyDefaultPCT[color_index][1];
330 92 : *blue = abyDefaultPCT[color_index][2];
331 : }
332 : else
333 : {
334 0 : *red = psDGN->color_table[color_index][0];
335 0 : *green = psDGN->color_table[color_index][1];
336 0 : *blue = psDGN->color_table[color_index][2];
337 : }
338 :
339 92 : return TRUE;
340 : }
341 :
342 : /************************************************************************/
343 : /* DGNGetShapeFillInfo() */
344 : /************************************************************************/
345 :
346 : /**
347 : * Fetch fill color for a shape.
348 : *
349 : * This method will check for a 0x0041 user attribute linkaged with fill
350 : * color information for the element. If found the function returns TRUE,
351 : * and places the fill color in *pnColor, otherwise FALSE is returned and
352 : * *pnColor is not updated.
353 : *
354 : * @param hDGN the file.
355 : * @param psElem the element.
356 : * @param pnColor the location to return the fill color.
357 : *
358 : * @return TRUE on success or FALSE on failure.
359 : */
360 :
361 6 : int DGNGetShapeFillInfo( DGNHandle hDGN, DGNElemCore *psElem, int *pnColor )
362 :
363 : {
364 : int iLink;
365 :
366 7 : for( iLink = 0; TRUE; iLink++ )
367 : {
368 : int nLinkType, nLinkSize;
369 : unsigned char *pabyData;
370 :
371 : pabyData = DGNGetLinkage( hDGN, psElem, iLink, &nLinkType,
372 7 : NULL, NULL, &nLinkSize );
373 7 : if( pabyData == NULL )
374 2 : return FALSE;
375 :
376 5 : if( nLinkType == DGNLT_SHAPE_FILL && nLinkSize >= 7 )
377 : {
378 4 : *pnColor = pabyData[8];
379 4 : return TRUE;
380 : }
381 : }
382 : }
383 :
384 : /************************************************************************/
385 : /* DGNGetAssocID() */
386 : /************************************************************************/
387 :
388 : /**
389 : * Fetch association id for an element.
390 : *
391 : * This method will check if an element has an association id, and if so
392 : * returns it, otherwise returning -1. Association ids are kept as a
393 : * user attribute linkage where present.
394 : *
395 : * @param hDGN the file.
396 : * @param psElem the element.
397 : *
398 : * @return The id or -1 on failure.
399 : */
400 :
401 0 : int DGNGetAssocID( DGNHandle hDGN, DGNElemCore *psElem )
402 :
403 : {
404 : int iLink;
405 :
406 0 : for( iLink = 0; TRUE; iLink++ )
407 : {
408 : int nLinkType, nLinkSize;
409 : unsigned char *pabyData;
410 :
411 : pabyData = DGNGetLinkage( hDGN, psElem, iLink, &nLinkType,
412 0 : NULL, NULL, &nLinkSize );
413 0 : if( pabyData == NULL )
414 0 : return -1;
415 :
416 0 : if( nLinkType == DGNLT_ASSOC_ID && nLinkSize >= 8 )
417 : {
418 0 : return pabyData[4]
419 0 : + pabyData[5] * 256
420 0 : + pabyData[6]*256*256
421 0 : + pabyData[7] * 256*256*256;
422 : }
423 : }
424 : }
425 :
426 : /************************************************************************/
427 : /* DGNRad50ToAscii() */
428 : /* */
429 : /* Convert one 16-bits Radix-50 to ASCII (3 chars). */
430 : /************************************************************************/
431 :
432 0 : void DGNRad50ToAscii(unsigned short sRad50, char *str )
433 : {
434 : unsigned short sValue;
435 0 : char ch = '\0';
436 0 : unsigned short saQuots[3] = {1600,40,1};
437 : int i;
438 :
439 0 : for ( i=0; i<3; i++)
440 : {
441 0 : sValue = sRad50;
442 0 : sValue /= saQuots[i];
443 : /* Map 0..39 to ASCII */
444 0 : if (sValue==0)
445 0 : ch = ' '; /* space */
446 0 : else if (sValue >= 1 && sValue <= 26)
447 0 : ch = (char) (sValue-1+'A');/* printable alpha A..Z */
448 0 : else if (sValue == 27)
449 0 : ch = '$'; /* dollar */
450 0 : else if (sValue == 28)
451 0 : ch = '.'; /* period */
452 0 : else if (sValue == 29)
453 0 : ch = ' '; /* unused char, emit a space instead */
454 0 : else if (sValue >= 30 && sValue <= 39)
455 0 : ch = (char) (sValue-30+'0'); /* digit 0..9 */
456 0 : *str = ch;
457 0 : str++;
458 :
459 0 : sRad50-=(sValue*saQuots[i]);
460 : }
461 :
462 : /* Do zero-terminate */
463 0 : *str = '\0';
464 0 : }
465 :
466 : /************************************************************************/
467 : /* DGNAsciiToRad50() */
468 : /************************************************************************/
469 :
470 0 : void DGNAsciiToRad50( const char *str, unsigned short *pRad50 )
471 :
472 : {
473 0 : unsigned short rad50 = 0;
474 : int i;
475 :
476 0 : for( i = 0; i < 3; i++ )
477 : {
478 : unsigned short value;
479 :
480 0 : if( i >= (int) strlen(str) )
481 : {
482 0 : rad50 = rad50 * 40;
483 0 : continue;
484 : }
485 :
486 0 : if( str[i] == '$' )
487 0 : value = 27;
488 0 : else if( str[i] == '.' )
489 0 : value = 28;
490 0 : else if( str[i] == ' ' )
491 0 : value = 29;
492 0 : else if( str[i] >= '0' && str[i] <= '9' )
493 0 : value = str[i] - '0' + 30;
494 0 : else if( str[i] >= 'a' && str[i] <= 'z' )
495 0 : value = str[i] - 'a' + 1;
496 0 : else if( str[i] >= 'A' && str[i] <= 'Z' )
497 0 : value = str[i] - 'A' + 1;
498 : else
499 0 : value = 0;
500 :
501 0 : rad50 = rad50 * 40 + value;
502 : }
503 :
504 0 : *pRad50 = rad50;
505 0 : }
506 :
507 :
508 : /************************************************************************/
509 : /* DGNGetLineStyleName() */
510 : /* */
511 : /* Read the line style name from symbol table. */
512 : /* The got name is stored in psLine. */
513 : /************************************************************************/
514 :
515 0 : int DGNGetLineStyleName(DGNInfo *psDGN, DGNElemMultiPoint *psLine,
516 : char szLineStyle[65] )
517 : {
518 0 : if (psLine->core.attr_bytes > 0 &&
519 0 : psLine->core.attr_data[1] == 0x10 &&
520 0 : psLine->core.attr_data[2] == 0xf9 &&
521 0 : psLine->core.attr_data[3] == 0x79)
522 : {
523 : #ifdef notdef
524 : for (int i=0;i<SYMBOL_TABLE_SIZE;i++)
525 : {
526 : if (*((unsigned char*)psDGN->buffer + 0x21e5 + i) == psLine->core.attr_data[4] &&
527 : *((unsigned char*)psDGN->buffer + 0x21e6 + i) == psLine->core.attr_data[5] &&
528 : *((unsigned char*)psDGN->buffer + 0x21e7 + i) == psLine->core.attr_data[6] &&
529 : *((unsigned char*)psDGN->buffer + 0x21e8 + i) == psLine->core.attr_data[7])
530 : {
531 : memcpy( szLineStyle,
532 : (unsigned char*)psDGN->buffer + 0x21e9 + i, 64 );
533 : szLineStyle[64] = '\0';
534 : return TRUE;
535 : }
536 : }
537 : #endif
538 0 : return FALSE;
539 : }
540 : else
541 : {
542 0 : szLineStyle[0] = '\0';
543 0 : return FALSE;
544 : }
545 : }
546 :
547 : /************************************************************************/
548 : /* DGNDumpElement() */
549 : /************************************************************************/
550 :
551 : /**
552 : * Emit textual report of an element.
553 : *
554 : * This function exists primarily for debugging, and will produce a textual
555 : * report about any element type to the designated file.
556 : *
557 : * @param hDGN the file from which the element originated.
558 : * @param psElement the element to report on.
559 : * @param fp the file (such as stdout) to report the element information to.
560 : */
561 :
562 0 : void DGNDumpElement( DGNHandle hDGN, DGNElemCore *psElement, FILE *fp )
563 :
564 : {
565 0 : DGNInfo *psInfo = (DGNInfo *) hDGN;
566 :
567 0 : fprintf( fp, "\n" );
568 : fprintf( fp, "Element:%-12s Level:%2d id:%-6d ",
569 : DGNTypeToName( psElement->type ),
570 : psElement->level,
571 0 : psElement->element_id );
572 :
573 0 : if( psElement->complex )
574 0 : fprintf( fp, "(Complex) " );
575 :
576 0 : if( psElement->deleted )
577 0 : fprintf( fp, "(DELETED) " );
578 :
579 0 : fprintf( fp, "\n" );
580 :
581 : fprintf( fp, " offset=%d size=%d bytes\n",
582 0 : psElement->offset, psElement->size );
583 :
584 : fprintf( fp,
585 : " graphic_group:%-3d color:%d weight:%d style:%d\n",
586 : psElement->graphic_group,
587 : psElement->color,
588 : psElement->weight,
589 0 : psElement->style );
590 :
591 0 : if( psElement->properties != 0 )
592 : {
593 : int nClass;
594 :
595 0 : fprintf( fp, " properties=%d", psElement->properties );
596 0 : if( psElement->properties & DGNPF_HOLE )
597 0 : fprintf( fp, ",HOLE" );
598 0 : if( psElement->properties & DGNPF_SNAPPABLE )
599 0 : fprintf( fp, ",SNAPPABLE" );
600 0 : if( psElement->properties & DGNPF_PLANAR )
601 0 : fprintf( fp, ",PLANAR" );
602 0 : if( psElement->properties & DGNPF_ORIENTATION )
603 0 : fprintf( fp, ",ORIENTATION" );
604 0 : if( psElement->properties & DGNPF_ATTRIBUTES )
605 0 : fprintf( fp, ",ATTRIBUTES" );
606 0 : if( psElement->properties & DGNPF_MODIFIED )
607 0 : fprintf( fp, ",MODIFIED" );
608 0 : if( psElement->properties & DGNPF_NEW )
609 0 : fprintf( fp, ",NEW" );
610 0 : if( psElement->properties & DGNPF_LOCKED )
611 0 : fprintf( fp, ",LOCKED" );
612 :
613 0 : nClass = psElement->properties & DGNPF_CLASS;
614 0 : if( nClass == DGNC_PATTERN_COMPONENT )
615 0 : fprintf( fp, ",PATTERN_COMPONENT" );
616 0 : else if( nClass == DGNC_CONSTRUCTION_ELEMENT )
617 0 : fprintf( fp, ",CONSTRUCTION ELEMENT" );
618 0 : else if( nClass == DGNC_DIMENSION_ELEMENT )
619 0 : fprintf( fp, ",DIMENSION ELEMENT" );
620 0 : else if( nClass == DGNC_PRIMARY_RULE_ELEMENT )
621 0 : fprintf( fp, ",PRIMARY RULE ELEMENT" );
622 0 : else if( nClass == DGNC_LINEAR_PATTERNED_ELEMENT )
623 0 : fprintf( fp, ",LINEAR PATTERNED ELEMENT" );
624 0 : else if( nClass == DGNC_CONSTRUCTION_RULE_ELEMENT )
625 0 : fprintf( fp, ",CONSTRUCTION_RULE_ELEMENT" );
626 :
627 0 : fprintf( fp, "\n" );
628 : }
629 :
630 0 : switch( psElement->stype )
631 : {
632 : case DGNST_MULTIPOINT:
633 : {
634 0 : DGNElemMultiPoint *psLine = (DGNElemMultiPoint *) psElement;
635 : int i;
636 :
637 0 : for( i=0; i < psLine->num_vertices; i++ )
638 : fprintf( fp, " (%.6f,%.6f,%.6f)\n",
639 : psLine->vertices[i].x,
640 : psLine->vertices[i].y,
641 0 : psLine->vertices[i].z );
642 : }
643 0 : break;
644 :
645 : case DGNST_CELL_HEADER:
646 : {
647 0 : DGNElemCellHeader *psCell = (DGNElemCellHeader*) psElement;
648 :
649 : fprintf( fp, " totlength=%d, name=%s, class=%x, levels=%02x%02x%02x%02x\n",
650 : psCell->totlength, psCell->name, psCell->cclass,
651 0 : psCell->levels[0], psCell->levels[1], psCell->levels[2],
652 0 : psCell->levels[3] );
653 : fprintf( fp, " rnglow=(%.5f,%.5f,%.5f)\n"
654 : " rnghigh=(%.5f,%.5f,%.5f)\n",
655 : psCell->rnglow.x, psCell->rnglow.y, psCell->rnglow.z,
656 0 : psCell->rnghigh.x, psCell->rnghigh.y, psCell->rnghigh.z );
657 : fprintf( fp, " origin=(%.5f,%.5f,%.5f)\n",
658 0 : psCell->origin.x, psCell->origin.y, psCell->origin.z);
659 :
660 0 : if( psInfo->dimension == 2 )
661 : fprintf( fp, " xscale=%g, yscale=%g, rotation=%g\n",
662 0 : psCell->xscale, psCell->yscale, psCell->rotation );
663 : else
664 : fprintf( fp, " trans=%g,%g,%g,%g,%g,%g,%g,%g,%g\n",
665 : psCell->trans[0],
666 : psCell->trans[1],
667 : psCell->trans[2],
668 : psCell->trans[3],
669 : psCell->trans[4],
670 : psCell->trans[5],
671 : psCell->trans[6],
672 : psCell->trans[7],
673 0 : psCell->trans[8] );
674 : }
675 0 : break;
676 :
677 : case DGNST_CELL_LIBRARY:
678 : {
679 0 : DGNElemCellLibrary *psCell = (DGNElemCellLibrary*) psElement;
680 :
681 : fprintf( fp,
682 : " name=%s, class=%x, levels=%02x%02x%02x%02x, numwords=%d\n",
683 : psCell->name, psCell->cclass,
684 0 : psCell->levels[0], psCell->levels[1], psCell->levels[2],
685 0 : psCell->levels[3], psCell->numwords );
686 : fprintf( fp, " dispsymb=%d, description=%s\n",
687 0 : psCell->dispsymb, psCell->description );
688 : }
689 0 : break;
690 :
691 : case DGNST_SHARED_CELL_DEFN:
692 : {
693 0 : DGNElemSharedCellDefn *psShared = (DGNElemSharedCellDefn *) psElement;
694 :
695 0 : fprintf( fp, " totlength=%d\n", psShared->totlength);
696 : }
697 0 : break;
698 :
699 : case DGNST_ARC:
700 : {
701 0 : DGNElemArc *psArc = (DGNElemArc *) psElement;
702 :
703 0 : if( psInfo->dimension == 2 )
704 : fprintf( fp, " origin=(%.5f,%.5f), rotation=%f\n",
705 : psArc->origin.x,
706 : psArc->origin.y,
707 0 : psArc->rotation );
708 : else
709 : fprintf( fp, " origin=(%.5f,%.5f,%.5f), quat=%d,%d,%d,%d\n",
710 : psArc->origin.x,
711 : psArc->origin.y,
712 : psArc->origin.z,
713 : psArc->quat[0],
714 : psArc->quat[1],
715 : psArc->quat[2],
716 0 : psArc->quat[3] );
717 : fprintf( fp, " axes=(%.5f,%.5f), start angle=%f, sweep=%f\n",
718 : psArc->primary_axis,
719 : psArc->secondary_axis,
720 : psArc->startang,
721 0 : psArc->sweepang );
722 : }
723 0 : break;
724 :
725 : case DGNST_TEXT:
726 : {
727 0 : DGNElemText *psText = (DGNElemText *) psElement;
728 :
729 : fprintf( fp,
730 : " origin=(%.5f,%.5f), rotation=%f\n"
731 : " font=%d, just=%d, length_mult=%g, height_mult=%g\n"
732 : " string = \"%s\"\n",
733 : psText->origin.x,
734 : psText->origin.y,
735 : psText->rotation,
736 : psText->font_id,
737 : psText->justification,
738 : psText->length_mult,
739 : psText->height_mult,
740 0 : psText->string );
741 : }
742 0 : break;
743 :
744 : case DGNST_TEXT_NODE:
745 : {
746 0 : DGNElemTextNode *psNode = (DGNElemTextNode *) psElement;
747 :
748 : fprintf( fp,
749 : " totlength=%d, num_texts=%d\n",
750 : psNode->totlength,
751 0 : psNode->numelems );
752 : fprintf( fp,
753 : " origin=(%.5f,%.5f), rotation=%f\n"
754 : " font=%d, just=%d, length_mult=%g, height_mult=%g\n",
755 : psNode->origin.x,
756 : psNode->origin.y,
757 : psNode->rotation,
758 : psNode->font_id,
759 : psNode->justification,
760 : psNode->length_mult,
761 0 : psNode->height_mult );
762 : fprintf( fp,
763 : " max_length=%d, used=%d,",
764 : psNode->max_length,
765 0 : psNode->max_used );
766 : fprintf( fp,
767 : " node_number=%d\n",
768 0 : psNode->node_number );
769 : }
770 0 : break;
771 :
772 : case DGNST_COMPLEX_HEADER:
773 : {
774 0 : DGNElemComplexHeader *psHdr = (DGNElemComplexHeader *) psElement;
775 :
776 : fprintf( fp,
777 : " totlength=%d, numelems=%d\n",
778 : psHdr->totlength,
779 0 : psHdr->numelems );
780 0 : if (psElement->type == DGNT_3DSOLID_HEADER ||
781 : psElement->type == DGNT_3DSURFACE_HEADER) {
782 : fprintf( fp,
783 : " surftype=%d, boundelms=%d\n",
784 0 : psHdr->surftype, psHdr->boundelms );
785 : }
786 : }
787 0 : break;
788 :
789 : case DGNST_COLORTABLE:
790 : {
791 0 : DGNElemColorTable *psCT = (DGNElemColorTable *) psElement;
792 : int i;
793 :
794 0 : fprintf( fp, " screen_flag: %d\n", psCT->screen_flag );
795 0 : for( i = 0; i < 256; i++ )
796 : {
797 : fprintf( fp, " %3d: (%3d,%3d,%3d)\n",
798 : i,
799 0 : psCT->color_info[i][0],
800 0 : psCT->color_info[i][1],
801 0 : psCT->color_info[i][2] );
802 : }
803 : }
804 0 : break;
805 :
806 : case DGNST_TCB:
807 : {
808 0 : DGNElemTCB *psTCB = (DGNElemTCB *) psElement;
809 : int iView;
810 :
811 0 : fprintf( fp, " dimension = %d\n", psTCB->dimension );
812 : fprintf( fp, " uor_per_subunit = %ld, subunits = `%s'\n",
813 0 : psTCB->uor_per_subunit, psTCB->sub_units );
814 : fprintf( fp, " subunits_per_master = %ld, master units = `%s'\n",
815 0 : psTCB->subunits_per_master, psTCB->master_units );
816 : fprintf( fp, " origin = (%.5f,%.5f,%.5f)\n",
817 : psTCB->origin_x,
818 : psTCB->origin_y,
819 0 : psTCB->origin_z );
820 :
821 0 : for( iView = 0; iView < 8; iView++ )
822 : {
823 0 : DGNViewInfo *psView = psTCB->views + iView;
824 :
825 : fprintf(fp,
826 : " View%d: flags=%04X, levels=%02X%02X%02X%02X%02X%02X%02X%02X\n",
827 : iView,
828 : psView->flags,
829 0 : psView->levels[0],
830 0 : psView->levels[1],
831 0 : psView->levels[2],
832 0 : psView->levels[3],
833 0 : psView->levels[4],
834 0 : psView->levels[5],
835 0 : psView->levels[6],
836 0 : psView->levels[7] );
837 : fprintf(fp,
838 : " origin=(%g,%g,%g)\n delta=(%g,%g,%g)\n",
839 : psView->origin.x, psView->origin.y, psView->origin.z,
840 0 : psView->delta.x, psView->delta.y, psView->delta.z );
841 : fprintf(fp,
842 : " trans=(%g,%g,%g,%g,%g,%g,%g,%g,%g)\n",
843 : psView->transmatrx[0],
844 : psView->transmatrx[1],
845 : psView->transmatrx[2],
846 : psView->transmatrx[3],
847 : psView->transmatrx[4],
848 : psView->transmatrx[5],
849 : psView->transmatrx[6],
850 : psView->transmatrx[7],
851 0 : psView->transmatrx[8] );
852 : }
853 : }
854 0 : break;
855 :
856 : case DGNST_TAG_SET:
857 : {
858 0 : DGNElemTagSet *psTagSet = (DGNElemTagSet*) psElement;
859 : int iTag;
860 :
861 : fprintf( fp, " tagSetName=%s, tagSet=%d, tagCount=%d, flags=%d\n",
862 : psTagSet->tagSetName, psTagSet->tagSet,
863 0 : psTagSet->tagCount, psTagSet->flags );
864 0 : for( iTag = 0; iTag < psTagSet->tagCount; iTag++ )
865 : {
866 0 : DGNTagDef *psTagDef = psTagSet->tagList + iTag;
867 :
868 : fprintf( fp, " %d: name=%s, type=%d, prompt=%s",
869 : psTagDef->id, psTagDef->name, psTagDef->type,
870 0 : psTagDef->prompt );
871 0 : if( psTagDef->type == 1 )
872 : fprintf( fp, ", default=%s\n",
873 0 : psTagDef->defaultValue.string );
874 0 : else if( psTagDef->type == 3 || psTagDef->type == 5 )
875 : fprintf( fp, ", default=%d\n",
876 0 : psTagDef->defaultValue.integer );
877 0 : else if( psTagDef->type == 4 )
878 : fprintf( fp, ", default=%g\n",
879 0 : psTagDef->defaultValue.real );
880 : else
881 0 : fprintf( fp, ", default=<unknown>\n" );
882 : }
883 : }
884 0 : break;
885 :
886 : case DGNST_TAG_VALUE:
887 : {
888 0 : DGNElemTagValue *psTag = (DGNElemTagValue*) psElement;
889 :
890 : fprintf( fp, " tagType=%d, tagSet=%d, tagIndex=%d, tagLength=%d\n",
891 : psTag->tagType, psTag->tagSet, psTag->tagIndex,
892 0 : psTag->tagLength );
893 0 : if( psTag->tagType == 1 )
894 0 : fprintf( fp, " value=%s\n", psTag->tagValue.string );
895 0 : else if( psTag->tagType == 3 )
896 0 : fprintf( fp, " value=%d\n", psTag->tagValue.integer );
897 0 : else if( psTag->tagType == 4 )
898 0 : fprintf( fp, " value=%g\n", psTag->tagValue.real );
899 : }
900 0 : break;
901 :
902 : case DGNST_CONE:
903 : {
904 0 : DGNElemCone *psCone = (DGNElemCone *) psElement;
905 :
906 : fprintf( fp,
907 : " center_1=(%g,%g,%g) radius=%g\n"
908 : " center_2=(%g,%g,%g) radius=%g\n"
909 : " quat=%d,%d,%d,%d unknown=%d\n",
910 : psCone->center_1.x, psCone->center_1.y, psCone->center_1.z,
911 : psCone->radius_1,
912 : psCone->center_2.x, psCone->center_2.y, psCone->center_2.z,
913 : psCone->radius_2,
914 : psCone->quat[0], psCone->quat[1],
915 : psCone->quat[2], psCone->quat[3],
916 0 : psCone->unknown );
917 : }
918 0 : break;
919 :
920 : case DGNST_BSPLINE_SURFACE_HEADER:
921 : {
922 : DGNElemBSplineSurfaceHeader *psSpline =
923 0 : (DGNElemBSplineSurfaceHeader *) psElement;
924 :
925 : fprintf( fp, " desc_words=%ld, curve type=%d\n",
926 0 : psSpline->desc_words, psSpline->curve_type);
927 :
928 : fprintf( fp, " U: properties=%02x",
929 0 : psSpline->u_properties);
930 0 : if (psSpline->u_properties != 0) {
931 0 : if (psSpline->u_properties & DGNBSC_CURVE_DISPLAY) {
932 0 : fprintf(fp, ",CURVE_DISPLAY");
933 : }
934 0 : if (psSpline->u_properties & DGNBSC_POLY_DISPLAY) {
935 0 : fprintf(fp, ",POLY_DISPLAY");
936 : }
937 0 : if (psSpline->u_properties & DGNBSC_RATIONAL) {
938 0 : fprintf(fp, ",RATIONAL");
939 : }
940 0 : if (psSpline->u_properties & DGNBSC_CLOSED) {
941 0 : fprintf(fp, ",CLOSED");
942 : }
943 : }
944 0 : fprintf(fp, "\n");
945 : fprintf( fp, " order=%d\n %d poles, %d knots, %d rule lines\n",
946 : psSpline->u_order, psSpline->num_poles_u,
947 0 : psSpline->num_knots_u, psSpline->rule_lines_u);
948 :
949 : fprintf( fp, " V: properties=%02x",
950 0 : psSpline->v_properties);
951 0 : if (psSpline->v_properties != 0) {
952 0 : if (psSpline->v_properties & DGNBSS_ARC_SPACING) {
953 0 : fprintf(fp, ",ARC_SPACING");
954 : }
955 0 : if (psSpline->v_properties & DGNBSS_CLOSED) {
956 0 : fprintf(fp, ",CLOSED");
957 : }
958 : }
959 0 : fprintf(fp, "\n");
960 : fprintf( fp, " order=%d\n %d poles, %d knots, %d rule lines\n",
961 : psSpline->v_order, psSpline->num_poles_v,
962 0 : psSpline->num_knots_v, psSpline->rule_lines_v);
963 : }
964 0 : break;
965 :
966 : case DGNST_BSPLINE_CURVE_HEADER:
967 : {
968 : DGNElemBSplineCurveHeader *psSpline =
969 0 : (DGNElemBSplineCurveHeader *) psElement;
970 :
971 : fprintf( fp,
972 : " desc_words=%ld, curve type=%d\n"
973 : " properties=%02x",
974 : psSpline->desc_words, psSpline->curve_type,
975 0 : psSpline->properties);
976 0 : if (psSpline->properties != 0) {
977 0 : if (psSpline->properties & DGNBSC_CURVE_DISPLAY) {
978 0 : fprintf(fp, ",CURVE_DISPLAY");
979 : }
980 0 : if (psSpline->properties & DGNBSC_POLY_DISPLAY) {
981 0 : fprintf(fp, ",POLY_DISPLAY");
982 : }
983 0 : if (psSpline->properties & DGNBSC_RATIONAL) {
984 0 : fprintf(fp, ",RATIONAL");
985 : }
986 0 : if (psSpline->properties & DGNBSC_CLOSED) {
987 0 : fprintf(fp, ",CLOSED");
988 : }
989 : }
990 0 : fprintf(fp, "\n");
991 : fprintf( fp, " order=%d\n %d poles, %d knots\n",
992 0 : psSpline->order, psSpline->num_poles, psSpline->num_knots);
993 : }
994 0 : break;
995 :
996 : case DGNST_BSPLINE_SURFACE_BOUNDARY:
997 : {
998 : DGNElemBSplineSurfaceBoundary *psBounds =
999 0 : (DGNElemBSplineSurfaceBoundary *) psElement;
1000 :
1001 : fprintf( fp, " boundary number=%d, # vertices=%d\n",
1002 0 : psBounds->number, psBounds->numverts);
1003 0 : for (int i=0;i<psBounds->numverts;i++) {
1004 : fprintf( fp, " (%.6f,%.6f)\n",
1005 : psBounds->vertices[i].x,
1006 0 : psBounds->vertices[i].y);
1007 : }
1008 : }
1009 0 : break;
1010 :
1011 : case DGNST_KNOT_WEIGHT:
1012 : {
1013 0 : DGNElemKnotWeight *psArray = (DGNElemKnotWeight *) psElement;
1014 0 : int numelems = (psArray->core.size-36)/4;
1015 0 : for (int i=0;i<numelems;i++) {
1016 0 : fprintf(fp, " %.6f\n", psArray->array[i]);
1017 : }
1018 : }
1019 : break;
1020 :
1021 : default:
1022 : break;
1023 : }
1024 :
1025 0 : if( psElement->attr_bytes > 0 )
1026 : {
1027 : int iLink;
1028 :
1029 0 : fprintf( fp, "Attributes (%d bytes):\n", psElement->attr_bytes );
1030 :
1031 0 : for( iLink = 0; TRUE; iLink++ )
1032 :
1033 : {
1034 0 : int nLinkType, nEntityNum=0, nMSLink=0, nLinkSize, i;
1035 : unsigned char *pabyData;
1036 :
1037 : pabyData = DGNGetLinkage( hDGN, psElement, iLink, &nLinkType,
1038 0 : &nEntityNum, &nMSLink, &nLinkSize );
1039 0 : if( pabyData == NULL )
1040 0 : break;
1041 :
1042 0 : fprintf( fp, "Type=0x%04x", nLinkType );
1043 0 : if( nMSLink != 0 || nEntityNum != 0 )
1044 : fprintf( fp, ", EntityNum=%d, MSLink=%d",
1045 0 : nEntityNum, nMSLink );
1046 :
1047 0 : int nBytes = psElement->attr_data + psElement->attr_bytes - pabyData;
1048 0 : if( nBytes < nLinkSize )
1049 : {
1050 : CPLError( CE_Failure, CPLE_AppDefined,
1051 : "Corrupt linkage, element id:%d, link:%d",
1052 0 : psElement->element_id, iLink);
1053 : fprintf(fp, " (Corrupt, declared size: %d, assuming size: %d)",
1054 0 : nLinkSize, nBytes);
1055 0 : nLinkSize = nBytes;
1056 : }
1057 0 : fprintf( fp, "\n 0x" );
1058 :
1059 0 : for( i = 0; i < nLinkSize; i++ )
1060 0 : fprintf( fp, "%02x", pabyData[i] );
1061 0 : fprintf( fp, "\n" );
1062 :
1063 : }
1064 : }
1065 0 : }
1066 :
1067 :
1068 : /************************************************************************/
1069 : /* DGNTypeToName() */
1070 : /************************************************************************/
1071 :
1072 : /**
1073 : * Convert type to name.
1074 : *
1075 : * Returns a human readable name for an element type such as DGNT_LINE.
1076 : *
1077 : * @param nType the DGNT_* type code to translate.
1078 : *
1079 : * @return a pointer to an internal string with the translation. This string
1080 : * should not be modified or freed.
1081 : */
1082 :
1083 0 : const char *DGNTypeToName( int nType )
1084 :
1085 : {
1086 : static char szNumericResult[16];
1087 :
1088 0 : switch( nType )
1089 : {
1090 : case DGNT_CELL_LIBRARY:
1091 0 : return "Cell Library";
1092 :
1093 : case DGNT_CELL_HEADER:
1094 0 : return "Cell Header";
1095 :
1096 : case DGNT_LINE:
1097 0 : return "Line";
1098 :
1099 : case DGNT_LINE_STRING:
1100 0 : return "Line String";
1101 :
1102 : case DGNT_POINT_STRING:
1103 0 : return "Point String";
1104 :
1105 : case DGNT_GROUP_DATA:
1106 0 : return "Group Data";
1107 :
1108 : case DGNT_SHAPE:
1109 0 : return "Shape";
1110 :
1111 : case DGNT_TEXT_NODE:
1112 0 : return "Text Node";
1113 :
1114 : case DGNT_DIGITIZER_SETUP:
1115 0 : return "Digitizer Setup";
1116 :
1117 : case DGNT_TCB:
1118 0 : return "TCB";
1119 :
1120 : case DGNT_LEVEL_SYMBOLOGY:
1121 0 : return "Level Symbology";
1122 :
1123 : case DGNT_CURVE:
1124 0 : return "Curve";
1125 :
1126 : case DGNT_COMPLEX_CHAIN_HEADER:
1127 0 : return "Complex Chain Header";
1128 :
1129 : case DGNT_COMPLEX_SHAPE_HEADER:
1130 0 : return "Complex Shape Header";
1131 :
1132 : case DGNT_ELLIPSE:
1133 0 : return "Ellipse";
1134 :
1135 : case DGNT_ARC:
1136 0 : return "Arc";
1137 :
1138 : case DGNT_TEXT:
1139 0 : return "Text";
1140 :
1141 : case DGNT_BSPLINE_POLE:
1142 0 : return "B-Spline Pole";
1143 :
1144 : case DGNT_BSPLINE_SURFACE_HEADER:
1145 0 : return "B-Spline Surface Header";
1146 :
1147 : case DGNT_BSPLINE_SURFACE_BOUNDARY:
1148 0 : return "B-Spline Surface Boundary";
1149 :
1150 : case DGNT_BSPLINE_KNOT:
1151 0 : return "B-Spline Knot";
1152 :
1153 : case DGNT_BSPLINE_CURVE_HEADER:
1154 0 : return "B-Spline Curve Header";
1155 :
1156 : case DGNT_BSPLINE_WEIGHT_FACTOR:
1157 0 : return "B-Spline Weight Factor";
1158 :
1159 : case DGNT_APPLICATION_ELEM:
1160 0 : return "Application Element";
1161 :
1162 : case DGNT_SHARED_CELL_DEFN:
1163 0 : return "Shared Cell Definition";
1164 :
1165 : case DGNT_SHARED_CELL_ELEM:
1166 0 : return "Shared Cell Element";
1167 :
1168 : case DGNT_TAG_VALUE:
1169 0 : return "Tag Value";
1170 :
1171 : case DGNT_CONE:
1172 0 : return "Cone";
1173 :
1174 : case DGNT_3DSURFACE_HEADER:
1175 0 : return "3D Surface Header";
1176 :
1177 : case DGNT_3DSOLID_HEADER:
1178 0 : return "3D Solid Header";
1179 :
1180 : default:
1181 0 : sprintf( szNumericResult, "%d", nType );
1182 0 : return szNumericResult;
1183 : }
1184 : }
1185 :
1186 : /************************************************************************/
1187 : /* DGNGetAttrLinkSize() */
1188 : /************************************************************************/
1189 :
1190 : /**
1191 : * Get attribute linkage size.
1192 : *
1193 : * Returns the size, in bytes, of the attribute linkage starting at byte
1194 : * offset nOffset. On failure a value of 0 is returned.
1195 : *
1196 : * @param hDGN the file from which the element originated.
1197 : * @param psElement the element to report on.
1198 : * @param nOffset byte offset within attribute data of linkage to check.
1199 : *
1200 : * @return size of linkage in bytes, or zero.
1201 : */
1202 :
1203 109 : int DGNGetAttrLinkSize( DGNHandle hDGN, DGNElemCore *psElement,
1204 : int nOffset )
1205 :
1206 : {
1207 109 : if( psElement->attr_bytes < nOffset + 4 )
1208 91 : return 0;
1209 :
1210 : /* DMRS Linkage */
1211 36 : if( (psElement->attr_data[nOffset+0] == 0
1212 6 : && psElement->attr_data[nOffset+1] == 0)
1213 12 : || (psElement->attr_data[nOffset+0] == 0
1214 0 : && psElement->attr_data[nOffset+1] == 0x80) )
1215 6 : return 8;
1216 :
1217 : /* If low order bit of second byte is set, first byte is length */
1218 12 : if( psElement->attr_data[nOffset+1] & 0x10 )
1219 12 : return psElement->attr_data[nOffset+0] * 2 + 2;
1220 :
1221 : /* unknown */
1222 0 : return 0;
1223 : }
1224 :
1225 : /************************************************************************/
1226 : /* DGNGetLinkage() */
1227 : /************************************************************************/
1228 :
1229 : /**
1230 : * Returns requested linkage raw data.
1231 : *
1232 : * A pointer to the raw data for the requested attribute linkage is returned
1233 : * as well as (potentially) various information about the linkage including
1234 : * the linkage type, database entity number and MSLink value, and the length
1235 : * of the raw linkage data in bytes.
1236 : *
1237 : * If the requested linkage (iIndex) does not exist a value of zero is
1238 : * returned.
1239 : *
1240 : * The entity number is (loosely speaking) the index of the table within
1241 : * the current database to which the MSLINK value will refer. The entity
1242 : * number should be used to lookup the table name in the MSCATALOG table.
1243 : * The MSLINK value is the key value for the record in the target table.
1244 : *
1245 : * @param hDGN the file from which the element originated.
1246 : * @param psElement the element to report on.
1247 : * @param iIndex the zero based index of the linkage to fetch.
1248 : * @param pnLinkageType variable to return linkage type. This may be one of
1249 : * the predefined DGNLT_ values or a different value. This pointer may be NULL.
1250 : * @param pnEntityNum variable to return the entity number in or NULL if not
1251 : * required.
1252 : * @param pnMSLink variable to return the MSLINK value in, or NULL if not
1253 : * required.
1254 : * @param pnLength variable to returned the linkage size in bytes or NULL.
1255 : *
1256 : * @return pointer to raw internal linkage data. This data should not be
1257 : * altered or freed. NULL returned on failure.
1258 : */
1259 :
1260 102 : unsigned char *DGNGetLinkage( DGNHandle hDGN, DGNElemCore *psElement,
1261 : int iIndex, int *pnLinkageType,
1262 : int *pnEntityNum, int *pnMSLink, int *pnLength )
1263 :
1264 : {
1265 : int nAttrOffset;
1266 : int iLinkage, nLinkSize;
1267 :
1268 109 : for( iLinkage=0, nAttrOffset=0;
1269 : (nLinkSize = DGNGetAttrLinkSize( hDGN, psElement, nAttrOffset)) != 0;
1270 : iLinkage++, nAttrOffset += nLinkSize )
1271 : {
1272 18 : if( iLinkage == iIndex )
1273 : {
1274 11 : int nLinkageType=0, nEntityNum=0, nMSLink = 0;
1275 11 : CPLAssert( nLinkSize > 4 );
1276 :
1277 17 : if( psElement->attr_data[nAttrOffset+0] == 0x00
1278 3 : && (psElement->attr_data[nAttrOffset+1] == 0x00
1279 0 : || psElement->attr_data[nAttrOffset+1] == 0x80) )
1280 : {
1281 3 : nLinkageType = DGNLT_DMRS;
1282 3 : nEntityNum = psElement->attr_data[nAttrOffset+2]
1283 3 : + psElement->attr_data[nAttrOffset+3] * 256;
1284 3 : nMSLink = psElement->attr_data[nAttrOffset+4]
1285 3 : + psElement->attr_data[nAttrOffset+5] * 256
1286 6 : + psElement->attr_data[nAttrOffset+6] * 65536;
1287 : }
1288 : else
1289 8 : nLinkageType = psElement->attr_data[nAttrOffset+2]
1290 8 : + psElement->attr_data[nAttrOffset+3] * 256;
1291 :
1292 : // Possibly an external database linkage?
1293 11 : if( nLinkSize == 16 && nLinkageType != DGNLT_SHAPE_FILL )
1294 : {
1295 0 : nEntityNum = psElement->attr_data[nAttrOffset+6]
1296 0 : + psElement->attr_data[nAttrOffset+7] * 256;
1297 0 : nMSLink = psElement->attr_data[nAttrOffset+8]
1298 0 : + psElement->attr_data[nAttrOffset+9] * 256
1299 0 : + psElement->attr_data[nAttrOffset+10] * 65536
1300 0 : + psElement->attr_data[nAttrOffset+11] * 65536 * 256;
1301 :
1302 : }
1303 :
1304 11 : if( pnLinkageType != NULL )
1305 5 : *pnLinkageType = nLinkageType;
1306 11 : if( pnEntityNum != NULL )
1307 5 : *pnEntityNum = nEntityNum;
1308 11 : if( pnMSLink != NULL )
1309 5 : *pnMSLink = nMSLink;
1310 11 : if( pnLength != NULL )
1311 5 : *pnLength = nLinkSize;
1312 :
1313 11 : return psElement->attr_data + nAttrOffset;
1314 : }
1315 : }
1316 :
1317 91 : return NULL;
1318 : }
1319 :
1320 : /************************************************************************/
1321 : /* DGNRotationToQuat() */
1322 : /* */
1323 : /* Compute a quaternion for a given Z rotation. */
1324 : /************************************************************************/
1325 :
1326 0 : void DGNRotationToQuaternion( double dfRotation, int *panQuaternion )
1327 :
1328 : {
1329 0 : double dfRadianRot = (dfRotation / 180.0) * PI;
1330 :
1331 0 : panQuaternion[0] = (int) (cos(-dfRadianRot/2.0) * 2147483647);
1332 0 : panQuaternion[1] = 0;
1333 0 : panQuaternion[2] = 0;
1334 0 : panQuaternion[3] = (int) (sin(-dfRadianRot/2.0) * 2147483647);
1335 0 : }
1336 :
1337 : /************************************************************************/
1338 : /* DGNQuaternionToMatrix() */
1339 : /* */
1340 : /* Compute a rotation matrix for a given quaternion */
1341 : /* FIXME: Write documentation on how to use this matrix */
1342 : /* (i.e. things like row/column major, OpenGL style or not) */
1343 : /* kintel 20030819 */
1344 : /************************************************************************/
1345 :
1346 0 : void DGNQuaternionToMatrix( int *quat, float *mat )
1347 : {
1348 : double q[4];
1349 :
1350 0 : q[0] = 1.0 * quat[1] / (1<<31);
1351 0 : q[1] = 1.0 * quat[2] / (1<<31);
1352 0 : q[2] = 1.0 * quat[3] / (1<<31);
1353 0 : q[3] = 1.0 * quat[0] / (1<<31);
1354 :
1355 0 : mat[0*3+0] = (float) (q[0]*q[0] - q[1]*q[1] - q[2]*q[2] + q[3]*q[3]);
1356 0 : mat[0*3+1] = (float) (2 * (q[2]*q[3] + q[0]*q[1]));
1357 0 : mat[0*3+2] = (float) (2 * (q[0]*q[2] - q[1]*q[3]));
1358 0 : mat[1*3+0] = (float) (2 * (q[0]*q[1] - q[2]*q[3]));
1359 0 : mat[1*3+1] = (float) (-q[0]*q[0] + q[1]*q[1] - q[2]*q[2] + q[3]*q[3]);
1360 0 : mat[1*3+2] = (float) (2 * (q[0]*q[3] + q[1]*q[2]));
1361 0 : mat[2*3+0] = (float) (2 * (q[0]*q[2] + q[1]*q[3]));
1362 0 : mat[2*3+1] = (float) (2 * (q[1]*q[2] - q[0]*q[3]));
1363 0 : mat[2*3+2] = (float) (-q[0]*q[0] - q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
1364 0 : }
1365 :
1366 : /************************************************************************/
1367 : /* DGNTransformPointWithQuaternion() */
1368 : /************************************************************************/
1369 :
1370 0 : void DGNTransformPointWithQuaternionVertex( int *quat, DGNPoint *v1, DGNPoint *v2 )
1371 : {
1372 :
1373 : /* ==================================================================== */
1374 : /* Original code provided by kintel 20030819, but assumed to be */
1375 : /* incomplete. */
1376 : /* ==================================================================== */
1377 :
1378 : #ifdef notdef
1379 : See below for sketched implementation. kintel 20030819.
1380 : float x,y,z,w;
1381 : // FIXME: Convert quat to x,y,z,w
1382 : v2.x = w*w*v1.x + 2*y*w*v1.z - 2*z*w*v1.y + x*x*v1.x + 2*y*x*v1.y + 2*z*x*v1.z - z*z*v1.x - y*y*v1.x;
1383 : v2.y = 2*x*y*v1.x + y*y*v1.y + 2*z*y*v1.z + 2*w*z*v1.x - z*z*v1.y + w*w*v1.y - 2*x*w*v1.z - x*x*v1.y;
1384 : v2.z = 2*x*z*v1.x + 2*y*z*v1.y + z*z*v1.z - 2*w*y*v1.x - y*y*v1.z + 2*w*x*v1.y - x*x*v1.z + w*w*v1.z;
1385 : #endif
1386 :
1387 : /* ==================================================================== */
1388 : /* Impelementation provided by Peggy Jung - 2004/03/05. */
1389 : /* peggy.jung at moskito-gis dot de. I haven't tested it. */
1390 : /* ==================================================================== */
1391 :
1392 : /* Version: 0.1 Datum: 26.01.2004
1393 :
1394 : IN:
1395 : x,y,z // DGNPoint &v1
1396 : quat[] //
1397 :
1398 : OUT:
1399 : newX, newY, newZ // DGNPoint &v2
1400 :
1401 : A u t o r : Peggy Jung
1402 : */
1403 : /*
1404 : double ROT[12]; //rotation matrix for a given quaternion
1405 : double xx, xy, xz, xw, yy, yz, yw, zz, zw;
1406 : double a, b, c, d, n, x, y, z;
1407 :
1408 : x = v1->x;
1409 : y = v1->y;
1410 : z = v1->z;
1411 :
1412 : n = sqrt((double)PDP2PC_long(quat[0])*(double)PDP2PC_long(quat[0])+(double)PDP2PC_long(quat[1])*(double)PDP2PC_long(quat[1])+
1413 : (double)PDP2PC_long(quat[2])*(double)PDP2PC_long(quat[2])+(double)PDP2PC_long(quat[3])*(double)PDP2PC_long(quat[3]));
1414 :
1415 : a = (double)PDP2PC_long(quat[0])/n; //w
1416 : b = (double)PDP2PC_long(quat[1])/n; //x
1417 : c = (double)PDP2PC_long(quat[2])/n; //y
1418 : d = (double)PDP2PC_long(quat[3])/n; //z
1419 :
1420 : xx = b*b;
1421 : xy = b*c;
1422 : xz = b*d;
1423 : xw = b*a;
1424 :
1425 : yy = c*c;
1426 : yz = c*d;
1427 : yw = c*a;
1428 :
1429 : zz = d*d;
1430 : zw = d+a;
1431 :
1432 : ROT[0] = 1 - 2 * yy - 2 * zz ;
1433 : ROT[1] = 2 * xy - 2 * zw ;
1434 : ROT[2] = 2 * xz + 2 * yw ;
1435 :
1436 : ROT[4] = 2 * xy + 2 * zw ;
1437 : ROT[5] = 1 - 2 * xx - 2 * zz ;
1438 : ROT[6] = 2 * yz - 2 * xw ;
1439 :
1440 : ROT[8] = 2 * xz - 2 * yw ;
1441 : ROT[9] = 2 * yz + 2 * xw ;
1442 : ROT[10] = 1 - 2 * xx - 2 * yy ;
1443 :
1444 : v2->x = ROT[0]*x + ROT[1]*y + ROT[2]*z;
1445 : v2->y = ROT[4]*x + ROT[5]*y + ROT[6]*z;
1446 : v2->z = ROT[8]*x + ROT[9]*y + ROT[10]*z;
1447 : */
1448 0 : }
|