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