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