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