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