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