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