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