1 : /******************************************************************************
2 : * $Id: dgnwrite.cpp 22623 2011-06-29 21:44:00Z rouault $
3 : *
4 : * Project: Microstation DGN Access Library
5 : * Purpose: DGN Access functions related to writing DGN elements.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "dgnlibp.h"
31 :
32 : CPL_CVSID("$Id: dgnwrite.cpp 22623 2011-06-29 21:44:00Z rouault $");
33 :
34 : static void DGNPointToInt( DGNInfo *psDGN, DGNPoint *psPoint,
35 : unsigned char *pabyTarget );
36 :
37 : /************************************************************************/
38 : /* DGNResizeElement() */
39 : /************************************************************************/
40 :
41 : /**
42 : * Resize an existing element.
43 : *
44 : * If the new size is the same as the old nothing happens.
45 : *
46 : * Otherwise, the old element in the file is marked as deleted, and the
47 : * DGNElemCore.offset and element_id are set to -1 indicating that the
48 : * element should be written to the end of file when next written by
49 : * DGNWriteElement(). The internal raw data buffer is updated to the new
50 : * size.
51 : *
52 : * Only elements with "raw_data" loaded may be moved.
53 : *
54 : * In normal use the DGNResizeElement() call would be called on a previously
55 : * loaded element, and afterwards the raw_data would be updated before calling
56 : * DGNWriteElement(). If DGNWriteElement() isn't called after
57 : * DGNResizeElement() then the element will be lost having been marked as
58 : * deleted in it's old position but never written at the new location.
59 : *
60 : * @param hDGN the DGN file on which the element lives.
61 : * @param psElement the element to alter.
62 : * @param nNewSize the desired new size of the element in bytes. Must be
63 : * a multiple of 2.
64 : *
65 : * @return TRUE on success, or FALSE on error.
66 : */
67 :
68 0 : int DGNResizeElement( DGNHandle hDGN, DGNElemCore *psElement, int nNewSize )
69 :
70 : {
71 0 : DGNInfo *psDGN = (DGNInfo *) hDGN;
72 :
73 : /* -------------------------------------------------------------------- */
74 : /* Check various conditions. */
75 : /* -------------------------------------------------------------------- */
76 0 : if( psElement->raw_bytes == 0
77 : || psElement->raw_bytes != psElement->size )
78 : {
79 : CPLError( CE_Failure, CPLE_AppDefined,
80 0 : "Raw bytes not loaded, or not matching element size." );
81 0 : return FALSE;
82 : }
83 :
84 0 : if( nNewSize % 2 == 1 )
85 : {
86 : CPLError( CE_Failure, CPLE_AppDefined,
87 : "DGNResizeElement(%d): "
88 : "can't change to odd (not divisible by two) size.",
89 0 : nNewSize );
90 0 : return FALSE;
91 : }
92 :
93 0 : if( nNewSize == psElement->raw_bytes )
94 0 : return TRUE;
95 :
96 : /* -------------------------------------------------------------------- */
97 : /* Mark the existing element as deleted if the element has to */
98 : /* move to the end of the file. */
99 : /* -------------------------------------------------------------------- */
100 :
101 0 : if( psElement->offset != -1 )
102 : {
103 0 : int nOldFLoc = VSIFTell( psDGN->fp );
104 : unsigned char abyLeader[2];
105 :
106 0 : if( VSIFSeek( psDGN->fp, psElement->offset, SEEK_SET ) != 0
107 : || VSIFRead( abyLeader, sizeof(abyLeader), 1, psDGN->fp ) != 1 )
108 : {
109 : CPLError( CE_Failure, CPLE_AppDefined,
110 : "Failed seek or read when trying to mark existing\n"
111 0 : "element as deleted in DGNResizeElement()\n" );
112 0 : return FALSE;
113 : }
114 :
115 0 : abyLeader[1] |= 0x80;
116 :
117 0 : if( VSIFSeek( psDGN->fp, psElement->offset, SEEK_SET ) != 0
118 : || VSIFWrite( abyLeader, sizeof(abyLeader), 1, psDGN->fp ) != 1 )
119 : {
120 : CPLError( CE_Failure, CPLE_AppDefined,
121 : "Failed seek or write when trying to mark existing\n"
122 0 : "element as deleted in DGNResizeElement()\n" );
123 0 : return FALSE;
124 : }
125 :
126 0 : VSIFSeek( psDGN->fp, SEEK_SET, nOldFLoc );
127 :
128 0 : if( psElement->element_id != -1 && psDGN->index_built )
129 : psDGN->element_index[psElement->element_id].flags
130 0 : |= DGNEIF_DELETED;
131 : }
132 :
133 0 : psElement->offset = -1; /* move to end of file. */
134 0 : psElement->element_id = -1;
135 :
136 : /* -------------------------------------------------------------------- */
137 : /* Set the new size information, and realloc the raw data buffer. */
138 : /* -------------------------------------------------------------------- */
139 0 : psElement->size = nNewSize;
140 : psElement->raw_data = (unsigned char *)
141 0 : CPLRealloc( psElement->raw_data, nNewSize );
142 0 : psElement->raw_bytes = nNewSize;
143 :
144 : /* -------------------------------------------------------------------- */
145 : /* Update the size information within the raw buffer. */
146 : /* -------------------------------------------------------------------- */
147 0 : int nWords = (nNewSize / 2) - 2;
148 :
149 0 : psElement->raw_data[2] = (unsigned char) (nWords % 256);
150 0 : psElement->raw_data[3] = (unsigned char) (nWords / 256);
151 :
152 0 : return TRUE;
153 : }
154 :
155 : /************************************************************************/
156 : /* DGNWriteElement() */
157 : /************************************************************************/
158 :
159 : /**
160 : * Write element to file.
161 : *
162 : * Only elements with "raw_data" loaded may be written. This should
163 : * include elements created with the various DGNCreate*() functions, and
164 : * those read from the file with the DGNO_CAPTURE_RAW_DATA flag turned on
165 : * with DGNSetOptions().
166 : *
167 : * The passed element is written to the indicated file. If the
168 : * DGNElemCore.offset field is -1 then the element is written at the end of
169 : * the file (and offset/element are reset properly) otherwise the element
170 : * is written back to the location indicated by DGNElemCore.offset.
171 : *
172 : * If the element is added at the end of the file, and if an element index
173 : * has already been built, it will be updated to reference the new element.
174 : *
175 : * This function takes care of ensuring that the end-of-file marker is
176 : * maintained after the last element.
177 : *
178 : * @param hDGN the file to write the element to.
179 : * @param psElement the element to write.
180 : *
181 : * @return TRUE on success or FALSE in case of failure.
182 : */
183 :
184 17 : int DGNWriteElement( DGNHandle hDGN, DGNElemCore *psElement )
185 :
186 : {
187 17 : DGNInfo *psDGN = (DGNInfo *) hDGN;
188 :
189 : /* ==================================================================== */
190 : /* If this element hasn't been positioned yet, place it at the */
191 : /* end of the file. */
192 : /* ==================================================================== */
193 17 : if( psElement->offset == -1 )
194 : {
195 : int nJunk;
196 :
197 : // We must have an index, in order to properly assign the
198 : // element id of the newly written element. Ensure it is built.
199 17 : if( !psDGN->index_built )
200 1 : DGNBuildIndex( psDGN );
201 :
202 : // Read the current "last" element.
203 17 : if( !DGNGotoElement( hDGN, psDGN->element_count-1 ) )
204 0 : return FALSE;
205 :
206 17 : if( !DGNLoadRawElement( psDGN, &nJunk, &nJunk ) )
207 0 : return FALSE;
208 :
209 : // Establish the position of the new element.
210 17 : psElement->offset = VSIFTell( psDGN->fp );
211 17 : psElement->element_id = psDGN->element_count;
212 :
213 : // Grow element buffer if needed.
214 17 : if( psDGN->element_count == psDGN->max_element_count )
215 : {
216 0 : psDGN->max_element_count += 500;
217 :
218 : psDGN->element_index = (DGNElementInfo *)
219 : CPLRealloc( psDGN->element_index,
220 0 : psDGN->max_element_count * sizeof(DGNElementInfo));
221 : }
222 :
223 : // Set up the element info
224 : DGNElementInfo *psInfo;
225 :
226 17 : psInfo = psDGN->element_index + psDGN->element_count;
227 17 : psInfo->level = (unsigned char) psElement->level;
228 17 : psInfo->type = (unsigned char) psElement->type;
229 17 : psInfo->stype = (unsigned char) psElement->stype;
230 17 : psInfo->offset = psElement->offset;
231 17 : if( psElement->complex )
232 3 : psInfo->flags = DGNEIF_COMPLEX;
233 : else
234 14 : psInfo->flags = 0;
235 :
236 17 : psDGN->element_count++;
237 : }
238 :
239 : /* -------------------------------------------------------------------- */
240 : /* Write out the element. */
241 : /* -------------------------------------------------------------------- */
242 17 : if( VSIFSeek( psDGN->fp, psElement->offset, SEEK_SET ) != 0
243 : || VSIFWrite( psElement->raw_data, psElement->raw_bytes,
244 : 1, psDGN->fp) != 1 )
245 : {
246 : CPLError( CE_Failure, CPLE_AppDefined,
247 : "Error seeking or writing new element of %d bytes at %d.",
248 : psElement->offset,
249 0 : psElement->raw_bytes );
250 0 : return FALSE;
251 : }
252 :
253 17 : psDGN->next_element_id = psElement->element_id + 1;
254 :
255 : /* -------------------------------------------------------------------- */
256 : /* Write out the end of file 0xffff marker (if we were */
257 : /* extending the file), but push the file pointer back before */
258 : /* this EOF when done. */
259 : /* -------------------------------------------------------------------- */
260 17 : if( psDGN->next_element_id == psDGN->element_count )
261 : {
262 : unsigned char abyEOF[2];
263 :
264 17 : abyEOF[0] = 0xff;
265 17 : abyEOF[1] = 0xff;
266 :
267 17 : VSIFWrite( abyEOF, 2, 1, psDGN->fp );
268 17 : VSIFSeek( psDGN->fp, -2, SEEK_CUR );
269 : }
270 :
271 17 : return TRUE;
272 : }
273 :
274 : /************************************************************************/
275 : /* DGNCreate() */
276 : /************************************************************************/
277 :
278 : /**
279 : * Create new DGN file.
280 : *
281 : * This function will create a new DGN file based on the provided seed
282 : * file, and return a handle on which elements may be read and written.
283 : *
284 : * The following creation flags may be passed:
285 : * <ul>
286 : * <li> DGNCF_USE_SEED_UNITS: The master and subunit resolutions and names
287 : * from the seed file will be used in the new file. The nMasterUnitPerSubUnit,
288 : * nUORPerSubUnit, pszMasterUnits, and pszSubUnits arguments will be ignored.
289 : * <li> DGNCF_USE_SEED_ORIGIN: The origin from the seed file will be used
290 : * and the X, Y and Z origin passed into the call will be ignored.
291 : * <li> DGNCF_COPY_SEED_FILE_COLOR_TABLE: Should the first color table occuring
292 : * in the seed file also be copied?
293 : * <li> DGNCF_COPY_WHOLE_SEED_FILE: By default only the first three elements
294 : * (TCB, Digitizer Setup and Level Symbology) are copied from the seed file.
295 : * If this flag is provided the entire seed file is copied verbatim (with the
296 : * TCB origin and units possibly updated).
297 : * </ul>
298 : *
299 : * @param pszNewFilename the filename to create. If it already exists
300 : * it will be overwritten.
301 : * @param pszSeedFile the seed file to copy header from.
302 : * @param nCreationFlags An ORing of DGNCF_* flags that are to take effect.
303 : * @param dfOriginX the X origin for the file.
304 : * @param dfOriginY the Y origin for the file.
305 : * @param dfOriginZ the Z origin for the file.
306 : * @param nSubUnitPerMasterUnit the number of subunits in one master unit.
307 : * @param nUORPerSubUnit the number of UOR (units of resolution) per subunit.
308 : * @param pszMasterUnits the name of the master units (2 characters).
309 : * @param pszSubUnits the name of the subunits (2 characters).
310 : */
311 :
312 : DGNHandle
313 1 : DGNCreate( const char *pszNewFilename, const char *pszSeedFile,
314 : int nCreationFlags,
315 : double dfOriginX, double dfOriginY, double dfOriginZ,
316 : int nSubUnitsPerMasterUnit, int nUORPerSubUnit,
317 : const char *pszMasterUnits, const char *pszSubUnits )
318 :
319 : {
320 : DGNInfo *psSeed, *psDGN;
321 : FILE *fpNew;
322 : DGNElemCore *psSrcTCB;
323 :
324 : /* -------------------------------------------------------------------- */
325 : /* Open seed file, and read TCB element. */
326 : /* -------------------------------------------------------------------- */
327 1 : psSeed = (DGNInfo *) DGNOpen( pszSeedFile, FALSE );
328 1 : if( psSeed == NULL )
329 0 : return NULL;
330 :
331 1 : DGNSetOptions( psSeed, DGNO_CAPTURE_RAW_DATA );
332 :
333 1 : psSrcTCB = DGNReadElement( psSeed );
334 :
335 1 : CPLAssert( psSrcTCB->raw_bytes >= 1536 );
336 :
337 : /* -------------------------------------------------------------------- */
338 : /* Open output file. */
339 : /* -------------------------------------------------------------------- */
340 1 : fpNew = VSIFOpen( pszNewFilename, "wb" );
341 1 : if( fpNew == NULL )
342 : {
343 : CPLError( CE_Failure, CPLE_OpenFailed,
344 0 : "Failed to open output file: %s", pszNewFilename );
345 0 : return NULL;
346 : }
347 :
348 : /* -------------------------------------------------------------------- */
349 : /* Modify TCB appropriately for the output file. */
350 : /* -------------------------------------------------------------------- */
351 1 : GByte *pabyRawTCB = (GByte *) CPLMalloc(psSrcTCB->raw_bytes);
352 :
353 1 : memcpy( pabyRawTCB, psSrcTCB->raw_data, psSrcTCB->raw_bytes );
354 :
355 1 : if( !(nCreationFlags & DGNCF_USE_SEED_UNITS) )
356 : {
357 1 : memcpy( pabyRawTCB+1120, pszMasterUnits, 2 );
358 1 : memcpy( pabyRawTCB+1122, pszSubUnits, 2 );
359 :
360 1 : DGN_WRITE_INT32( nUORPerSubUnit, pabyRawTCB+1116 );
361 1 : DGN_WRITE_INT32( nSubUnitsPerMasterUnit,pabyRawTCB+1112);
362 : }
363 : else
364 : {
365 0 : nUORPerSubUnit = DGN_INT32( pabyRawTCB+1116 );
366 0 : nSubUnitsPerMasterUnit = DGN_INT32( pabyRawTCB+1112 );
367 : }
368 :
369 1 : if( !(nCreationFlags & DGNCF_USE_SEED_ORIGIN) )
370 : {
371 1 : dfOriginX *= (nUORPerSubUnit * nSubUnitsPerMasterUnit);
372 1 : dfOriginY *= (nUORPerSubUnit * nSubUnitsPerMasterUnit);
373 1 : dfOriginZ *= (nUORPerSubUnit * nSubUnitsPerMasterUnit);
374 :
375 1 : memcpy( pabyRawTCB+1240, &dfOriginX, 8 );
376 1 : memcpy( pabyRawTCB+1248, &dfOriginY, 8 );
377 1 : memcpy( pabyRawTCB+1256, &dfOriginZ, 8 );
378 :
379 1 : IEEE2DGNDouble( pabyRawTCB+1240 );
380 1 : IEEE2DGNDouble( pabyRawTCB+1248 );
381 1 : IEEE2DGNDouble( pabyRawTCB+1256 );
382 : }
383 :
384 : /* -------------------------------------------------------------------- */
385 : /* Write TCB and EOF to new file. */
386 : /* -------------------------------------------------------------------- */
387 : unsigned char abyEOF[2];
388 :
389 1 : VSIFWrite( pabyRawTCB, psSrcTCB->raw_bytes, 1, fpNew );
390 1 : CPLFree( pabyRawTCB );
391 :
392 1 : abyEOF[0] = 0xff;
393 1 : abyEOF[1] = 0xff;
394 :
395 1 : VSIFWrite( abyEOF, 2, 1, fpNew );
396 :
397 1 : DGNFreeElement( psSeed, psSrcTCB );
398 :
399 : /* -------------------------------------------------------------------- */
400 : /* Close and re-open using DGN API. */
401 : /* -------------------------------------------------------------------- */
402 1 : VSIFClose( fpNew );
403 :
404 1 : psDGN = (DGNInfo *) DGNOpen( pszNewFilename, TRUE );
405 :
406 : /* -------------------------------------------------------------------- */
407 : /* Now copy over elements according to options in effect. */
408 : /* -------------------------------------------------------------------- */
409 : DGNElemCore *psSrcElement, *psDstElement;
410 :
411 13 : while( (psSrcElement = DGNReadElement( psSeed )) != NULL )
412 : {
413 11 : if( (nCreationFlags & DGNCF_COPY_WHOLE_SEED_FILE)
414 : || (psSrcElement->stype == DGNST_COLORTABLE
415 : && nCreationFlags & DGNCF_COPY_SEED_FILE_COLOR_TABLE)
416 : || psSrcElement->element_id <= 2 )
417 : {
418 11 : psDstElement = DGNCloneElement( psSeed, psDGN, psSrcElement );
419 11 : DGNWriteElement( psDGN, psDstElement );
420 11 : DGNFreeElement( psDGN, psDstElement );
421 : }
422 :
423 11 : DGNFreeElement( psSeed, psSrcElement );
424 : }
425 :
426 1 : DGNClose( psSeed );
427 :
428 1 : return psDGN;
429 : }
430 :
431 : /************************************************************************/
432 : /* DGNCloneElement() */
433 : /************************************************************************/
434 :
435 : /**
436 : * Clone a retargetted element.
437 : *
438 : * Creates a copy of an element in a suitable form to write to a
439 : * different file than that it was read from.
440 : *
441 : * NOTE: At this time the clone operation will fail if the source
442 : * and destination file have a different origin or master/sub units.
443 : *
444 : * @param hDGNSrc the source file (from which psSrcElement was read).
445 : * @param hDGNDst the destination file (to which the returned element may be
446 : * written).
447 : * @param psSrcElement the element to be cloned (from hDGNSrc).
448 : *
449 : * @return NULL on failure, or an appropriately modified copy of
450 : * the source element suitable to write to hDGNDst.
451 : */
452 :
453 11 : DGNElemCore *DGNCloneElement( DGNHandle hDGNSrc, DGNHandle hDGNDst,
454 : DGNElemCore *psSrcElement )
455 :
456 : {
457 11 : DGNElemCore *psClone = NULL;
458 :
459 11 : DGNLoadTCB( hDGNDst );
460 :
461 : /* -------------------------------------------------------------------- */
462 : /* Per structure specific copying. The core is fixed up later. */
463 : /* -------------------------------------------------------------------- */
464 11 : if( psSrcElement->stype == DGNST_CORE )
465 : {
466 11 : psClone = (DGNElemCore *) CPLMalloc(sizeof(DGNElemCore));
467 11 : memcpy( psClone, psSrcElement, sizeof(DGNElemCore) );
468 : }
469 0 : else if( psSrcElement->stype == DGNST_MULTIPOINT )
470 : {
471 : DGNElemMultiPoint *psMP, *psSrcMP;
472 : int nSize;
473 :
474 0 : psSrcMP = (DGNElemMultiPoint *) psSrcElement;
475 :
476 : nSize = sizeof(DGNElemMultiPoint)
477 0 : + sizeof(DGNPoint) * (psSrcMP->num_vertices-2);
478 :
479 0 : psMP = (DGNElemMultiPoint *) CPLMalloc( nSize );
480 0 : memcpy( psMP, psSrcElement, nSize );
481 :
482 0 : psClone = (DGNElemCore *) psMP;
483 : }
484 0 : else if( psSrcElement->stype == DGNST_ARC )
485 : {
486 : DGNElemArc *psArc;
487 :
488 0 : psArc = (DGNElemArc *) CPLMalloc(sizeof(DGNElemArc));
489 0 : memcpy( psArc, psSrcElement, sizeof(DGNElemArc) );
490 :
491 0 : psClone = (DGNElemCore *) psArc;
492 : }
493 0 : else if( psSrcElement->stype == DGNST_TEXT )
494 : {
495 : DGNElemText *psText, *psSrcText;
496 : int nSize;
497 :
498 0 : psSrcText = (DGNElemText *) psSrcElement;
499 0 : nSize = sizeof(DGNElemText) + strlen(psSrcText->string);
500 :
501 0 : psText = (DGNElemText *) CPLMalloc( nSize );
502 0 : memcpy( psText, psSrcElement, nSize );
503 :
504 0 : psClone = (DGNElemCore *) psText;
505 : }
506 0 : else if( psSrcElement->stype == DGNST_TEXT_NODE )
507 : {
508 : DGNElemTextNode *psNode;
509 :
510 : psNode = (DGNElemTextNode *)
511 0 : CPLMalloc(sizeof(DGNElemTextNode));
512 0 : memcpy( psNode, psSrcElement, sizeof(DGNElemTextNode) );
513 :
514 0 : psClone = (DGNElemCore *) psNode;
515 : }
516 0 : else if( psSrcElement->stype == DGNST_COMPLEX_HEADER )
517 : {
518 : DGNElemComplexHeader *psCH;
519 :
520 : psCH = (DGNElemComplexHeader *)
521 0 : CPLMalloc(sizeof(DGNElemComplexHeader));
522 0 : memcpy( psCH, psSrcElement, sizeof(DGNElemComplexHeader) );
523 :
524 0 : psClone = (DGNElemCore *) psCH;
525 : }
526 0 : else if( psSrcElement->stype == DGNST_COLORTABLE )
527 : {
528 : DGNElemColorTable *psCT;
529 :
530 0 : psCT = (DGNElemColorTable *) CPLMalloc(sizeof(DGNElemColorTable));
531 0 : memcpy( psCT, psSrcElement, sizeof(DGNElemColorTable) );
532 :
533 0 : psClone = (DGNElemCore *) psCT;
534 : }
535 0 : else if( psSrcElement->stype == DGNST_TCB )
536 : {
537 : DGNElemTCB *psTCB;
538 :
539 0 : psTCB = (DGNElemTCB *) CPLMalloc(sizeof(DGNElemTCB));
540 0 : memcpy( psTCB, psSrcElement, sizeof(DGNElemTCB) );
541 :
542 0 : psClone = (DGNElemCore *) psTCB;
543 : }
544 0 : else if( psSrcElement->stype == DGNST_CELL_HEADER )
545 : {
546 : DGNElemCellHeader *psCH;
547 :
548 0 : psCH = (DGNElemCellHeader *) CPLMalloc(sizeof(DGNElemCellHeader));
549 0 : memcpy( psCH, psSrcElement, sizeof(DGNElemCellHeader) );
550 :
551 0 : psClone = (DGNElemCore *) psCH;
552 : }
553 0 : else if( psSrcElement->stype == DGNST_CELL_LIBRARY )
554 : {
555 : DGNElemCellLibrary *psCL;
556 :
557 0 : psCL = (DGNElemCellLibrary *) CPLMalloc(sizeof(DGNElemCellLibrary));
558 0 : memcpy( psCL, psSrcElement, sizeof(DGNElemCellLibrary) );
559 :
560 0 : psClone = (DGNElemCore *) psCL;
561 : }
562 0 : else if( psSrcElement->stype == DGNST_TAG_VALUE )
563 : {
564 : DGNElemTagValue *psTV;
565 :
566 0 : psTV = (DGNElemTagValue *) CPLMalloc(sizeof(DGNElemTagValue));
567 0 : memcpy( psTV, psSrcElement, sizeof(DGNElemTagValue) );
568 :
569 0 : if( psTV->tagType == 1 )
570 0 : psTV->tagValue.string = CPLStrdup( psTV->tagValue.string );
571 :
572 0 : psClone = (DGNElemCore *) psTV;
573 : }
574 0 : else if( psSrcElement->stype == DGNST_TAG_SET )
575 : {
576 : DGNElemTagSet *psTS;
577 : int iTag;
578 : DGNTagDef *pasTagList;
579 :
580 0 : psTS = (DGNElemTagSet *) CPLMalloc(sizeof(DGNElemTagSet));
581 0 : memcpy( psTS, psSrcElement, sizeof(DGNElemTagSet) );
582 :
583 0 : psTS->tagSetName = CPLStrdup( psTS->tagSetName );
584 :
585 : pasTagList = (DGNTagDef *)
586 0 : CPLMalloc( sizeof(DGNTagDef) * psTS->tagCount );
587 : memcpy( pasTagList, psTS->tagList,
588 0 : sizeof(DGNTagDef) * psTS->tagCount );
589 :
590 0 : for( iTag = 0; iTag < psTS->tagCount; iTag++ )
591 : {
592 0 : pasTagList[iTag].name = CPLStrdup( pasTagList[iTag].name );
593 0 : pasTagList[iTag].prompt = CPLStrdup( pasTagList[iTag].prompt );
594 0 : if( pasTagList[iTag].type == 1 )
595 0 : pasTagList[iTag].defaultValue.string =
596 0 : CPLStrdup( pasTagList[iTag].defaultValue.string);
597 : }
598 :
599 0 : psTS->tagList = pasTagList;
600 0 : psClone = (DGNElemCore *) psTS;
601 : }
602 0 : else if( psSrcElement->stype == DGNST_CONE )
603 : {
604 : DGNElemCone *psCone;
605 :
606 0 : psCone = (DGNElemCone *) CPLMalloc(sizeof(DGNElemCone));
607 0 : memcpy( psCone, psSrcElement, sizeof(DGNElemCone) );
608 :
609 0 : psClone = (DGNElemCore *) psCone;
610 : }
611 0 : else if( psSrcElement->stype == DGNST_BSPLINE_SURFACE_HEADER )
612 : {
613 : DGNElemBSplineSurfaceHeader *psSurface;
614 :
615 : psSurface = (DGNElemBSplineSurfaceHeader *)
616 0 : CPLMalloc(sizeof(DGNElemBSplineSurfaceHeader));
617 0 : memcpy( psSurface, psSrcElement, sizeof(DGNElemBSplineSurfaceHeader) );
618 :
619 0 : psClone = (DGNElemCore *) psSurface;
620 : }
621 0 : else if( psSrcElement->stype == DGNST_BSPLINE_CURVE_HEADER )
622 : {
623 : DGNElemBSplineCurveHeader *psCurve;
624 :
625 : psCurve = (DGNElemBSplineCurveHeader *)
626 0 : CPLMalloc(sizeof(DGNElemBSplineCurveHeader));
627 0 : memcpy( psCurve, psSrcElement, sizeof(DGNElemBSplineCurveHeader) );
628 :
629 0 : psClone = (DGNElemCore *) psCurve;
630 : }
631 0 : else if( psSrcElement->stype == DGNST_BSPLINE_SURFACE_BOUNDARY )
632 : {
633 : DGNElemBSplineSurfaceBoundary *psBSB, *psSrcBSB;
634 : int nSize;
635 :
636 0 : psSrcBSB = (DGNElemBSplineSurfaceBoundary *) psSrcElement;
637 :
638 : nSize = sizeof(DGNElemBSplineSurfaceBoundary)
639 0 : + sizeof(DGNPoint) * (psSrcBSB->numverts-1);
640 :
641 0 : psBSB = (DGNElemBSplineSurfaceBoundary *) CPLMalloc( nSize );
642 0 : memcpy( psBSB, psSrcElement, nSize );
643 :
644 0 : psClone = (DGNElemCore *) psBSB;
645 : }
646 0 : else if( psSrcElement->stype == DGNST_KNOT_WEIGHT )
647 : {
648 : DGNElemKnotWeight *psArray, *psSrcArray;
649 : int nSize, numelems;
650 :
651 : // FIXME: Is it OK to assume that the # of elements corresponds
652 : // directly to the element size? kintel 20051218.
653 0 : numelems = (psSrcElement->size - 36 - psSrcElement->attr_bytes)/4;
654 :
655 0 : psSrcArray = (DGNElemKnotWeight *) psSrcElement;
656 :
657 0 : nSize = sizeof(DGNElemKnotWeight) + sizeof(long) * (numelems-1);
658 :
659 0 : psArray = (DGNElemKnotWeight *) CPLMalloc( nSize );
660 0 : memcpy( psArray, psSrcElement, nSize );
661 :
662 0 : psClone = (DGNElemCore *) psArray;
663 : }
664 0 : else if( psSrcElement->stype == DGNST_SHARED_CELL_DEFN )
665 : {
666 : DGNElemSharedCellDefn *psCH;
667 :
668 0 : psCH = (DGNElemSharedCellDefn *)CPLMalloc(sizeof(DGNElemSharedCellDefn));
669 0 : memcpy( psCH, psSrcElement, sizeof(DGNElemSharedCellDefn) );
670 :
671 0 : psClone = (DGNElemCore *) psCH;
672 : }
673 : else
674 : {
675 0 : CPLAssert( FALSE );
676 0 : return NULL;
677 : }
678 :
679 : /* -------------------------------------------------------------------- */
680 : /* Copy core raw data, and attributes. */
681 : /* -------------------------------------------------------------------- */
682 11 : if( psClone->raw_bytes != 0 )
683 : {
684 11 : psClone->raw_data = (unsigned char *) CPLMalloc(psClone->raw_bytes);
685 : memcpy( psClone->raw_data, psSrcElement->raw_data,
686 11 : psClone->raw_bytes );
687 : }
688 :
689 11 : if( psClone->attr_bytes != 0 )
690 : {
691 0 : psClone->attr_data = (unsigned char *) CPLMalloc(psClone->attr_bytes);
692 : memcpy( psClone->attr_data, psSrcElement->attr_data,
693 0 : psClone->attr_bytes );
694 : }
695 :
696 : /* -------------------------------------------------------------------- */
697 : /* Clear location and id information. */
698 : /* -------------------------------------------------------------------- */
699 11 : psClone->offset = -1;
700 11 : psClone->element_id = -1;
701 :
702 11 : return psClone;
703 : }
704 :
705 : /************************************************************************/
706 : /* DGNUpdateElemCore() */
707 : /************************************************************************/
708 :
709 : /**
710 : * Change element core values.
711 : *
712 : * The indicated values in the element are updated in the structure, as well
713 : * as in the raw data. The updated element is not written to disk. That
714 : * must be done with DGNWriteElement(). The element must have raw_data
715 : * loaded.
716 : *
717 : * @param hDGN the file on which the element belongs.
718 : * @param psElement the element to modify.
719 : * @param nLevel the new level value.
720 : * @param nGraphicGroup the new graphic group value.
721 : * @param nColor the new color index.
722 : * @param nWeight the new element weight.
723 : * @param nStyle the new style value for the element.
724 : *
725 : * @return Returns TRUE on success or FALSE on failure.
726 : */
727 :
728 5 : int DGNUpdateElemCore( DGNHandle hDGN, DGNElemCore *psElement,
729 : int nLevel, int nGraphicGroup, int nColor,
730 : int nWeight, int nStyle )
731 :
732 : {
733 5 : psElement->level = nLevel;
734 5 : psElement->graphic_group = nGraphicGroup;
735 5 : psElement->color = nColor;
736 5 : psElement->weight = nWeight;
737 5 : psElement->style = nStyle;
738 :
739 5 : return DGNUpdateElemCoreExtended( hDGN, psElement );
740 : }
741 :
742 : /************************************************************************/
743 : /* DGNUpdateElemCoreExtended() */
744 : /************************************************************************/
745 :
746 : /**
747 : * Update internal raw data representation.
748 : *
749 : * The raw_data representation of the passed element is updated to reflect
750 : * the various core fields. The DGNElemCore level, type, complex, deleted,
751 : * graphic_group, properties, color, weight and style values are all
752 : * applied to the raw_data representation. Spatial bounds, element type
753 : * specific information and attributes are not updated in the raw data.
754 : *
755 : * @param hDGN the file to which the element belongs.
756 : * @param psElement the element to be updated.
757 : *
758 : * @return TRUE on success, or FALSE on failure.
759 : */
760 :
761 :
762 12 : int DGNUpdateElemCoreExtended( DGNHandle hDGN, DGNElemCore *psElement )
763 :
764 : {
765 12 : GByte *rd = psElement->raw_data;
766 12 : int nWords = (psElement->raw_bytes / 2) - 2;
767 :
768 12 : if( psElement->raw_data == NULL
769 : || psElement->raw_bytes < 36 )
770 : {
771 0 : CPLAssert( FALSE );
772 0 : return FALSE;
773 : }
774 :
775 : /* -------------------------------------------------------------------- */
776 : /* Setup first four bytes. */
777 : /* -------------------------------------------------------------------- */
778 12 : rd[0] = (GByte) psElement->level;
779 12 : if( psElement->complex )
780 4 : rd[0] |= 0x80;
781 :
782 12 : rd[1] = (GByte) psElement->type;
783 12 : if( psElement->deleted )
784 0 : rd[1] |= 0x80;
785 :
786 12 : rd[2] = (GByte) (nWords % 256);
787 12 : rd[3] = (GByte) (nWords / 256);
788 :
789 : /* -------------------------------------------------------------------- */
790 : /* If the attribute offset hasn't been set, set it now under */
791 : /* the assumption it should point to the end of the element. */
792 : /* -------------------------------------------------------------------- */
793 12 : if( psElement->raw_data[30] == 0 && psElement->raw_data[31] == 0 )
794 : {
795 6 : int nAttIndex = (psElement->raw_bytes - 32) / 2;
796 :
797 6 : psElement->raw_data[30] = (GByte) (nAttIndex % 256);
798 6 : psElement->raw_data[31] = (GByte) (nAttIndex / 256);
799 : }
800 : /* -------------------------------------------------------------------- */
801 : /* Handle the graphic properties. */
802 : /* -------------------------------------------------------------------- */
803 12 : if( psElement->raw_bytes > 36 && DGNElemTypeHasDispHdr( psElement->type ) )
804 : {
805 12 : rd[28] = (GByte) (psElement->graphic_group % 256);
806 12 : rd[29] = (GByte) (psElement->graphic_group / 256);
807 12 : rd[32] = (GByte) (psElement->properties % 256);
808 12 : rd[33] = (GByte) (psElement->properties / 256);
809 12 : rd[34] = (GByte) (psElement->style | (psElement->weight << 3));
810 12 : rd[35] = (GByte) psElement->color;
811 : }
812 :
813 12 : return TRUE;
814 : }
815 :
816 : /************************************************************************/
817 : /* DGNInitializeElemCore() */
818 : /************************************************************************/
819 :
820 6 : static void DGNInitializeElemCore( DGNHandle hDGN, DGNElemCore *psElement )
821 :
822 : {
823 6 : memset( psElement, 0, sizeof(DGNElemCore) );
824 :
825 6 : psElement->offset = -1;
826 6 : psElement->element_id = -1;
827 6 : }
828 :
829 : /************************************************************************/
830 : /* DGNWriteBounds() */
831 : /* */
832 : /* Write bounds to element raw data. */
833 : /************************************************************************/
834 :
835 6 : static void DGNWriteBounds( DGNInfo *psInfo, DGNElemCore *psElement,
836 : DGNPoint *psMin, DGNPoint *psMax )
837 :
838 : {
839 6 : CPLAssert( psElement->raw_bytes >= 28 );
840 :
841 6 : DGNInverseTransformPointToInt( psInfo, psMin, psElement->raw_data + 4 );
842 6 : DGNInverseTransformPointToInt( psInfo, psMax, psElement->raw_data + 16 );
843 :
844 : /* convert from twos complement to "binary offset" format. */
845 :
846 6 : psElement->raw_data[5] ^= 0x80;
847 6 : psElement->raw_data[9] ^= 0x80;
848 6 : psElement->raw_data[13] ^= 0x80;
849 6 : psElement->raw_data[17] ^= 0x80;
850 6 : psElement->raw_data[21] ^= 0x80;
851 6 : psElement->raw_data[25] ^= 0x80;
852 6 : }
853 :
854 : /************************************************************************/
855 : /* DGNCreateMultiPointElem() */
856 : /************************************************************************/
857 :
858 : /**
859 : * Create new multi-point element.
860 : *
861 : * The newly created element will still need to be written to file using
862 : * DGNWriteElement(). Also the level and other core values will be defaulted.
863 : * Use DGNUpdateElemCore() on the element before writing to set these values.
864 : *
865 : * NOTE: There are restrictions on the nPointCount for some elements. For
866 : * instance, DGNT_LINE can only have 2 points. Maximum element size
867 : * precludes very large numbers of points.
868 : *
869 : * @param hDGN the file on which the element will eventually be written.
870 : * @param nType the type of the element to be created. It must be one of
871 : * DGNT_LINE, DGNT_LINE_STRING, DGNT_SHAPE, DGNT_CURVE or DGNT_BSPLINE_POLE.
872 : * @param nPointCount the number of points in the pasVertices list.
873 : * @param pasVertices the list of points to be written.
874 : *
875 : * @return the new element (a DGNElemMultiPoint structure) or NULL on failure.
876 : */
877 :
878 4 : DGNElemCore *DGNCreateMultiPointElem( DGNHandle hDGN, int nType,
879 : int nPointCount, DGNPoint *pasVertices )
880 :
881 : {
882 : DGNElemMultiPoint *psMP;
883 : DGNElemCore *psCore;
884 4 : DGNInfo *psDGN = (DGNInfo *) hDGN;
885 : int i;
886 : DGNPoint sMin, sMax;
887 :
888 : CPLAssert( nType == DGNT_LINE
889 : || nType == DGNT_LINE_STRING
890 : || nType == DGNT_SHAPE
891 : || nType == DGNT_CURVE
892 4 : || nType == DGNT_BSPLINE_POLE );
893 :
894 4 : DGNLoadTCB( hDGN );
895 :
896 : /* -------------------------------------------------------------------- */
897 : /* Is this too many vertices to write to a single element? */
898 : /* -------------------------------------------------------------------- */
899 4 : if( nPointCount > 101 )
900 : {
901 : CPLError( CE_Failure, CPLE_ElementTooBig,
902 : "Attempt to create %s element with %d points failed.\n"
903 : "Element would be too large.",
904 0 : DGNTypeToName( nType ), nPointCount );
905 0 : return NULL;
906 : }
907 :
908 : /* -------------------------------------------------------------------- */
909 : /* Allocate element. */
910 : /* -------------------------------------------------------------------- */
911 : psMP = (DGNElemMultiPoint *)
912 : CPLCalloc( sizeof(DGNElemMultiPoint)
913 4 : + sizeof(DGNPoint) * (nPointCount-2), 1 );
914 4 : psCore = &(psMP->core);
915 :
916 4 : DGNInitializeElemCore( hDGN, psCore );
917 4 : psCore->stype = DGNST_MULTIPOINT;
918 4 : psCore->type = nType;
919 :
920 : /* -------------------------------------------------------------------- */
921 : /* Set multipoint specific information in the structure. */
922 : /* -------------------------------------------------------------------- */
923 4 : psMP->num_vertices = nPointCount;
924 4 : memcpy( psMP->vertices + 0, pasVertices, sizeof(DGNPoint) * nPointCount );
925 :
926 : /* -------------------------------------------------------------------- */
927 : /* Setup Raw data for the multipoint section. */
928 : /* -------------------------------------------------------------------- */
929 4 : if( nType == DGNT_LINE )
930 : {
931 0 : CPLAssert( nPointCount == 2 );
932 :
933 0 : psCore->raw_bytes = 36 + psDGN->dimension* 4 * nPointCount;
934 :
935 0 : psCore->raw_data = (unsigned char*) CPLCalloc(psCore->raw_bytes,1);
936 :
937 : DGNInverseTransformPointToInt( psDGN, pasVertices + 0,
938 0 : psCore->raw_data + 36 );
939 : DGNInverseTransformPointToInt( psDGN, pasVertices + 1,
940 : psCore->raw_data + 36
941 0 : + psDGN->dimension * 4 );
942 : }
943 : else
944 : {
945 4 : CPLAssert( nPointCount >= 2 );
946 :
947 4 : psCore->raw_bytes = 38 + psDGN->dimension * 4 * nPointCount;
948 4 : psCore->raw_data = (unsigned char*) CPLCalloc(psCore->raw_bytes,1);
949 :
950 4 : psCore->raw_data[36] = (unsigned char) (nPointCount % 256);
951 4 : psCore->raw_data[37] = (unsigned char) (nPointCount/256);
952 :
953 85 : for( i = 0; i < nPointCount; i++ )
954 : DGNInverseTransformPointToInt( psDGN, pasVertices + i,
955 : psCore->raw_data + 38
956 81 : + psDGN->dimension * i * 4 );
957 : }
958 :
959 : /* -------------------------------------------------------------------- */
960 : /* Set the core raw data, including the bounds. */
961 : /* -------------------------------------------------------------------- */
962 4 : DGNUpdateElemCoreExtended( hDGN, psCore );
963 :
964 4 : sMin = sMax = pasVertices[0];
965 81 : for( i = 1; i < nPointCount; i++ )
966 : {
967 77 : sMin.x = MIN(pasVertices[i].x,sMin.x);
968 77 : sMin.y = MIN(pasVertices[i].y,sMin.y);
969 77 : sMin.z = MIN(pasVertices[i].z,sMin.z);
970 77 : sMax.x = MAX(pasVertices[i].x,sMax.x);
971 77 : sMax.y = MAX(pasVertices[i].y,sMax.y);
972 77 : sMax.z = MAX(pasVertices[i].z,sMax.z);
973 : }
974 :
975 4 : DGNWriteBounds( psDGN, psCore, &sMin, &sMax );
976 :
977 4 : return psCore;
978 : }
979 :
980 : /************************************************************************/
981 : /* DGNCreateArcElem2D() */
982 : /************************************************************************/
983 :
984 : DGNElemCore *
985 0 : DGNCreateArcElem2D( DGNHandle hDGN, int nType,
986 : double dfOriginX, double dfOriginY,
987 : double dfPrimaryAxis, double dfSecondaryAxis,
988 : double dfRotation,
989 : double dfStartAngle, double dfSweepAngle )
990 :
991 : {
992 : return DGNCreateArcElem( hDGN, nType, dfOriginX, dfOriginY, 0.0,
993 : dfPrimaryAxis, dfSecondaryAxis,
994 : dfStartAngle, dfSweepAngle,
995 0 : dfRotation, NULL );
996 : }
997 :
998 : /************************************************************************/
999 : /* DGNCreateArcElem() */
1000 : /************************************************************************/
1001 :
1002 : /**
1003 : * Create Arc or Ellipse element.
1004 : *
1005 : * Create a new 2D or 3D arc or ellipse element. The start angle, and sweep
1006 : * angle are ignored for DGNT_ELLIPSE but used for DGNT_ARC.
1007 : *
1008 : * The newly created element will still need to be written to file using
1009 : * DGNWriteElement(). Also the level and other core values will be defaulted.
1010 : * Use DGNUpdateElemCore() on the element before writing to set these values.
1011 : *
1012 : * @param hDGN the DGN file on which the element will eventually be written.
1013 : * @param nType either DGNT_ELLIPSE or DGNT_ARC to select element type.
1014 : * @param dfOriginX the origin (center of rotation) of the arc (X).
1015 : * @param dfOriginY the origin (center of rotation) of the arc (Y).
1016 : * @param dfOriginZ the origin (center of rotation) of the arc (Y).
1017 : * @param dfPrimaryAxis the length of the primary axis.
1018 : * @param dfSecondaryAxis the length of the secondary axis.
1019 : * @param dfStartAngle start angle, degrees counterclockwise of primary axis.
1020 : * @param dfSweepAngle sweep angle, degrees
1021 : * @param dfRotation Counterclockwise rotation in degrees.
1022 : * @param panQuaternion 3D orientation quaternion (NULL to use rotation).
1023 : *
1024 : * @return the new element (DGNElemArc) or NULL on failure.
1025 : */
1026 :
1027 : DGNElemCore *
1028 0 : DGNCreateArcElem( DGNHandle hDGN, int nType,
1029 : double dfOriginX, double dfOriginY, double dfOriginZ,
1030 : double dfPrimaryAxis, double dfSecondaryAxis,
1031 : double dfStartAngle, double dfSweepAngle,
1032 : double dfRotation, int *panQuaternion )
1033 :
1034 : {
1035 : DGNElemArc *psArc;
1036 : DGNElemCore *psCore;
1037 0 : DGNInfo *psDGN = (DGNInfo *) hDGN;
1038 : DGNPoint sMin, sMax, sOrigin;
1039 : GInt32 nAngle;
1040 :
1041 0 : CPLAssert( nType == DGNT_ARC || nType == DGNT_ELLIPSE );
1042 :
1043 0 : DGNLoadTCB( hDGN );
1044 :
1045 : /* -------------------------------------------------------------------- */
1046 : /* Allocate element. */
1047 : /* -------------------------------------------------------------------- */
1048 0 : psArc = (DGNElemArc *) CPLCalloc( sizeof(DGNElemArc), 1 );
1049 0 : psCore = &(psArc->core);
1050 :
1051 0 : DGNInitializeElemCore( hDGN, psCore );
1052 0 : psCore->stype = DGNST_ARC;
1053 0 : psCore->type = nType;
1054 :
1055 : /* -------------------------------------------------------------------- */
1056 : /* Set arc specific information in the structure. */
1057 : /* -------------------------------------------------------------------- */
1058 0 : sOrigin.x = dfOriginX;
1059 0 : sOrigin.y = dfOriginY;
1060 0 : sOrigin.z = dfOriginZ;
1061 :
1062 0 : psArc->origin = sOrigin;
1063 0 : psArc->primary_axis = dfPrimaryAxis;
1064 0 : psArc->secondary_axis = dfSecondaryAxis;
1065 0 : memset( psArc->quat, 0, sizeof(int) * 4 );
1066 0 : psArc->startang = dfStartAngle;
1067 0 : psArc->sweepang = dfSweepAngle;
1068 :
1069 0 : psArc->rotation = dfRotation;
1070 0 : if( panQuaternion == NULL )
1071 : {
1072 0 : DGNRotationToQuaternion( dfRotation, psArc->quat );
1073 : }
1074 : else
1075 : {
1076 0 : memcpy( psArc->quat, panQuaternion, sizeof(long)*4 );
1077 : }
1078 :
1079 : /* -------------------------------------------------------------------- */
1080 : /* Setup Raw data for the arc section. */
1081 : /* -------------------------------------------------------------------- */
1082 0 : if( nType == DGNT_ARC )
1083 : {
1084 : double dfScaledAxis;
1085 :
1086 0 : if( psDGN->dimension == 3 )
1087 0 : psCore->raw_bytes = 100;
1088 : else
1089 0 : psCore->raw_bytes = 80;
1090 0 : psCore->raw_data = (unsigned char*) CPLCalloc(psCore->raw_bytes,1);
1091 :
1092 : /* start angle */
1093 0 : nAngle = (int) (dfStartAngle * 360000.0);
1094 0 : DGN_WRITE_INT32( nAngle, psCore->raw_data + 36 );
1095 :
1096 : /* sweep angle */
1097 0 : if( dfSweepAngle < 0.0 )
1098 : {
1099 0 : nAngle = (int) (ABS(dfSweepAngle) * 360000.0);
1100 0 : nAngle |= 0x80000000;
1101 : }
1102 0 : else if( dfSweepAngle > 364.9999 )
1103 : {
1104 0 : nAngle = 0;
1105 : }
1106 : else
1107 : {
1108 0 : nAngle = (int) (dfSweepAngle * 360000.0);
1109 : }
1110 0 : DGN_WRITE_INT32( nAngle, psCore->raw_data + 40 );
1111 :
1112 : /* axes */
1113 0 : dfScaledAxis = dfPrimaryAxis / psDGN->scale;
1114 0 : memcpy( psCore->raw_data + 44, &dfScaledAxis, 8 );
1115 0 : IEEE2DGNDouble( psCore->raw_data + 44 );
1116 :
1117 0 : dfScaledAxis = dfSecondaryAxis / psDGN->scale;
1118 0 : memcpy( psCore->raw_data + 52, &dfScaledAxis, 8 );
1119 0 : IEEE2DGNDouble( psCore->raw_data + 52 );
1120 :
1121 0 : if( psDGN->dimension == 3 )
1122 : {
1123 : /* quaternion */
1124 0 : DGN_WRITE_INT32( psArc->quat[0], psCore->raw_data + 60 );
1125 0 : DGN_WRITE_INT32( psArc->quat[1], psCore->raw_data + 64 );
1126 0 : DGN_WRITE_INT32( psArc->quat[2], psCore->raw_data + 68 );
1127 0 : DGN_WRITE_INT32( psArc->quat[3], psCore->raw_data + 72 );
1128 :
1129 : /* origin */
1130 0 : DGNInverseTransformPoint( psDGN, &sOrigin );
1131 0 : memcpy( psCore->raw_data + 76, &(sOrigin.x), 8 );
1132 0 : memcpy( psCore->raw_data + 84, &(sOrigin.y), 8 );
1133 0 : memcpy( psCore->raw_data + 92, &(sOrigin.z), 8 );
1134 0 : IEEE2DGNDouble( psCore->raw_data + 76 );
1135 0 : IEEE2DGNDouble( psCore->raw_data + 84 );
1136 0 : IEEE2DGNDouble( psCore->raw_data + 92 );
1137 : }
1138 : else
1139 : {
1140 : /* rotation */
1141 0 : nAngle = (int) (dfRotation * 360000.0);
1142 0 : DGN_WRITE_INT32( nAngle, psCore->raw_data + 60 );
1143 :
1144 : /* origin */
1145 0 : DGNInverseTransformPoint( psDGN, &sOrigin );
1146 0 : memcpy( psCore->raw_data + 64, &(sOrigin.x), 8 );
1147 0 : memcpy( psCore->raw_data + 72, &(sOrigin.y), 8 );
1148 0 : IEEE2DGNDouble( psCore->raw_data + 64 );
1149 0 : IEEE2DGNDouble( psCore->raw_data + 72 );
1150 : }
1151 : }
1152 :
1153 : /* -------------------------------------------------------------------- */
1154 : /* Setup Raw data for the ellipse section. */
1155 : /* -------------------------------------------------------------------- */
1156 : else
1157 : {
1158 : double dfScaledAxis;
1159 :
1160 0 : if( psDGN->dimension == 3 )
1161 0 : psCore->raw_bytes = 92;
1162 : else
1163 0 : psCore->raw_bytes = 72;
1164 0 : psCore->raw_data = (unsigned char*) CPLCalloc(psCore->raw_bytes,1);
1165 :
1166 : /* axes */
1167 0 : dfScaledAxis = dfPrimaryAxis / psDGN->scale;
1168 0 : memcpy( psCore->raw_data + 36, &dfScaledAxis, 8 );
1169 0 : IEEE2DGNDouble( psCore->raw_data + 36 );
1170 :
1171 0 : dfScaledAxis = dfSecondaryAxis / psDGN->scale;
1172 0 : memcpy( psCore->raw_data + 44, &dfScaledAxis, 8 );
1173 0 : IEEE2DGNDouble( psCore->raw_data + 44 );
1174 :
1175 0 : if( psDGN->dimension == 3 )
1176 : {
1177 : /* quaternion */
1178 0 : DGN_WRITE_INT32( psArc->quat[0], psCore->raw_data + 52 );
1179 0 : DGN_WRITE_INT32( psArc->quat[1], psCore->raw_data + 56 );
1180 0 : DGN_WRITE_INT32( psArc->quat[2], psCore->raw_data + 60 );
1181 0 : DGN_WRITE_INT32( psArc->quat[3], psCore->raw_data + 64 );
1182 :
1183 : /* origin */
1184 0 : DGNInverseTransformPoint( psDGN, &sOrigin );
1185 0 : memcpy( psCore->raw_data + 68, &(sOrigin.x), 8 );
1186 0 : memcpy( psCore->raw_data + 76, &(sOrigin.y), 8 );
1187 0 : memcpy( psCore->raw_data + 84, &(sOrigin.z), 8 );
1188 0 : IEEE2DGNDouble( psCore->raw_data + 68 );
1189 0 : IEEE2DGNDouble( psCore->raw_data + 76 );
1190 0 : IEEE2DGNDouble( psCore->raw_data + 84 );
1191 : }
1192 : else
1193 : {
1194 : /* rotation */
1195 0 : nAngle = (int) (dfRotation * 360000.0);
1196 0 : DGN_WRITE_INT32( nAngle, psCore->raw_data + 52 );
1197 :
1198 : /* origin */
1199 0 : DGNInverseTransformPoint( psDGN, &sOrigin );
1200 0 : memcpy( psCore->raw_data + 56, &(sOrigin.x), 8 );
1201 0 : memcpy( psCore->raw_data + 64, &(sOrigin.y), 8 );
1202 0 : IEEE2DGNDouble( psCore->raw_data + 56 );
1203 0 : IEEE2DGNDouble( psCore->raw_data + 64 );
1204 : }
1205 :
1206 0 : psArc->startang = 0.0;
1207 0 : psArc->sweepang = 360.0;
1208 : }
1209 :
1210 : /* -------------------------------------------------------------------- */
1211 : /* Set the core raw data, including the bounds. */
1212 : /* -------------------------------------------------------------------- */
1213 0 : DGNUpdateElemCoreExtended( hDGN, psCore );
1214 :
1215 0 : sMin.x = dfOriginX - MAX(dfPrimaryAxis,dfSecondaryAxis);
1216 0 : sMin.y = dfOriginY - MAX(dfPrimaryAxis,dfSecondaryAxis);
1217 0 : sMin.z = dfOriginZ - MAX(dfPrimaryAxis,dfSecondaryAxis);
1218 0 : sMax.x = dfOriginX + MAX(dfPrimaryAxis,dfSecondaryAxis);
1219 0 : sMax.y = dfOriginY + MAX(dfPrimaryAxis,dfSecondaryAxis);
1220 0 : sMax.z = dfOriginZ + MAX(dfPrimaryAxis,dfSecondaryAxis);
1221 :
1222 0 : DGNWriteBounds( psDGN, psCore, &sMin, &sMax );
1223 :
1224 0 : return psCore;
1225 : }
1226 :
1227 : /************************************************************************/
1228 : /* DGNCreateConeElem() */
1229 : /************************************************************************/
1230 :
1231 : /**
1232 : * Create Cone element.
1233 : *
1234 : * Create a new 3D cone element.
1235 : *
1236 : * The newly created element will still need to be written to file using
1237 : * DGNWriteElement(). Also the level and other core values will be defaulted.
1238 : * Use DGNUpdateElemCore() on the element before writing to set these values.
1239 : *
1240 : * @param hDGN the DGN file on which the element will eventually be written.
1241 : * @param dfCenter1X the center of the first bounding circle (X).
1242 : * @param dfCenter1Y the center of the first bounding circle (Y).
1243 : * @param dfCenter1Z the center of the first bounding circle (Z).
1244 : * @param dfRadius1 the radius of the first bounding circle.
1245 : * @param dfCenter2X the center of the second bounding circle (X).
1246 : * @param dfCenter2Y the center of the second bounding circle (Y).
1247 : * @param dfCenter2Z the center of the second bounding circle (Z).
1248 : * @param dfRadius2 the radius of the second bounding circle.
1249 : * @param panQuaternion 3D orientation quaternion (NULL for default orientation - circles parallel to the X-Y plane).
1250 : *
1251 : * @return the new element (DGNElemCone) or NULL on failure.
1252 : */
1253 :
1254 : DGNElemCore *
1255 0 : DGNCreateConeElem( DGNHandle hDGN,
1256 : double dfCenter_1X, double dfCenter_1Y,
1257 : double dfCenter_1Z, double dfRadius_1,
1258 : double dfCenter_2X, double dfCenter_2Y,
1259 : double dfCenter_2Z, double dfRadius_2,
1260 : int *panQuaternion )
1261 : {
1262 : DGNElemCone *psCone;
1263 : DGNElemCore *psCore;
1264 0 : DGNInfo *psDGN = (DGNInfo *) hDGN;
1265 : DGNPoint sMin, sMax, sCenter_1, sCenter_2;
1266 : double dfScaledRadius;
1267 :
1268 0 : DGNLoadTCB( hDGN );
1269 :
1270 : /* -------------------------------------------------------------------- */
1271 : /* Allocate element. */
1272 : /* -------------------------------------------------------------------- */
1273 0 : psCone = (DGNElemCone *) CPLCalloc( sizeof(DGNElemCone), 1 );
1274 0 : psCore = &(psCone->core);
1275 :
1276 0 : DGNInitializeElemCore( hDGN, psCore );
1277 0 : psCore->stype = DGNST_CONE;
1278 0 : psCore->type = DGNT_CONE;
1279 :
1280 : /* -------------------------------------------------------------------- */
1281 : /* Set cone specific information in the structure. */
1282 : /* -------------------------------------------------------------------- */
1283 0 : sCenter_1.x = dfCenter_1X;
1284 0 : sCenter_1.y = dfCenter_1Y;
1285 0 : sCenter_1.z = dfCenter_1Z;
1286 0 : sCenter_2.x = dfCenter_2X;
1287 0 : sCenter_2.y = dfCenter_2Y;
1288 0 : sCenter_2.z = dfCenter_2Z;
1289 0 : psCone->center_1 = sCenter_1;
1290 0 : psCone->center_2 = sCenter_2;
1291 0 : psCone->radius_1 = dfRadius_1;
1292 0 : psCone->radius_2 = dfRadius_2;
1293 :
1294 0 : memset( psCone->quat, 0, sizeof(int) * 4 );
1295 0 : if( panQuaternion != NULL )
1296 : {
1297 0 : memcpy( psCone->quat, panQuaternion, sizeof(long)*4 );
1298 : }
1299 : else {
1300 0 : psCone->quat[0] = 1 << 31;
1301 0 : psCone->quat[1] = 0;
1302 0 : psCone->quat[2] = 0;
1303 0 : psCone->quat[3] = 0;
1304 : }
1305 :
1306 : /* -------------------------------------------------------------------- */
1307 : /* Setup Raw data for the cone. */
1308 : /* -------------------------------------------------------------------- */
1309 0 : psCore->raw_bytes = 118;
1310 0 : psCore->raw_data = (unsigned char*) CPLCalloc(psCore->raw_bytes,1);
1311 :
1312 : /* unknown data */
1313 0 : psCore->raw_data[36] = 0;
1314 0 : psCore->raw_data[37] = 0;
1315 :
1316 : /* quaternion */
1317 0 : DGN_WRITE_INT32( psCone->quat[0], psCore->raw_data + 38 );
1318 0 : DGN_WRITE_INT32( psCone->quat[1], psCore->raw_data + 42 );
1319 0 : DGN_WRITE_INT32( psCone->quat[2], psCore->raw_data + 46 );
1320 0 : DGN_WRITE_INT32( psCone->quat[3], psCore->raw_data + 50 );
1321 :
1322 : /* center_1 */
1323 0 : DGNInverseTransformPoint( psDGN, &sCenter_1 );
1324 0 : memcpy( psCore->raw_data + 54, &sCenter_1.x, 8 );
1325 0 : memcpy( psCore->raw_data + 62, &sCenter_1.y, 8 );
1326 0 : memcpy( psCore->raw_data + 70, &sCenter_1.z, 8 );
1327 0 : IEEE2DGNDouble( psCore->raw_data + 54 );
1328 0 : IEEE2DGNDouble( psCore->raw_data + 62 );
1329 0 : IEEE2DGNDouble( psCore->raw_data + 70 );
1330 :
1331 : /* radius_1 */
1332 0 : dfScaledRadius = psCone->radius_1 / psDGN->scale;
1333 0 : memcpy( psCore->raw_data + 78, &dfScaledRadius, 8 );
1334 0 : IEEE2DGNDouble( psCore->raw_data + 78 );
1335 :
1336 : /* center_2 */
1337 0 : DGNInverseTransformPoint( psDGN, &sCenter_2 );
1338 0 : memcpy( psCore->raw_data + 86, &sCenter_2.x, 8 );
1339 0 : memcpy( psCore->raw_data + 94, &sCenter_2.y, 8 );
1340 0 : memcpy( psCore->raw_data + 102, &sCenter_2.z, 8 );
1341 0 : IEEE2DGNDouble( psCore->raw_data + 86 );
1342 0 : IEEE2DGNDouble( psCore->raw_data + 94 );
1343 0 : IEEE2DGNDouble( psCore->raw_data + 102 );
1344 :
1345 : /* radius_2 */
1346 0 : dfScaledRadius = psCone->radius_2 / psDGN->scale;
1347 0 : memcpy( psCore->raw_data + 110, &dfScaledRadius, 8 );
1348 0 : IEEE2DGNDouble( psCore->raw_data + 110 );
1349 :
1350 : /* -------------------------------------------------------------------- */
1351 : /* Set the core raw data, including the bounds. */
1352 : /* -------------------------------------------------------------------- */
1353 0 : DGNUpdateElemCoreExtended( hDGN, psCore );
1354 :
1355 : //FIXME: Calculate bounds. Do we need to take the quaternion into account?
1356 : // kintel 20030819
1357 :
1358 : // Old implementation attempt:
1359 : // What if center_1.z > center_2.z ?
1360 : // double largestRadius =
1361 : // psCone->radius_1>psCone->radius_2?psCone->radius_1:psCone->radius_2;
1362 : // sMin.x = psCone->center_1.x-largestRadius;
1363 : // sMin.y = psCone->center_1.y-largestRadius;
1364 : // sMin.z = psCone->center_1.z;
1365 : // sMax.x = psCone->center_2.x+largestRadius;
1366 : // sMax.y = psCone->center_2.y+largestRadius;
1367 : // sMax.z = psCone->center_2.z;
1368 :
1369 0 : DGNWriteBounds( psDGN, psCore, &sMin, &sMax );
1370 :
1371 0 : return psCore;
1372 : }
1373 :
1374 : /************************************************************************/
1375 : /* DGNCreateTextElem() */
1376 : /************************************************************************/
1377 :
1378 : /**
1379 : * Create text element.
1380 : *
1381 : * The newly created element will still need to be written to file using
1382 : * DGNWriteElement(). Also the level and other core values will be defaulted.
1383 : * Use DGNUpdateElemCore() on the element before writing to set these values.
1384 : *
1385 : * @param hDGN the file on which the element will eventually be written.
1386 : * @param pszText the string of text.
1387 : * @param nFontId microstation font id for the text. 1 may be used as default.
1388 : * @param nJustification text justification. One of DGNJ_LEFT_TOP,
1389 : * DGNJ_LEFT_CENTER, DGNJ_LEFT_BOTTOM, DGNJ_CENTER_TOP, DGNJ_CENTER_CENTER,
1390 : * DGNJ_CENTER_BOTTOM, DGNJ_RIGHT_TOP, DGNJ_RIGHT_CENTER, DGNJ_RIGHT_BOTTOM.
1391 : * @param dfLengthMult character width in master units.
1392 : * @param dfHeightMult character height in master units.
1393 : * @param dfRotation Counterclockwise text rotation in degrees.
1394 : * @param panQuaternion 3D orientation quaternion (NULL to use rotation).
1395 : * @param dfOriginX Text origin (X).
1396 : * @param dfOriginY Text origin (Y).
1397 : * @param dfOriginZ Text origin (Z).
1398 : *
1399 : * @return the new element (DGNElemText) or NULL on failure.
1400 : */
1401 :
1402 : DGNElemCore *
1403 1 : DGNCreateTextElem( DGNHandle hDGN, const char *pszText,
1404 : int nFontId, int nJustification,
1405 : double dfLengthMult, double dfHeightMult,
1406 : double dfRotation, int *panQuaternion,
1407 : double dfOriginX, double dfOriginY, double dfOriginZ )
1408 :
1409 : {
1410 : DGNElemText *psText;
1411 : DGNElemCore *psCore;
1412 1 : DGNInfo *psDGN = (DGNInfo *) hDGN;
1413 : DGNPoint sMin, sMax, sLowLeft, sLowRight, sUpLeft, sUpRight;
1414 : GInt32 nIntValue, nBase;
1415 : double length, height, diagonal;
1416 :
1417 1 : DGNLoadTCB( hDGN );
1418 :
1419 : /* -------------------------------------------------------------------- */
1420 : /* Allocate element. */
1421 : /* -------------------------------------------------------------------- */
1422 : psText = (DGNElemText *)
1423 1 : CPLCalloc( sizeof(DGNElemText)+strlen(pszText), 1 );
1424 1 : psCore = &(psText->core);
1425 :
1426 1 : DGNInitializeElemCore( hDGN, psCore );
1427 1 : psCore->stype = DGNST_TEXT;
1428 1 : psCore->type = DGNT_TEXT;
1429 :
1430 : /* -------------------------------------------------------------------- */
1431 : /* Set arc specific information in the structure. */
1432 : /* -------------------------------------------------------------------- */
1433 1 : psText->font_id = nFontId;
1434 1 : psText->justification = nJustification;
1435 1 : psText->length_mult = dfLengthMult;
1436 1 : psText->height_mult = dfHeightMult;
1437 1 : psText->rotation = dfRotation;
1438 1 : psText->origin.x = dfOriginX;
1439 1 : psText->origin.y = dfOriginY;
1440 1 : psText->origin.z = dfOriginZ;
1441 1 : strcpy( psText->string, pszText );
1442 :
1443 : /* -------------------------------------------------------------------- */
1444 : /* Setup Raw data for the text specific portion. */
1445 : /* -------------------------------------------------------------------- */
1446 1 : if( psDGN->dimension == 2 )
1447 1 : psCore->raw_bytes = 60 + strlen(pszText);
1448 : else
1449 0 : psCore->raw_bytes = 76 + strlen(pszText);
1450 :
1451 1 : psCore->raw_bytes += (psCore->raw_bytes % 2);
1452 1 : psCore->raw_data = (unsigned char*) CPLCalloc(psCore->raw_bytes,1);
1453 :
1454 1 : psCore->raw_data[36] = (unsigned char) nFontId;
1455 1 : psCore->raw_data[37] = (unsigned char) nJustification;
1456 :
1457 1 : nIntValue = (int) (dfLengthMult * 1000.0 / (psDGN->scale * 6.0) + 0.5);
1458 1 : DGN_WRITE_INT32( nIntValue, psCore->raw_data + 38 );
1459 :
1460 1 : nIntValue = (int) (dfHeightMult * 1000.0 / (psDGN->scale * 6.0) + 0.5);
1461 1 : DGN_WRITE_INT32( nIntValue, psCore->raw_data + 42 );
1462 :
1463 1 : if( psDGN->dimension == 2 )
1464 : {
1465 1 : nIntValue = (int) (dfRotation * 360000.0);
1466 1 : DGN_WRITE_INT32( nIntValue, psCore->raw_data + 46 );
1467 :
1468 : DGNInverseTransformPointToInt( psDGN, &(psText->origin),
1469 1 : psCore->raw_data + 50 );
1470 :
1471 1 : nBase = 58;
1472 : }
1473 : else
1474 : {
1475 : int anQuaternion[4];
1476 :
1477 0 : if( panQuaternion == NULL )
1478 0 : DGNRotationToQuaternion( dfRotation, anQuaternion );
1479 : else
1480 0 : memcpy( anQuaternion, panQuaternion, sizeof(int) * 4 );
1481 :
1482 0 : DGN_WRITE_INT32( anQuaternion[0], psCore->raw_data + 46 );
1483 0 : DGN_WRITE_INT32( anQuaternion[1], psCore->raw_data + 50 );
1484 0 : DGN_WRITE_INT32( anQuaternion[2], psCore->raw_data + 54 );
1485 0 : DGN_WRITE_INT32( anQuaternion[3], psCore->raw_data + 58 );
1486 :
1487 : DGNInverseTransformPointToInt( psDGN, &(psText->origin),
1488 0 : psCore->raw_data + 62 );
1489 0 : nBase = 74;
1490 : }
1491 :
1492 1 : psCore->raw_data[nBase] = (unsigned char) strlen(pszText);
1493 1 : psCore->raw_data[nBase+1] = 0; /* edflds? */
1494 1 : memcpy( psCore->raw_data + nBase+2, pszText, strlen(pszText) );
1495 :
1496 : /* -------------------------------------------------------------------- */
1497 : /* Set the core raw data, including the bounds. */
1498 : /* */
1499 : /* Code contributed by Mart Kelder. */
1500 : /* -------------------------------------------------------------------- */
1501 1 : DGNUpdateElemCoreExtended( hDGN, psCore );
1502 :
1503 : //calculate bounds if rotation is 0
1504 1 : sMin.x = dfOriginX;
1505 1 : sMin.y = dfOriginY;
1506 1 : sMin.z = 0.0;
1507 1 : sMax.x = dfOriginX + dfLengthMult * strlen(pszText);
1508 1 : sMax.y = dfOriginY + dfHeightMult;
1509 1 : sMax.z = 0.0;
1510 :
1511 : //calculate rotated bounding box coordinates
1512 1 : length = sMax.x-sMin.x;
1513 1 : height = sMax.y-sMin.y;
1514 1 : diagonal=sqrt(length*length+height*height);
1515 1 : sLowLeft.x=sMin.x;
1516 1 : sLowLeft.y=sMin.y;
1517 1 : sLowRight.x=sMin.x+cos(psText->rotation*PI/180.0)*length;
1518 1 : sLowRight.y=sMin.y+sin(psText->rotation*PI/180.0)*length;
1519 1 : sUpRight.x=sMin.x+cos((psText->rotation*PI/180.0)+atan(height/length))*diagonal;
1520 1 : sUpRight.y=sMin.y+sin((psText->rotation*PI/180.0)+atan(height/length))*diagonal;
1521 1 : sUpLeft.x=sMin.x+cos((psText->rotation+90.0)*PI/180.0)*height;
1522 1 : sUpLeft.y=sMin.y+sin((psText->rotation+90.0)*PI/180.0)*height;
1523 :
1524 : //calculate new values for bounding box
1525 1 : sMin.x=MIN(sLowLeft.x,MIN(sLowRight.x,MIN(sUpLeft.x,sUpRight.x)));
1526 1 : sMin.y=MIN(sLowLeft.y,MIN(sLowRight.y,MIN(sUpLeft.y,sUpRight.y)));
1527 1 : sMax.x=MAX(sLowLeft.x,MAX(sLowRight.x,MAX(sUpLeft.x,sUpRight.x)));
1528 1 : sMax.y=MAX(sLowLeft.y,MAX(sLowRight.y,MAX(sUpLeft.y,sUpRight.y)));
1529 1 : sMin.x = dfOriginX - dfLengthMult * strlen(pszText);
1530 1 : sMin.y = dfOriginY - dfHeightMult;
1531 1 : sMin.z = 0.0;
1532 1 : sMax.x = dfOriginX + dfLengthMult * strlen(pszText);
1533 1 : sMax.y = dfOriginY + dfHeightMult;
1534 1 : sMax.z = 0.0;
1535 :
1536 1 : DGNWriteBounds( psDGN, psCore, &sMin, &sMax );
1537 :
1538 1 : return psCore;
1539 : }
1540 :
1541 : /************************************************************************/
1542 : /* DGNCreateColorTableElem() */
1543 : /************************************************************************/
1544 :
1545 : /**
1546 : * Create color table element.
1547 : *
1548 : * Creates a color table element with the indicated color table.
1549 : *
1550 : * Note that color table elements are actally of type DGNT_GROUP_DATA(5)
1551 : * and always on level 1. Do not alter the level with DGNUpdateElemCore()
1552 : * or the element will essentially be corrupt.
1553 : *
1554 : * The newly created element will still need to be written to file using
1555 : * DGNWriteElement(). Also the level and other core values will be defaulted.
1556 : * Use DGNUpdateElemCore() on the element before writing to set these values.
1557 : *
1558 : * @param hDGN the file to which the element will eventually be written.
1559 : * @param nScreenFlag the screen to which the color table applies
1560 : * (0 = left, 1 = right).
1561 : * @param abyColorInfo[8][3] array of 256 color entries. The first is
1562 : * the background color.
1563 : *
1564 : * @return the new element (DGNElemColorTable) or NULL on failure.
1565 : */
1566 :
1567 :
1568 : DGNElemCore *
1569 0 : DGNCreateColorTableElem( DGNHandle hDGN, int nScreenFlag,
1570 : GByte abyColorInfo[256][3] )
1571 :
1572 : {
1573 : DGNElemColorTable *psCT;
1574 : DGNElemCore *psCore;
1575 :
1576 : /* -------------------------------------------------------------------- */
1577 : /* Allocate element. */
1578 : /* -------------------------------------------------------------------- */
1579 0 : psCT = (DGNElemColorTable *) CPLCalloc( sizeof(DGNElemColorTable), 1 );
1580 0 : psCore = &(psCT->core);
1581 :
1582 0 : DGNInitializeElemCore( hDGN, psCore );
1583 0 : psCore->stype = DGNST_COLORTABLE;
1584 0 : psCore->type = DGNT_GROUP_DATA;
1585 0 : psCore->level = DGN_GDL_COLOR_TABLE;
1586 :
1587 : /* -------------------------------------------------------------------- */
1588 : /* Set colortable specific information in the structure. */
1589 : /* -------------------------------------------------------------------- */
1590 0 : psCT->screen_flag = nScreenFlag;
1591 0 : memcpy( psCT->color_info, abyColorInfo, 768 );
1592 :
1593 : /* -------------------------------------------------------------------- */
1594 : /* Setup Raw data for the color table specific portion. */
1595 : /* -------------------------------------------------------------------- */
1596 0 : psCore->raw_bytes = 806; /* FIXME: this is invalid : 806 < 41 + 783 (see below lines) */
1597 0 : psCore->raw_data = (unsigned char*) CPLCalloc(psCore->raw_bytes,1);
1598 :
1599 0 : psCore->raw_data[36] = (unsigned char) (nScreenFlag % 256);
1600 0 : psCore->raw_data[37] = (unsigned char) (nScreenFlag / 256);
1601 :
1602 0 : memcpy( psCore->raw_data + 38, abyColorInfo[255], 3 );
1603 0 : memcpy( psCore->raw_data + 41, abyColorInfo, 783 );
1604 :
1605 : /* -------------------------------------------------------------------- */
1606 : /* Set the core raw data. */
1607 : /* -------------------------------------------------------------------- */
1608 0 : DGNUpdateElemCoreExtended( hDGN, psCore );
1609 :
1610 0 : return psCore;
1611 : }
1612 :
1613 : /************************************************************************/
1614 : /* DGNCreateComplexHeaderElem() */
1615 : /************************************************************************/
1616 :
1617 : /**
1618 : * Create complex chain/shape header.
1619 : *
1620 : * The newly created element will still need to be written to file using
1621 : * DGNWriteElement(). Also the level and other core values will be defaulted.
1622 : * Use DGNUpdateElemCore() on the element before writing to set these values.
1623 : *
1624 : * The nTotLength is the sum of the size of all elements in the complex
1625 : * group plus 5. The DGNCreateComplexHeaderFromGroup() can be used to build
1626 : * a complex element from the members more conveniently.
1627 : *
1628 : * @param hDGN the file on which the element will be written.
1629 : * @param nType DGNT_COMPLEX_CHAIN_HEADER or DGNT_COMPLEX_SHAPE_HEADER.
1630 : * depending on whether the list is open or closed (last point equal to last)
1631 : * or if the object represents a surface or a solid.
1632 : * @param nTotLength the value of the totlength field in the element.
1633 : * @param nNumElems the number of elements in the complex group not including
1634 : * the header element.
1635 : *
1636 : * @return the new element (DGNElemComplexHeader) or NULL on failure.
1637 : */
1638 : DGNElemCore *
1639 1 : DGNCreateComplexHeaderElem( DGNHandle hDGN, int nType,
1640 : int nTotLength, int nNumElems )
1641 : {
1642 : DGNElemComplexHeader *psCH;
1643 : DGNElemCore *psCore;
1644 1 : unsigned char abyRawZeroLinkage[8] = {0,0,0,0,0,0,0,0};
1645 :
1646 : CPLAssert( nType == DGNT_COMPLEX_CHAIN_HEADER
1647 1 : || nType == DGNT_COMPLEX_SHAPE_HEADER );
1648 :
1649 1 : DGNLoadTCB( hDGN );
1650 :
1651 : /* -------------------------------------------------------------------- */
1652 : /* Allocate element. */
1653 : /* -------------------------------------------------------------------- */
1654 : psCH = (DGNElemComplexHeader *)
1655 1 : CPLCalloc( sizeof(DGNElemComplexHeader), 1 );
1656 1 : psCore = &(psCH->core);
1657 :
1658 1 : DGNInitializeElemCore( hDGN, psCore );
1659 1 : psCore->complex = TRUE;
1660 1 : psCore->stype = DGNST_COMPLEX_HEADER;
1661 1 : psCore->type = nType;
1662 :
1663 : /* -------------------------------------------------------------------- */
1664 : /* Set complex header specific information in the structure. */
1665 : /* -------------------------------------------------------------------- */
1666 1 : psCH->totlength = nTotLength - 4;
1667 1 : psCH->numelems = nNumElems;
1668 1 : psCH->surftype = 0;
1669 1 : psCH->boundelms = 0;
1670 :
1671 : /* -------------------------------------------------------------------- */
1672 : /* Setup Raw data for the complex specific portion. */
1673 : /* -------------------------------------------------------------------- */
1674 1 : psCore->raw_bytes = 40;
1675 1 : psCore->raw_data = (unsigned char*) CPLCalloc(psCore->raw_bytes,1);
1676 :
1677 1 : psCore->raw_data[36] = (unsigned char) ((nTotLength-4) % 256);
1678 1 : psCore->raw_data[37] = (unsigned char) ((nTotLength-4) / 256);
1679 1 : psCore->raw_data[38] = (unsigned char) (nNumElems % 256);
1680 1 : psCore->raw_data[39] = (unsigned char) (nNumElems / 256);
1681 :
1682 : /* -------------------------------------------------------------------- */
1683 : /* Set the core raw data. */
1684 : /* -------------------------------------------------------------------- */
1685 1 : DGNUpdateElemCoreExtended( hDGN, psCore );
1686 :
1687 : /* -------------------------------------------------------------------- */
1688 : /* Elements have to be at least 48 bytes long, so we have to */
1689 : /* add a dummy bit of attribute data to fill out the length. */
1690 : /* -------------------------------------------------------------------- */
1691 1 : DGNAddRawAttrLink( hDGN, psCore, 8, abyRawZeroLinkage );
1692 :
1693 1 : return psCore;
1694 : }
1695 :
1696 : /************************************************************************/
1697 : /* DGNCreateComplexHeaderFromGroup() */
1698 : /************************************************************************/
1699 :
1700 : /**
1701 : * Create complex chain/shape header.
1702 : *
1703 : * This function is similar to DGNCreateComplexHeaderElem(), but it takes
1704 : * care of computing the total size of the set of elements being written,
1705 : * and collecting the bounding extents. It also takes care of some other
1706 : * convenience issues, like marking all the member elements as complex, and
1707 : * setting the level based on the level of the member elements.
1708 : *
1709 : * @param hDGN the file on which the element will be written.
1710 : * @param nType DGNT_COMPLEX_CHAIN_HEADER or DGNT_COMPLEX_SHAPE_HEADER.
1711 : * depending on whether the list is open or closed (last point equal to last)
1712 : * or if the object represents a surface or a solid.
1713 : * @param nNumElems the number of elements in the complex group not including
1714 : * the header element.
1715 : * @param papsElems array of pointers to nNumElems elements in the complex
1716 : * group. Some updates may be made to these elements.
1717 : *
1718 : * @return the new element (DGNElemComplexHeader) or NULL on failure.
1719 : */
1720 :
1721 : DGNElemCore *
1722 1 : DGNCreateComplexHeaderFromGroup( DGNHandle hDGN, int nType,
1723 : int nNumElems, DGNElemCore **papsElems )
1724 :
1725 : {
1726 1 : int nTotalLength = 5;
1727 : int i, nLevel;
1728 : DGNElemCore *psCH;
1729 1 : DGNPoint sMin = {0.0,0.0,0.0}, sMax = {0.0,0.0,0.0};
1730 :
1731 1 : DGNLoadTCB( hDGN );
1732 :
1733 1 : if( nNumElems < 1 || papsElems == NULL )
1734 : {
1735 : CPLError( CE_Failure, CPLE_AppDefined,
1736 0 : "Need at least one element to form a complex group." );
1737 0 : return NULL;
1738 : }
1739 :
1740 : /* -------------------------------------------------------------------- */
1741 : /* Collect the total size, and bounds. */
1742 : /* -------------------------------------------------------------------- */
1743 1 : nLevel = papsElems[0]->level;
1744 :
1745 3 : for( i = 0; i < nNumElems; i++ )
1746 : {
1747 : DGNPoint sThisMin, sThisMax;
1748 :
1749 2 : nTotalLength += papsElems[i]->raw_bytes / 2;
1750 :
1751 2 : papsElems[i]->complex = TRUE;
1752 2 : papsElems[i]->raw_data[0] |= 0x80;
1753 :
1754 2 : if( papsElems[i]->level != nLevel )
1755 : {
1756 : CPLError( CE_Warning, CPLE_AppDefined,
1757 0 : "Not all level values matching in a complex set group!");
1758 : }
1759 :
1760 2 : DGNGetElementExtents( hDGN, papsElems[i], &sThisMin, &sThisMax );
1761 2 : if( i == 0 )
1762 : {
1763 1 : sMin = sThisMin;
1764 1 : sMax = sThisMax;
1765 : }
1766 : else
1767 : {
1768 1 : sMin.x = MIN(sMin.x,sThisMin.x);
1769 1 : sMin.y = MIN(sMin.y,sThisMin.y);
1770 1 : sMin.z = MIN(sMin.z,sThisMin.z);
1771 1 : sMax.x = MAX(sMax.x,sThisMax.x);
1772 1 : sMax.y = MAX(sMax.y,sThisMax.y);
1773 1 : sMax.z = MAX(sMax.z,sThisMax.z);
1774 : }
1775 : }
1776 :
1777 : /* -------------------------------------------------------------------- */
1778 : /* Create the corresponding complex header. */
1779 : /* -------------------------------------------------------------------- */
1780 1 : psCH = DGNCreateComplexHeaderElem( hDGN, nType, nTotalLength, nNumElems );
1781 1 : DGNUpdateElemCore( hDGN, psCH, papsElems[0]->level, psCH->graphic_group,
1782 2 : psCH->color, psCH->weight, psCH->style );
1783 :
1784 1 : DGNWriteBounds( (DGNInfo *) hDGN, psCH, &sMin, &sMax );
1785 :
1786 1 : return psCH;
1787 : }
1788 :
1789 : /************************************************************************/
1790 : /* DGNCreateSolidHeaderElem() */
1791 : /************************************************************************/
1792 :
1793 : /**
1794 : * Create 3D solid/surface.
1795 : *
1796 : * The newly created element will still need to be written to file using
1797 : * DGNWriteElement(). Also the level and other core values will be defaulted.
1798 : * Use DGNUpdateElemCore() on the element before writing to set these values.
1799 : *
1800 : * The nTotLength is the sum of the size of all elements in the solid
1801 : * group plus 6. The DGNCreateSolidHeaderFromGroup() can be used to build
1802 : * a solid element from the members more conveniently.
1803 : *
1804 : * @param hDGN the file on which the element will be written.
1805 : * @param nType DGNT_3DSURFACE_HEADER or DGNT_3DSOLID_HEADER.
1806 : * @param nSurfType the surface/solid type, one of DGNSUT_* or DGNSOT_*.
1807 : * @param nBoundElems the number of elements in each boundary.
1808 : * @param nTotLength the value of the totlength field in the element.
1809 : * @param nNumElems the number of elements in the solid not including
1810 : * the header element.
1811 : *
1812 : * @return the new element (DGNElemComplexHeader) or NULL on failure.
1813 : */
1814 : DGNElemCore *
1815 0 : DGNCreateSolidHeaderElem( DGNHandle hDGN, int nType, int nSurfType,
1816 : int nBoundElems, int nTotLength, int nNumElems )
1817 : {
1818 : DGNElemComplexHeader *psCH;
1819 : DGNElemCore *psCore;
1820 0 : unsigned char abyRawZeroLinkage[8] = {0,0,0,0,0,0,0,0};
1821 :
1822 : CPLAssert( nType == DGNT_3DSURFACE_HEADER
1823 0 : || nType == DGNT_3DSOLID_HEADER );
1824 :
1825 0 : DGNLoadTCB( hDGN );
1826 :
1827 : /* -------------------------------------------------------------------- */
1828 : /* Allocate element. */
1829 : /* -------------------------------------------------------------------- */
1830 : psCH = (DGNElemComplexHeader *)
1831 0 : CPLCalloc( sizeof(DGNElemComplexHeader), 1 );
1832 0 : psCore = &(psCH->core);
1833 :
1834 0 : DGNInitializeElemCore( hDGN, psCore );
1835 0 : psCore->complex = TRUE;
1836 0 : psCore->stype = DGNST_COMPLEX_HEADER;
1837 0 : psCore->type = nType;
1838 :
1839 : /* -------------------------------------------------------------------- */
1840 : /* Set solid header specific information in the structure. */
1841 : /* -------------------------------------------------------------------- */
1842 0 : psCH->totlength = nTotLength - 4;
1843 0 : psCH->numelems = nNumElems;
1844 0 : psCH->surftype = nSurfType;
1845 0 : psCH->boundelms = nBoundElems;
1846 :
1847 : /* -------------------------------------------------------------------- */
1848 : /* Setup Raw data for the solid specific portion. */
1849 : /* -------------------------------------------------------------------- */
1850 0 : psCore->raw_bytes = 42;
1851 :
1852 0 : psCore->raw_data = (unsigned char*) CPLCalloc(psCore->raw_bytes,1);
1853 :
1854 0 : psCore->raw_data[36] = (unsigned char) ((nTotLength-4) % 256);
1855 0 : psCore->raw_data[37] = (unsigned char) ((nTotLength-4) / 256);
1856 0 : psCore->raw_data[38] = (unsigned char) (nNumElems % 256);
1857 0 : psCore->raw_data[39] = (unsigned char) (nNumElems / 256);
1858 0 : psCore->raw_data[40] = (unsigned char) psCH->surftype;
1859 0 : psCore->raw_data[41] = (unsigned char) psCH->boundelms - 1;
1860 :
1861 : /* -------------------------------------------------------------------- */
1862 : /* Set the core raw data. */
1863 : /* -------------------------------------------------------------------- */
1864 0 : DGNUpdateElemCoreExtended( hDGN, psCore );
1865 :
1866 : /* -------------------------------------------------------------------- */
1867 : /* Elements have to be at least 48 bytes long, so we have to */
1868 : /* add a dummy bit of attribute data to fill out the length. */
1869 : /* -------------------------------------------------------------------- */
1870 0 : DGNAddRawAttrLink( hDGN, psCore, 8, abyRawZeroLinkage );
1871 :
1872 0 : return psCore;
1873 : }
1874 :
1875 : /************************************************************************/
1876 : /* DGNCreateSolidHeaderFromGroup() */
1877 : /************************************************************************/
1878 :
1879 : /**
1880 : * Create 3D solid/surface header.
1881 : *
1882 : * This function is similar to DGNCreateSolidHeaderElem(), but it takes
1883 : * care of computing the total size of the set of elements being written,
1884 : * and collecting the bounding extents. It also takes care of some other
1885 : * convenience issues, like marking all the member elements as complex, and
1886 : * setting the level based on the level of the member elements.
1887 : *
1888 : * @param hDGN the file on which the element will be written.
1889 : * @param nType DGNT_3DSURFACE_HEADER or DGNT_3DSOLID_HEADER.
1890 : * @param nSurfType the surface/solid type, one of DGNSUT_* or DGNSOT_*.
1891 : * @param nBoundElems the number of boundary elements.
1892 : * @param nNumElems the number of elements in the solid not including
1893 : * the header element.
1894 : * @param papsElems array of pointers to nNumElems elements in the solid.
1895 : * Some updates may be made to these elements.
1896 : *
1897 : * @return the new element (DGNElemComplexHeader) or NULL on failure.
1898 : */
1899 :
1900 : DGNElemCore *
1901 0 : DGNCreateSolidHeaderFromGroup( DGNHandle hDGN, int nType, int nSurfType,
1902 : int nBoundElems, int nNumElems,
1903 : DGNElemCore **papsElems )
1904 :
1905 : {
1906 0 : int nTotalLength = 6;
1907 : int i, nLevel;
1908 : DGNElemCore *psCH;
1909 0 : DGNPoint sMin = {0.0,0.0,0.0}, sMax = {0.0,0.0,0.0};
1910 :
1911 0 : DGNLoadTCB( hDGN );
1912 :
1913 0 : if( nNumElems < 1 || papsElems == NULL )
1914 : {
1915 : CPLError( CE_Failure, CPLE_AppDefined,
1916 0 : "Need at least one element to form a solid." );
1917 0 : return NULL;
1918 : }
1919 :
1920 : /* -------------------------------------------------------------------- */
1921 : /* Collect the total size, and bounds. */
1922 : /* -------------------------------------------------------------------- */
1923 0 : nLevel = papsElems[0]->level;
1924 :
1925 0 : for( i = 0; i < nNumElems; i++ )
1926 : {
1927 : DGNPoint sThisMin, sThisMax;
1928 :
1929 0 : nTotalLength += papsElems[i]->raw_bytes / 2;
1930 :
1931 0 : papsElems[i]->complex = TRUE;
1932 0 : papsElems[i]->raw_data[0] |= 0x80;
1933 :
1934 0 : if( papsElems[i]->level != nLevel )
1935 : {
1936 : CPLError( CE_Warning, CPLE_AppDefined,
1937 0 : "Not all level values matching in a complex set group!");
1938 : }
1939 :
1940 0 : DGNGetElementExtents( hDGN, papsElems[i], &sThisMin, &sThisMax );
1941 0 : if( i == 0 )
1942 : {
1943 0 : sMin = sThisMin;
1944 0 : sMax = sThisMax;
1945 : }
1946 : else
1947 : {
1948 0 : sMin.x = MIN(sMin.x,sThisMin.x);
1949 0 : sMin.y = MIN(sMin.y,sThisMin.y);
1950 0 : sMin.z = MIN(sMin.z,sThisMin.z);
1951 0 : sMax.x = MAX(sMax.x,sThisMax.x);
1952 0 : sMax.y = MAX(sMax.y,sThisMax.y);
1953 0 : sMax.z = MAX(sMax.z,sThisMax.z);
1954 : }
1955 : }
1956 :
1957 : /* -------------------------------------------------------------------- */
1958 : /* Create the corresponding solid header. */
1959 : /* -------------------------------------------------------------------- */
1960 : psCH = DGNCreateSolidHeaderElem( hDGN, nType, nSurfType, nBoundElems,
1961 0 : nTotalLength, nNumElems );
1962 0 : DGNUpdateElemCore( hDGN, psCH, papsElems[0]->level, psCH->graphic_group,
1963 0 : psCH->color, psCH->weight, psCH->style );
1964 :
1965 0 : DGNWriteBounds( (DGNInfo *) hDGN, psCH, &sMin, &sMax );
1966 :
1967 0 : return psCH;
1968 : }
1969 :
1970 : /************************************************************************/
1971 : /* DGNCreateCellHeaderElem() */
1972 : /************************************************************************/
1973 :
1974 : DGNElemCore CPL_DLL *
1975 0 : DGNCreateCellHeaderElem( DGNHandle hDGN, int nTotLength, const char *pszName,
1976 : short nClass, short *panLevels,
1977 : DGNPoint *psRangeLow, DGNPoint *psRangeHigh,
1978 : DGNPoint *psOrigin, double dfXScale, double dfYScale,
1979 : double dfRotation )
1980 :
1981 : /**
1982 : * Create cell header.
1983 : *
1984 : * The newly created element will still need to be written to file using
1985 : * DGNWriteElement(). Also the level and other core values will be defaulted.
1986 : * Use DGNUpdateElemCore() on the element before writing to set these values.
1987 : *
1988 : * Generally speaking the function DGNCreateCellHeaderFromGroup() should
1989 : * be used instead of this function.
1990 : *
1991 : * @param hDGN the file handle on which the element is to be written.
1992 : * @param nTotLength total length of cell in words not including the 38 bytes
1993 : * of the cell header that occur before the totlength indicator.
1994 : * @param nClass the class value for the cell.
1995 : * @param panLevels an array of shorts holding the bit mask of levels in
1996 : * effect for this cell. This array should contain 4 shorts (64 bits).
1997 : * @param psRangeLow the cell diagonal origin in original cell file
1998 : * coordinates.
1999 : * @param psRangeHigh the cell diagonal top left corner in original cell file
2000 : * coordinates.
2001 : * @param psOrigin the origin of the cell in output file coordinates.
2002 : * @param dfXScale the amount of scaling applied in the X dimension in
2003 : * mapping from cell file coordinates to output file coordinates.
2004 : * @param dfYScale the amount of scaling applied in the Y dimension in
2005 : * mapping from cell file coordinates to output file coordinates.
2006 : * @param dfRotation the amount of rotation (degrees counterclockwise) in
2007 : * mapping from cell coordinates to output file coordinates.
2008 : *
2009 : * @return the new element (DGNElemCellHeader) or NULL on failure.
2010 : */
2011 :
2012 : {
2013 : DGNElemCellHeader *psCH;
2014 : DGNElemCore *psCore;
2015 0 : DGNInfo *psInfo = (DGNInfo *) hDGN;
2016 :
2017 0 : DGNLoadTCB( hDGN );
2018 :
2019 : /* -------------------------------------------------------------------- */
2020 : /* Allocate element. */
2021 : /* -------------------------------------------------------------------- */
2022 0 : psCH = (DGNElemCellHeader *) CPLCalloc( sizeof(DGNElemCellHeader), 1 );
2023 0 : psCore = &(psCH->core);
2024 :
2025 0 : DGNInitializeElemCore( hDGN, psCore );
2026 0 : psCore->stype = DGNST_CELL_HEADER;
2027 0 : psCore->type = DGNT_CELL_HEADER;
2028 :
2029 : /* -------------------------------------------------------------------- */
2030 : /* Set complex header specific information in the structure. */
2031 : /* -------------------------------------------------------------------- */
2032 0 : psCH->totlength = nTotLength;
2033 :
2034 : /* -------------------------------------------------------------------- */
2035 : /* Setup Raw data for the cell header specific portion. */
2036 : /* -------------------------------------------------------------------- */
2037 0 : if( psInfo->dimension == 2 )
2038 0 : psCore->raw_bytes = 92;
2039 : else
2040 0 : psCore->raw_bytes = 124;
2041 0 : psCore->raw_data = (unsigned char*) CPLCalloc(psCore->raw_bytes,1);
2042 :
2043 0 : psCore->raw_data[36] = (unsigned char) (nTotLength % 256);
2044 0 : psCore->raw_data[37] = (unsigned char) (nTotLength / 256);
2045 :
2046 0 : DGNAsciiToRad50( pszName, (unsigned short *) (psCore->raw_data + 38) );
2047 0 : if( strlen(pszName) > 3 )
2048 0 : DGNAsciiToRad50( pszName+3, (unsigned short *) (psCore->raw_data+40) );
2049 :
2050 0 : psCore->raw_data[42] = (unsigned char) (nClass % 256);
2051 0 : psCore->raw_data[43] = (unsigned char) (nClass / 256);
2052 :
2053 0 : memcpy( psCore->raw_data + 44, panLevels, 8 );
2054 :
2055 0 : if( psInfo->dimension == 2 )
2056 : {
2057 0 : DGNPointToInt( psInfo, psRangeLow, psCore->raw_data + 52 );
2058 0 : DGNPointToInt( psInfo, psRangeHigh, psCore->raw_data+ 60 );
2059 :
2060 : DGNInverseTransformPointToInt( psInfo, psOrigin,
2061 0 : psCore->raw_data + 84 );
2062 : }
2063 : else
2064 : {
2065 0 : DGNPointToInt( psInfo, psRangeLow, psCore->raw_data + 52 );
2066 0 : DGNPointToInt( psInfo, psRangeHigh, psCore->raw_data+ 64 );
2067 :
2068 : DGNInverseTransformPointToInt( psInfo, psOrigin,
2069 0 : psCore->raw_data + 112 );
2070 : }
2071 :
2072 : /* -------------------------------------------------------------------- */
2073 : /* Produce a transformation matrix that approximates the */
2074 : /* requested scaling and rotation. */
2075 : /* -------------------------------------------------------------------- */
2076 0 : if( psInfo->dimension == 2 )
2077 : {
2078 : long anTrans[4];
2079 0 : double cos_a = cos(-dfRotation * PI / 180.0);
2080 0 : double sin_a = sin(-dfRotation * PI / 180.0);
2081 :
2082 0 : anTrans[0] = (long) (cos_a * dfXScale * 214748);
2083 0 : anTrans[1] = (long) (sin_a * dfYScale * 214748);
2084 0 : anTrans[2] = (long)(-sin_a * dfXScale * 214748);
2085 0 : anTrans[3] = (long) (cos_a * dfYScale * 214748);
2086 :
2087 0 : DGN_WRITE_INT32( anTrans[0], psCore->raw_data + 68 );
2088 0 : DGN_WRITE_INT32( anTrans[1], psCore->raw_data + 72 );
2089 0 : DGN_WRITE_INT32( anTrans[2], psCore->raw_data + 76 );
2090 0 : DGN_WRITE_INT32( anTrans[3], psCore->raw_data + 80 );
2091 : }
2092 : else
2093 : {
2094 : }
2095 :
2096 : /* -------------------------------------------------------------------- */
2097 : /* Set the core raw data. */
2098 : /* -------------------------------------------------------------------- */
2099 0 : DGNUpdateElemCoreExtended( hDGN, psCore );
2100 :
2101 0 : return psCore;
2102 : }
2103 :
2104 : /************************************************************************/
2105 : /* DGNPointToInt() */
2106 : /* */
2107 : /* Convert a point directly to integer coordinates and write to */
2108 : /* the indicate memory location. Intended to be used for the */
2109 : /* range section of the CELL HEADER. */
2110 : /************************************************************************/
2111 :
2112 0 : static void DGNPointToInt( DGNInfo *psDGN, DGNPoint *psPoint,
2113 : unsigned char *pabyTarget )
2114 :
2115 : {
2116 : double adfCT[3];
2117 : int i;
2118 :
2119 0 : adfCT[0] = psPoint->x;
2120 0 : adfCT[1] = psPoint->y;
2121 0 : adfCT[2] = psPoint->z;
2122 :
2123 0 : for( i = 0; i < psDGN->dimension; i++ )
2124 : {
2125 : GInt32 nCTI;
2126 0 : unsigned char *pabyCTI = (unsigned char *) &nCTI;
2127 :
2128 0 : nCTI = (GInt32) MAX(-2147483647,MIN(2147483647,adfCT[i]));
2129 :
2130 : #ifdef WORDS_BIGENDIAN
2131 : pabyTarget[i*4+0] = pabyCTI[1];
2132 : pabyTarget[i*4+1] = pabyCTI[0];
2133 : pabyTarget[i*4+2] = pabyCTI[3];
2134 : pabyTarget[i*4+3] = pabyCTI[2];
2135 : #else
2136 0 : pabyTarget[i*4+3] = pabyCTI[1];
2137 0 : pabyTarget[i*4+2] = pabyCTI[0];
2138 0 : pabyTarget[i*4+1] = pabyCTI[3];
2139 0 : pabyTarget[i*4+0] = pabyCTI[2];
2140 : #endif
2141 : }
2142 0 : }
2143 :
2144 : /************************************************************************/
2145 : /* DGNCreateCellHeaderFromGroup() */
2146 : /************************************************************************/
2147 :
2148 : /**
2149 : * Create cell header from a group of elements.
2150 : *
2151 : * The newly created element will still need to be written to file using
2152 : * DGNWriteElement(). Also the level and other core values will be defaulted.
2153 : * Use DGNUpdateElemCore() on the element before writing to set these values.
2154 : *
2155 : * This function will compute the total length, bounding box, and diagonal
2156 : * range values from the set of provided elements. Note that the proper
2157 : * diagonal range values will only be written if 1.0 is used for the x and y
2158 : * scale values, and 0.0 for the rotation. Use of other values will result
2159 : * in incorrect scaling handles being presented to the user in Microstation
2160 : * when they select the element.
2161 : *
2162 : * @param hDGN the file handle on which the element is to be written.
2163 : * @param nClass the class value for the cell.
2164 : * @param panLevels an array of shorts holding the bit mask of levels in
2165 : * effect for this cell. This array should contain 4 shorts (64 bits).
2166 : * This array would normally be passed in as NULL, and the function will
2167 : * build a mask from the passed list of elements.
2168 : * @param psOrigin the origin of the cell in output file coordinates.
2169 : * @param dfXScale the amount of scaling applied in the X dimension in
2170 : * mapping from cell file coordinates to output file coordinates.
2171 : * @param dfYScale the amount of scaling applied in the Y dimension in
2172 : * mapping from cell file coordinates to output file coordinates.
2173 : * @param dfRotation the amount of rotation (degrees counterclockwise) in
2174 : * mapping from cell coordinates to output file coordinates.
2175 : *
2176 : * @return the new element (DGNElemCellHeader) or NULL on failure.
2177 : */
2178 :
2179 : DGNElemCore *
2180 0 : DGNCreateCellHeaderFromGroup( DGNHandle hDGN, const char *pszName,
2181 : short nClass, short *panLevels,
2182 : int nNumElems, DGNElemCore **papsElems,
2183 : DGNPoint *psOrigin,
2184 : double dfXScale, double dfYScale,
2185 : double dfRotation )
2186 :
2187 : {
2188 : int nTotalLength;
2189 : int i, nLevel;
2190 : DGNElemCore *psCH;
2191 0 : DGNPoint sMin={0.0,0.0,0.0}, sMax={0.0,0.0,0.0};
2192 0 : unsigned char abyLevelsOccuring[8] = {0,0,0,0,0,0,0,0};
2193 0 : DGNInfo *psInfo = (DGNInfo *) hDGN;
2194 :
2195 0 : DGNLoadTCB( hDGN );
2196 :
2197 0 : if( nNumElems < 1 || papsElems == NULL )
2198 : {
2199 : CPLError( CE_Failure, CPLE_AppDefined,
2200 0 : "Need at least one element to form a cell." );
2201 0 : return NULL;
2202 : }
2203 :
2204 0 : if( psInfo->dimension == 2 )
2205 0 : nTotalLength = 27;
2206 : else
2207 0 : nTotalLength = 43;
2208 :
2209 : /* -------------------------------------------------------------------- */
2210 : /* Collect the total size, and bounds. */
2211 : /* -------------------------------------------------------------------- */
2212 0 : nLevel = papsElems[0]->level;
2213 :
2214 0 : for( i = 0; i < nNumElems; i++ )
2215 : {
2216 : DGNPoint sThisMin, sThisMax;
2217 : int nLevel;
2218 :
2219 0 : nTotalLength += papsElems[i]->raw_bytes / 2;
2220 :
2221 : /* mark as complex */
2222 0 : papsElems[i]->complex = TRUE;
2223 0 : papsElems[i]->raw_data[0] |= 0x80;
2224 :
2225 : /* establish level */
2226 0 : nLevel = papsElems[i]->level;
2227 0 : nLevel = MAX(1,MIN(nLevel,64));
2228 0 : abyLevelsOccuring[(nLevel-1) >> 3] |= (0x1 << ((nLevel-1)&0x7));
2229 :
2230 0 : DGNGetElementExtents( hDGN, papsElems[i], &sThisMin, &sThisMax );
2231 0 : if( i == 0 )
2232 : {
2233 0 : sMin = sThisMin;
2234 0 : sMax = sThisMax;
2235 : }
2236 : else
2237 : {
2238 0 : sMin.x = MIN(sMin.x,sThisMin.x);
2239 0 : sMin.y = MIN(sMin.y,sThisMin.y);
2240 0 : sMin.z = MIN(sMin.z,sThisMin.z);
2241 0 : sMax.x = MAX(sMax.x,sThisMax.x);
2242 0 : sMax.y = MAX(sMax.y,sThisMax.y);
2243 0 : sMax.z = MAX(sMax.z,sThisMax.z);
2244 : }
2245 : }
2246 :
2247 : /* -------------------------------------------------------------------- */
2248 : /* It seems that the range needs to be adjusted according to */
2249 : /* the rotation and scaling. */
2250 : /* */
2251 : /* NOTE: Omitting code ... this is already done in */
2252 : /* DGNInverseTransformPoint() called from DGNWriteBounds(). */
2253 : /* -------------------------------------------------------------------- */
2254 : #ifdef notdef
2255 : sMin.x -= psOrigin->x;
2256 : sMin.y -= psOrigin->y;
2257 : sMin.z -= psOrigin->z;
2258 : sMax.x -= psOrigin->x;
2259 : sMax.y -= psOrigin->y;
2260 : sMax.z -= psOrigin->z;
2261 :
2262 : sMin.x /= ((DGNInfo *) hDGN)->scale;
2263 : sMin.y /= ((DGNInfo *) hDGN)->scale;
2264 : sMin.z /= ((DGNInfo *) hDGN)->scale;
2265 : sMax.x /= ((DGNInfo *) hDGN)->scale;
2266 : sMax.y /= ((DGNInfo *) hDGN)->scale;
2267 : sMax.z /= ((DGNInfo *) hDGN)->scale;
2268 : #endif
2269 :
2270 : /* -------------------------------------------------------------------- */
2271 : /* Create the corresponding cell header. */
2272 : /* -------------------------------------------------------------------- */
2273 0 : if( panLevels == NULL )
2274 0 : panLevels = (short *) abyLevelsOccuring + 0;
2275 :
2276 : psCH = DGNCreateCellHeaderElem( hDGN, nTotalLength, pszName,
2277 : nClass, panLevels,
2278 : &sMin, &sMax, psOrigin,
2279 0 : dfXScale, dfYScale, dfRotation );
2280 0 : DGNWriteBounds( (DGNInfo *) hDGN, psCH, &sMin, &sMax );
2281 :
2282 0 : return psCH;
2283 :
2284 : }
2285 :
2286 : /************************************************************************/
2287 : /* DGNAddMSLink() */
2288 : /************************************************************************/
2289 :
2290 : /**
2291 : * Add a database link to element.
2292 : *
2293 : * The target element must already have raw_data loaded, and it will be
2294 : * resized (see DGNResizeElement()) as needed for the new attribute data.
2295 : * Note that the element is not written to disk immediate. Use
2296 : * DGNWriteElement() for that.
2297 : *
2298 : * @param hDGN the file to which the element corresponds.
2299 : * @param psElement the element being updated.
2300 : * @param nLinkageType link type (DGNLT_*). Usually one of DGNLT_DMRS,
2301 : * DGNLT_INFORMIX, DGNLT_ODBC, DGNLT_ORACLE, DGNLT_RIS, DGNLT_SYBASE,
2302 : * or DGNLT_XBASE.
2303 : * @param nEntityNum indicator of the table referenced on target database.
2304 : * @param nMSLink indicator of the record referenced on target table.
2305 : *
2306 : * @return -1 on failure, or the link index.
2307 : */
2308 :
2309 0 : int DGNAddMSLink( DGNHandle hDGN, DGNElemCore *psElement,
2310 : int nLinkageType, int nEntityNum, int nMSLink )
2311 :
2312 : {
2313 : unsigned char abyLinkage[32];
2314 : int nLinkageSize;
2315 :
2316 0 : if( nLinkageType == DGNLT_DMRS )
2317 : {
2318 0 : nLinkageSize = 8;
2319 0 : abyLinkage[0] = 0x00;
2320 0 : abyLinkage[1] = 0x00;
2321 0 : abyLinkage[2] = (GByte) (nEntityNum % 256);
2322 0 : abyLinkage[3] = (GByte) (nEntityNum / 256);
2323 0 : abyLinkage[4] = (GByte) (nMSLink % 256);
2324 0 : abyLinkage[5] = (GByte) ((nMSLink / 256) % 256);
2325 0 : abyLinkage[6] = (GByte) (nMSLink / 65536);
2326 0 : abyLinkage[7] = 0x01;
2327 : }
2328 : else
2329 : {
2330 0 : nLinkageSize = 16;
2331 0 : abyLinkage[0] = 0x07;
2332 0 : abyLinkage[1] = 0x10;
2333 0 : abyLinkage[2] = (GByte) (nLinkageType % 256);
2334 0 : abyLinkage[3] = (GByte) (nLinkageType / 256);
2335 0 : abyLinkage[4] = (GByte) (0x81);
2336 0 : abyLinkage[5] = (GByte) (0x0F);
2337 0 : abyLinkage[6] = (GByte) (nEntityNum % 256);
2338 0 : abyLinkage[7] = (GByte) (nEntityNum / 256);
2339 0 : abyLinkage[8] = (GByte) (nMSLink % 256);
2340 0 : abyLinkage[9] = (GByte) ((nMSLink / 256) % 256);
2341 0 : abyLinkage[10] = (GByte) ((nMSLink / 65536) % 256);
2342 0 : abyLinkage[11] = (GByte) (nMSLink / 16777216);
2343 0 : abyLinkage[12] = 0x00;
2344 0 : abyLinkage[13] = 0x00;
2345 0 : abyLinkage[14] = 0x00;
2346 0 : abyLinkage[15] = 0x00;
2347 : }
2348 :
2349 0 : return DGNAddRawAttrLink( hDGN, psElement, nLinkageSize, abyLinkage );
2350 : }
2351 :
2352 : /************************************************************************/
2353 : /* DGNAddRawAttrLink() */
2354 : /************************************************************************/
2355 :
2356 : /**
2357 : * Add a raw attribute linkage to element.
2358 : *
2359 : * Given a raw data buffer, append it to this element as an attribute linkage
2360 : * without trying to interprete the linkage data.
2361 : *
2362 : * The target element must already have raw_data loaded, and it will be
2363 : * resized (see DGNResizeElement()) as needed for the new attribute data.
2364 : * Note that the element is not written to disk immediate. Use
2365 : * DGNWriteElement() for that.
2366 : *
2367 : * This function will take care of updating the "totlength" field of
2368 : * complex chain or shape headers to account for the extra attribute space
2369 : * consumed in the header element.
2370 : *
2371 : * @param hDGN the file to which the element corresponds.
2372 : * @param psElement the element being updated.
2373 : * @param nLinkSize the size of the linkage in bytes.
2374 : * @param pabyRawLinkData the raw linkage data (nLinkSize bytes worth).
2375 : *
2376 : * @return -1 on failure, or the link index.
2377 : */
2378 :
2379 1 : int DGNAddRawAttrLink( DGNHandle hDGN, DGNElemCore *psElement,
2380 : int nLinkSize, unsigned char *pabyRawLinkData )
2381 :
2382 : {
2383 : int iLinkage;
2384 :
2385 1 : if( nLinkSize % 2 == 1 )
2386 0 : nLinkSize++;
2387 :
2388 1 : if( psElement->size + nLinkSize > 768 )
2389 : {
2390 : CPLError( CE_Failure, CPLE_ElementTooBig,
2391 : "Attempt to add %d byte linkage to element exceeds maximum"
2392 : " element size.",
2393 0 : nLinkSize );
2394 0 : return -1;
2395 : }
2396 :
2397 : /* -------------------------------------------------------------------- */
2398 : /* Ensure the attribute linkage bit is set. */
2399 : /* -------------------------------------------------------------------- */
2400 1 : psElement->properties |= DGNPF_ATTRIBUTES;
2401 :
2402 : /* -------------------------------------------------------------------- */
2403 : /* Append the attribute linkage to the linkage area. */
2404 : /* -------------------------------------------------------------------- */
2405 1 : psElement->attr_bytes += nLinkSize;
2406 : psElement->attr_data = (unsigned char *)
2407 1 : CPLRealloc( psElement->attr_data, psElement->attr_bytes );
2408 :
2409 : memcpy( psElement->attr_data + (psElement->attr_bytes-nLinkSize),
2410 1 : pabyRawLinkData, nLinkSize );
2411 :
2412 : /* -------------------------------------------------------------------- */
2413 : /* Grow the raw data, if we have rawdata. */
2414 : /* -------------------------------------------------------------------- */
2415 1 : psElement->raw_bytes = psElement->raw_bytes += nLinkSize;
2416 : psElement->raw_data = (unsigned char *)
2417 1 : CPLRealloc( psElement->raw_data, psElement->raw_bytes );
2418 :
2419 : memcpy( psElement->raw_data + (psElement->raw_bytes-nLinkSize),
2420 1 : pabyRawLinkData, nLinkSize );
2421 :
2422 : /* -------------------------------------------------------------------- */
2423 : /* If the element is a shape or chain complex header, then we */
2424 : /* need to increase the total complex group size appropriately. */
2425 : /* -------------------------------------------------------------------- */
2426 1 : if( psElement->stype == DGNST_COMPLEX_HEADER ||
2427 : psElement->stype == DGNST_TEXT_NODE ) // compatible structures
2428 : {
2429 1 : DGNElemComplexHeader *psCT = (DGNElemComplexHeader *) psElement;
2430 :
2431 1 : psCT->totlength += (nLinkSize / 2);
2432 :
2433 1 : psElement->raw_data[36] = (unsigned char) (psCT->totlength % 256);
2434 1 : psElement->raw_data[37] = (unsigned char) (psCT->totlength / 256);
2435 : }
2436 :
2437 : /* -------------------------------------------------------------------- */
2438 : /* Ensure everything is updated properly, including element */
2439 : /* length and properties. */
2440 : /* -------------------------------------------------------------------- */
2441 1 : DGNUpdateElemCoreExtended( hDGN, psElement );
2442 :
2443 : /* -------------------------------------------------------------------- */
2444 : /* Figure out what the linkage index is. */
2445 : /* -------------------------------------------------------------------- */
2446 2 : for( iLinkage = 0; ; iLinkage++ )
2447 : {
2448 2 : if( DGNGetLinkage( hDGN, psElement, iLinkage, NULL, NULL, NULL, NULL )
2449 : == NULL )
2450 : break;
2451 : }
2452 :
2453 1 : return iLinkage-1;
2454 : }
2455 :
2456 : /************************************************************************/
2457 : /* DGNAddShapeFileInfo() */
2458 : /************************************************************************/
2459 :
2460 : /**
2461 : * Add a shape fill attribute linkage.
2462 : *
2463 : * The target element must already have raw_data loaded, and it will be
2464 : * resized (see DGNResizeElement()) as needed for the new attribute data.
2465 : * Note that the element is not written to disk immediate. Use
2466 : * DGNWriteElement() for that.
2467 : *
2468 : * @param hDGN the file to which the element corresponds.
2469 : * @param psElement the element being updated.
2470 : * @param nColor fill color (color index from palette).
2471 : *
2472 : * @return -1 on failure, or the link index.
2473 : */
2474 :
2475 0 : int DGNAddShapeFillInfo( DGNHandle hDGN, DGNElemCore *psElement,
2476 : int nColor )
2477 :
2478 : {
2479 : unsigned char abyFillInfo[16] =
2480 : { 0x07, 0x10, 0x41, 0x00, 0x02, 0x08, 0x01, 0x00,
2481 0 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
2482 :
2483 0 : abyFillInfo[8] = (unsigned char) nColor;
2484 :
2485 0 : return DGNAddRawAttrLink( hDGN, psElement, 16, abyFillInfo );
2486 : }
|