LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/dgn - dgnread.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 773 363 47.0 %
Date: 2010-01-09 Functions: 20 17 85.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: dgnread.cpp 10645 2007-01-18 02:22:39Z warmerdam $
       3                 :  *
       4                 :  * Project:  Microstation DGN Access Library
       5                 :  * Purpose:  DGN Access Library element reading code.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2000, Avenza Systems Inc, http://www.avenza.com/
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "dgnlibp.h"
      31                 : 
      32                 : CPL_CVSID("$Id: dgnread.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
      33                 : 
      34                 : static DGNElemCore *DGNParseTCB( DGNInfo * );
      35                 : static DGNElemCore *DGNParseColorTable( DGNInfo * );
      36                 : static DGNElemCore *DGNParseTagSet( DGNInfo * );
      37                 : 
      38                 : 
      39                 : /************************************************************************/
      40                 : /*                           DGNGotoElement()                           */
      41                 : /************************************************************************/
      42                 : 
      43                 : /**
      44                 :  * Seek to indicated element.
      45                 :  *
      46                 :  * Changes what element will be read on the next call to DGNReadElement(). 
      47                 :  * Note that this function requires and index, and one will be built if
      48                 :  * not already available.
      49                 :  *
      50                 :  * @param hDGN the file to affect.
      51                 :  * @param element_id the element to seek to.  These values are sequentially
      52                 :  * ordered starting at zero for the first element.
      53                 :  * 
      54                 :  * @return returns TRUE on success or FALSE on failure. 
      55                 :  */
      56                 : 
      57              17 : int DGNGotoElement( DGNHandle hDGN, int element_id )
      58                 : 
      59                 : {
      60              17 :     DGNInfo     *psDGN = (DGNInfo *) hDGN;
      61                 : 
      62              17 :     DGNBuildIndex( psDGN );
      63                 : 
      64              17 :     if( element_id < 0 || element_id >= psDGN->element_count )
      65               0 :         return FALSE;
      66                 : 
      67              17 :     if( VSIFSeek( psDGN->fp, psDGN->element_index[element_id].offset, 
      68                 :                   SEEK_SET ) != 0 )
      69               0 :         return FALSE;
      70                 : 
      71              17 :     psDGN->next_element_id = element_id;
      72              17 :     psDGN->in_complex_group = FALSE;
      73                 : 
      74              17 :     return TRUE;
      75                 : }
      76                 : 
      77                 : /************************************************************************/
      78                 : /*                         DGNLoadRawElement()                          */
      79                 : /************************************************************************/
      80                 : 
      81             178 : int DGNLoadRawElement( DGNInfo *psDGN, int *pnType, int *pnLevel )
      82                 : 
      83                 : {
      84                 : /* -------------------------------------------------------------------- */
      85                 : /*      Read the first four bytes to get the level, type, and word      */
      86                 : /*      count.                                                          */
      87                 : /* -------------------------------------------------------------------- */
      88                 :     int         nType, nWords, nLevel;
      89                 : 
      90             178 :     if( VSIFRead( psDGN->abyElem, 1, 4, psDGN->fp ) != 4 )
      91               2 :         return FALSE;
      92                 : 
      93                 :     /* Is this an 0xFFFF endof file marker? */
      94             176 :     if( psDGN->abyElem[0] == 0xff && psDGN->abyElem[1] == 0xff )
      95               6 :         return FALSE;
      96                 : 
      97             170 :     nWords = psDGN->abyElem[2] + psDGN->abyElem[3]*256;
      98             170 :     nType = psDGN->abyElem[1] & 0x7f;
      99             170 :     nLevel = psDGN->abyElem[0] & 0x3f;
     100                 : 
     101                 : /* -------------------------------------------------------------------- */
     102                 : /*      Read the rest of the element data into the working buffer.      */
     103                 : /* -------------------------------------------------------------------- */
     104                 :     CPLAssert( nWords * 2 + 4 <= (int) sizeof(psDGN->abyElem) );
     105                 : 
     106             170 :     if( (int) VSIFRead( psDGN->abyElem + 4, 2, nWords, psDGN->fp ) != nWords )
     107               0 :         return FALSE;
     108                 : 
     109             170 :     psDGN->nElemBytes = nWords * 2 + 4;
     110                 : 
     111             170 :     psDGN->next_element_id++;
     112                 : 
     113                 : /* -------------------------------------------------------------------- */
     114                 : /*      Return requested info.                                          */
     115                 : /* -------------------------------------------------------------------- */
     116             170 :     if( pnType != NULL )
     117             170 :         *pnType = nType;
     118                 :     
     119             170 :     if( pnLevel != NULL )
     120             170 :         *pnLevel = nLevel;
     121                 :     
     122             170 :     return TRUE;
     123                 : }
     124                 : 
     125                 : 
     126                 : /************************************************************************/
     127                 : /*                          DGNGetRawExtents()                          */
     128                 : /*                                                                      */
     129                 : /*      Returns FALSE if the element type does not have reconisable     */
     130                 : /*      element extents, other TRUE and the extents will be updated.    */
     131                 : /*                                                                      */
     132                 : /*      It is assumed the raw element data has been loaded into the     */
     133                 : /*      working area by DGNLoadRawElement().                            */
     134                 : /************************************************************************/
     135                 : 
     136                 : static int 
     137              63 : DGNGetRawExtents( DGNInfo *psDGN, int nType, unsigned char *pabyRawData,
     138                 :                   GUInt32 *pnXMin, GUInt32 *pnYMin, GUInt32 *pnZMin, 
     139                 :                   GUInt32 *pnXMax, GUInt32 *pnYMax, GUInt32 *pnZMax )
     140                 : 
     141                 : {
     142              63 :     if( pabyRawData == NULL )
     143              61 :         pabyRawData = psDGN->abyElem + 0;
     144                 : 
     145              63 :     switch( nType )
     146                 :     {
     147                 :       case DGNT_LINE:
     148                 :       case DGNT_LINE_STRING:
     149                 :       case DGNT_SHAPE:
     150                 :       case DGNT_CURVE:
     151                 :       case DGNT_BSPLINE_POLE:
     152                 :       case DGNT_BSPLINE_SURFACE_HEADER:
     153                 :       case DGNT_BSPLINE_CURVE_HEADER:
     154                 :       case DGNT_ELLIPSE:
     155                 :       case DGNT_ARC:
     156                 :       case DGNT_TEXT:
     157                 :       case DGNT_TEXT_NODE:
     158                 :       case DGNT_COMPLEX_CHAIN_HEADER:
     159                 :       case DGNT_COMPLEX_SHAPE_HEADER:
     160                 :       case DGNT_CONE:
     161                 :       case DGNT_3DSURFACE_HEADER:
     162                 :       case DGNT_3DSOLID_HEADER:
     163              17 :         *pnXMin = DGN_INT32( pabyRawData + 4 );
     164              17 :         *pnYMin = DGN_INT32( pabyRawData + 8 );
     165              17 :         if( pnZMin != NULL )
     166              13 :             *pnZMin = DGN_INT32( pabyRawData + 12 );
     167                 : 
     168              17 :         *pnXMax = DGN_INT32( pabyRawData + 16 );
     169              17 :         *pnYMax = DGN_INT32( pabyRawData + 20 );
     170              17 :         if( pnZMax != NULL )
     171              13 :             *pnZMax = DGN_INT32( pabyRawData + 24 );
     172              17 :         return TRUE;
     173                 : 
     174                 :       default:
     175              46 :         return FALSE;
     176                 :     }
     177                 : }
     178                 : 
     179                 : 
     180                 : /************************************************************************/
     181                 : /*                        DGNGetElementExtents()                        */
     182                 : /************************************************************************/
     183                 : 
     184                 : /**
     185                 :  * Fetch extents of an element.
     186                 :  *
     187                 :  * This function will return the extents of the passed element if possible.
     188                 :  * The extents are extracted from the element header if it contains them,
     189                 :  * and transformed into master georeferenced format.  Some element types 
     190                 :  * do not have extents at all and will fail.  
     191                 :  *
     192                 :  * This call will also fail if the extents raw data for the element is not
     193                 :  * available.  This will occur if it was not the most recently read element,
     194                 :  * and if the raw_data field is not loaded. 
     195                 :  *
     196                 :  * @param hDGN the handle of the file to read from.
     197                 :  *
     198                 :  * @param psElement the element to extract extents from.
     199                 :  *
     200                 :  * @param psMin structure loaded with X, Y and Z minimum values for the 
     201                 :  * extent. 
     202                 :  *
     203                 :  * @param psMax structure loaded with X, Y and Z maximum values for the 
     204                 :  * extent. 
     205                 :  *
     206                 :  * @return TRUE on success of FALSE if extracting extents fails. 
     207                 :  */
     208                 : 
     209               2 : int DGNGetElementExtents( DGNHandle hDGN, DGNElemCore *psElement, 
     210                 :                           DGNPoint *psMin, DGNPoint *psMax )
     211                 : 
     212                 : {
     213               2 :     DGNInfo     *psDGN = (DGNInfo *) hDGN;
     214                 :     GUInt32 anMin[3], anMax[3];
     215                 :     int bResult;
     216                 : 
     217                 : /* -------------------------------------------------------------------- */
     218                 : /*      Get the extents if we have raw data in the element, or          */
     219                 : /*      loaded in the file buffer.                                      */
     220                 : /* -------------------------------------------------------------------- */
     221               2 :     if( psElement->raw_data != NULL )
     222                 :         bResult = DGNGetRawExtents( psDGN, psElement->type, 
     223                 :                                     psElement->raw_data, 
     224                 :                                     anMin + 0, anMin + 1, anMin + 2,
     225               2 :                                     anMax + 0, anMax + 1, anMax + 2 );
     226               0 :     else if( psElement->element_id == psDGN->next_element_id - 1 )
     227                 :         bResult = DGNGetRawExtents( psDGN, psElement->type, 
     228                 :                                     psDGN->abyElem + 0, 
     229                 :                                     anMin + 0, anMin + 1, anMin + 2,
     230               0 :                                     anMax + 0, anMax + 1, anMax + 2 );
     231                 :     else
     232                 :     {
     233                 :         CPLError(CE_Warning, CPLE_AppDefined, 
     234                 :                  "DGNGetElementExtents() fails because the requested element\n"
     235               0 :                  " does not have raw data available." );
     236               0 :         return FALSE;
     237                 :     }
     238                 : 
     239               2 :     if( !bResult )
     240               0 :         return FALSE;
     241                 : 
     242                 : /* -------------------------------------------------------------------- */
     243                 : /*      Transform to user coordinate system and return.  The offset     */
     244                 : /*      is to convert from "binary offset" form to twos complement.     */
     245                 : /* -------------------------------------------------------------------- */
     246               2 :     psMin->x = anMin[0] - 2147483648.0;
     247               2 :     psMin->y = anMin[1] - 2147483648.0;
     248               2 :     psMin->z = anMin[2] - 2147483648.0;
     249                 : 
     250               2 :     psMax->x = anMax[0] - 2147483648.0;
     251               2 :     psMax->y = anMax[1] - 2147483648.0;
     252               2 :     psMax->z = anMax[2] - 2147483648.0;
     253                 : 
     254               2 :     DGNTransformPoint( psDGN, psMin );
     255               2 :     DGNTransformPoint( psDGN, psMax );
     256                 : 
     257               2 :     return TRUE;
     258                 : }
     259                 : 
     260                 : /************************************************************************/
     261                 : /*                         DGNProcessElement()                          */
     262                 : /*                                                                      */
     263                 : /*      Assumes the raw element data has already been loaded, and       */
     264                 : /*      tries to convert it into an element structure.                  */
     265                 : /************************************************************************/
     266                 : 
     267             101 : static DGNElemCore *DGNProcessElement( DGNInfo *psDGN, int nType, int nLevel )
     268                 : 
     269                 : {
     270             101 :     DGNElemCore *psElement = NULL;
     271                 : 
     272                 : /* -------------------------------------------------------------------- */
     273                 : /*      Handle based on element type.                                   */
     274                 : /* -------------------------------------------------------------------- */
     275             101 :     switch( nType )
     276                 :     {
     277                 :       case DGNT_CELL_HEADER:
     278                 :       {
     279                 :           DGNElemCellHeader *psCell;
     280                 : 
     281                 :           psCell = (DGNElemCellHeader *) 
     282               0 :               CPLCalloc(sizeof(DGNElemCellHeader),1);
     283               0 :           psElement = (DGNElemCore *) psCell;
     284               0 :           psElement->stype = DGNST_CELL_HEADER;
     285               0 :           DGNParseCore( psDGN, psElement );
     286                 : 
     287               0 :           psCell->totlength = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
     288                 : 
     289               0 :           DGNRad50ToAscii( psDGN->abyElem[38] + psDGN->abyElem[39] * 256, 
     290               0 :                            psCell->name + 0 );
     291               0 :           DGNRad50ToAscii( psDGN->abyElem[40] + psDGN->abyElem[41] * 256, 
     292               0 :                            psCell->name + 3 );
     293                 : 
     294               0 :           psCell->cclass = psDGN->abyElem[42] + psDGN->abyElem[43] * 256;
     295               0 :           psCell->levels[0] = psDGN->abyElem[44] + psDGN->abyElem[45] * 256;
     296               0 :           psCell->levels[1] = psDGN->abyElem[46] + psDGN->abyElem[47] * 256;
     297               0 :           psCell->levels[2] = psDGN->abyElem[48] + psDGN->abyElem[49] * 256;
     298               0 :           psCell->levels[3] = psDGN->abyElem[50] + psDGN->abyElem[51] * 256;
     299                 : 
     300               0 :           if( psDGN->dimension == 2 )
     301                 :           {
     302               0 :               psCell->rnglow.x = DGN_INT32( psDGN->abyElem + 52 );
     303               0 :               psCell->rnglow.y = DGN_INT32( psDGN->abyElem + 56 );
     304               0 :               psCell->rnghigh.x = DGN_INT32( psDGN->abyElem + 60 );
     305               0 :               psCell->rnghigh.y = DGN_INT32( psDGN->abyElem + 64 );
     306                 : 
     307                 :               psCell->trans[0] =
     308               0 :                 1.0 * DGN_INT32( psDGN->abyElem + 68 ) / (1<<31);
     309                 :               psCell->trans[1] = 
     310               0 :                 1.0 * DGN_INT32( psDGN->abyElem + 72 ) / (1<<31);
     311                 :               psCell->trans[2] = 
     312               0 :                 1.0 * DGN_INT32( psDGN->abyElem + 76 ) / (1<<31);
     313                 :               psCell->trans[3] = 
     314               0 :                 1.0 * DGN_INT32( psDGN->abyElem + 80 ) / (1<<31);
     315                 : 
     316               0 :               psCell->origin.x = DGN_INT32( psDGN->abyElem + 84 );
     317               0 :               psCell->origin.y = DGN_INT32( psDGN->abyElem + 88 );
     318                 : 
     319                 :               {
     320                 :               double a, b, c, d, a2, c2;
     321               0 :               a = DGN_INT32( psDGN->abyElem + 68 );
     322               0 :               b = DGN_INT32( psDGN->abyElem + 72 );
     323               0 :               c = DGN_INT32( psDGN->abyElem + 76 );
     324               0 :               d = DGN_INT32( psDGN->abyElem + 80 );
     325               0 :               a2 = a * a;
     326               0 :               c2 = c * c;
     327                 :               
     328               0 :               psCell->xscale = sqrt(a2 + c2) / 214748;
     329               0 :               psCell->yscale = sqrt(b*b + d*d) / 214748;
     330               0 :               if( (a2 + c2) <= 0.0 )
     331               0 :                   psCell->rotation = 0.0;
     332                 :               else
     333               0 :                   psCell->rotation = acos(a / sqrt(a2 + c2));
     334                 : 
     335               0 :               if (b <= 0)
     336               0 :                   psCell->rotation = psCell->rotation * 180 / PI;
     337                 :               else
     338               0 :                   psCell->rotation = 360 - psCell->rotation * 180 / PI;
     339                 :               }
     340                 :           }
     341                 :           else
     342                 :           {
     343               0 :               psCell->rnglow.x = DGN_INT32( psDGN->abyElem + 52 );
     344               0 :               psCell->rnglow.y = DGN_INT32( psDGN->abyElem + 56 );
     345               0 :               psCell->rnglow.z = DGN_INT32( psDGN->abyElem + 60 );
     346               0 :               psCell->rnghigh.x = DGN_INT32( psDGN->abyElem + 64 );
     347               0 :               psCell->rnghigh.y = DGN_INT32( psDGN->abyElem + 68 );
     348               0 :               psCell->rnghigh.z = DGN_INT32( psDGN->abyElem + 72 );
     349                 : 
     350                 :               psCell->trans[0] =
     351               0 :                 1.0 * DGN_INT32( psDGN->abyElem + 76 ) / (1<<31);
     352                 :               psCell->trans[1] = 
     353               0 :                 1.0 * DGN_INT32( psDGN->abyElem + 80 ) / (1<<31);
     354                 :               psCell->trans[2] = 
     355               0 :                 1.0 * DGN_INT32( psDGN->abyElem + 84 ) / (1<<31);
     356                 :               psCell->trans[3] = 
     357               0 :                 1.0 * DGN_INT32( psDGN->abyElem + 88 ) / (1<<31);
     358                 :               psCell->trans[4] = 
     359               0 :                 1.0 * DGN_INT32( psDGN->abyElem + 92 ) / (1<<31);
     360                 :               psCell->trans[5] = 
     361               0 :                 1.0 * DGN_INT32( psDGN->abyElem + 96 ) / (1<<31);
     362                 :               psCell->trans[6] = 
     363               0 :                 1.0 * DGN_INT32( psDGN->abyElem + 100 ) / (1<<31);
     364                 :               psCell->trans[7] = 
     365               0 :                 1.0 * DGN_INT32( psDGN->abyElem + 104 ) / (1<<31);
     366                 :               psCell->trans[8] = 
     367               0 :                 1.0 * DGN_INT32( psDGN->abyElem + 108 ) / (1<<31);
     368                 : 
     369               0 :               psCell->origin.x = DGN_INT32( psDGN->abyElem + 112 );
     370               0 :               psCell->origin.y = DGN_INT32( psDGN->abyElem + 116 );
     371               0 :               psCell->origin.z = DGN_INT32( psDGN->abyElem + 120 );
     372                 :           }
     373                 : 
     374               0 :           DGNTransformPoint( psDGN, &(psCell->rnglow) );
     375               0 :           DGNTransformPoint( psDGN, &(psCell->rnghigh) );
     376               0 :           DGNTransformPoint( psDGN, &(psCell->origin) );
     377                 :       }
     378               0 :       break;
     379                 : 
     380                 :       case DGNT_CELL_LIBRARY:
     381                 :       {
     382                 :           DGNElemCellLibrary *psCell;
     383                 :           int                 iWord;
     384                 : 
     385                 :           psCell = (DGNElemCellLibrary *) 
     386               0 :               CPLCalloc(sizeof(DGNElemCellLibrary),1);
     387               0 :           psElement = (DGNElemCore *) psCell;
     388               0 :           psElement->stype = DGNST_CELL_LIBRARY;
     389               0 :           DGNParseCore( psDGN, psElement );
     390                 : 
     391               0 :           DGNRad50ToAscii( psDGN->abyElem[32] + psDGN->abyElem[33] * 256, 
     392               0 :                            psCell->name + 0 );
     393               0 :           DGNRad50ToAscii( psDGN->abyElem[34] + psDGN->abyElem[35] * 256, 
     394               0 :                            psCell->name + 3 );
     395                 : 
     396               0 :           psElement->properties = psDGN->abyElem[38] 
     397               0 :               + psDGN->abyElem[39] * 256;
     398                 : 
     399               0 :           psCell->dispsymb = psDGN->abyElem[40] + psDGN->abyElem[41] * 256;
     400                 : 
     401               0 :           psCell->cclass = psDGN->abyElem[42] + psDGN->abyElem[43] * 256;
     402               0 :           psCell->levels[0] = psDGN->abyElem[44] + psDGN->abyElem[45] * 256;
     403               0 :           psCell->levels[1] = psDGN->abyElem[46] + psDGN->abyElem[47] * 256;
     404               0 :           psCell->levels[2] = psDGN->abyElem[48] + psDGN->abyElem[49] * 256;
     405               0 :           psCell->levels[3] = psDGN->abyElem[50] + psDGN->abyElem[51] * 256;
     406                 : 
     407               0 :           psCell->numwords = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
     408                 : 
     409               0 :           memset( psCell->description, 0, sizeof(psCell->description) );
     410                 :           
     411               0 :           for( iWord = 0; iWord < 9; iWord++ )
     412                 :           {
     413               0 :               int iOffset = 52 + iWord * 2;
     414                 : 
     415               0 :               DGNRad50ToAscii( psDGN->abyElem[iOffset] 
     416               0 :                                + psDGN->abyElem[iOffset+1] * 256, 
     417               0 :                                psCell->description + iWord * 3 );
     418                 :           }
     419                 :       }
     420               0 :       break;
     421                 : 
     422                 :       case DGNT_LINE:
     423                 :       {
     424                 :           DGNElemMultiPoint *psLine;
     425                 : 
     426                 :           psLine = (DGNElemMultiPoint *) 
     427               3 :               CPLCalloc(sizeof(DGNElemMultiPoint),1);
     428               3 :           psElement = (DGNElemCore *) psLine;
     429               3 :           psElement->stype = DGNST_MULTIPOINT;
     430               3 :           DGNParseCore( psDGN, psElement );
     431                 : 
     432               3 :           psLine->num_vertices = 2;
     433               3 :           if( psDGN->dimension == 2 )
     434                 :           {
     435               3 :               psLine->vertices[0].x = DGN_INT32( psDGN->abyElem + 36 );
     436               3 :               psLine->vertices[0].y = DGN_INT32( psDGN->abyElem + 40 );
     437               3 :               psLine->vertices[1].x = DGN_INT32( psDGN->abyElem + 44 );
     438               3 :               psLine->vertices[1].y = DGN_INT32( psDGN->abyElem + 48 );
     439                 :           }
     440                 :           else
     441                 :           {
     442               0 :               psLine->vertices[0].x = DGN_INT32( psDGN->abyElem + 36 );
     443               0 :               psLine->vertices[0].y = DGN_INT32( psDGN->abyElem + 40 );
     444               0 :               psLine->vertices[0].z = DGN_INT32( psDGN->abyElem + 44 );
     445               0 :               psLine->vertices[1].x = DGN_INT32( psDGN->abyElem + 48 );
     446               0 :               psLine->vertices[1].y = DGN_INT32( psDGN->abyElem + 52 );
     447               0 :               psLine->vertices[1].z = DGN_INT32( psDGN->abyElem + 56 );
     448                 :           }
     449               3 :           DGNTransformPoint( psDGN, psLine->vertices + 0 );
     450               3 :           DGNTransformPoint( psDGN, psLine->vertices + 1 );
     451                 :       }
     452               3 :       break;
     453                 : 
     454                 :       case DGNT_LINE_STRING:
     455                 :       case DGNT_SHAPE:
     456                 :       case DGNT_CURVE:
     457                 :       case DGNT_BSPLINE_POLE:
     458                 :       {
     459                 :           DGNElemMultiPoint *psLine;
     460                 :           int                i, count;
     461               7 :           int                pntsize = psDGN->dimension * 4;
     462                 : 
     463               7 :           count = psDGN->abyElem[36] + psDGN->abyElem[37]*256;
     464                 :           psLine = (DGNElemMultiPoint *) 
     465               7 :               CPLCalloc(sizeof(DGNElemMultiPoint)+(count-2)*sizeof(DGNPoint),1);
     466               7 :           psElement = (DGNElemCore *) psLine;
     467               7 :           psElement->stype = DGNST_MULTIPOINT;
     468               7 :           DGNParseCore( psDGN, psElement );
     469                 : 
     470               7 :           if( psDGN->nElemBytes < 38 + count * pntsize )
     471                 :           {
     472                 :               CPLError( CE_Warning, CPLE_AppDefined, 
     473                 :                         "Trimming multipoint vertices to %d from %d because\n"
     474                 :                         "element is short.\n", 
     475                 :                         (psDGN->nElemBytes - 38) / pntsize,
     476               0 :                         count );
     477               0 :               count = (psDGN->nElemBytes - 38) / pntsize;
     478                 :           }
     479               7 :           psLine->num_vertices = count;
     480             106 :           for( i = 0; i < psLine->num_vertices; i++ )
     481                 :           {
     482                 :               psLine->vertices[i].x = 
     483              99 :                   DGN_INT32( psDGN->abyElem + 38 + i*pntsize );
     484                 :               psLine->vertices[i].y = 
     485              99 :                   DGN_INT32( psDGN->abyElem + 42 + i*pntsize );
     486              99 :               if( psDGN->dimension == 3 )
     487                 :                   psLine->vertices[i].z = 
     488               0 :                       DGN_INT32( psDGN->abyElem + 46 + i*pntsize );
     489                 : 
     490              99 :               DGNTransformPoint( psDGN, psLine->vertices + i );
     491                 :           }
     492                 :       }
     493               7 :       break;
     494                 : 
     495                 :       case DGNT_TEXT_NODE:
     496                 :       {
     497                 :           DGNElemTextNode *psNode;
     498                 : 
     499               0 :           psNode = (DGNElemTextNode *) CPLCalloc(sizeof(DGNElemTextNode),1);
     500               0 :           psElement = (DGNElemCore *) psNode;
     501               0 :           psElement->stype = DGNST_TEXT_NODE;
     502               0 :           DGNParseCore( psDGN, psElement );
     503                 : 
     504               0 :           psNode->totlength = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
     505               0 :           psNode->numelems  = psDGN->abyElem[38] + psDGN->abyElem[39] * 256;
     506                 : 
     507               0 :           psNode->node_number  = psDGN->abyElem[40] + psDGN->abyElem[41] * 256;
     508               0 :           psNode->max_length   = psDGN->abyElem[42];
     509               0 :           psNode->max_used   = psDGN->abyElem[43];
     510               0 :           psNode->font_id  = psDGN->abyElem[44];
     511               0 :           psNode->justification  = psDGN->abyElem[45];
     512               0 :           psNode->length_mult = (DGN_INT32( psDGN->abyElem + 50 ))
     513               0 :               * psDGN->scale * 6.0 / 1000.0;
     514               0 :           psNode->height_mult = (DGN_INT32( psDGN->abyElem + 54 ))
     515               0 :               * psDGN->scale * 6.0 / 1000.0;
     516                 : 
     517               0 :           if( psDGN->dimension == 2 )
     518                 :       {
     519               0 :         psNode->rotation = DGN_INT32( psDGN->abyElem + 58 ) / 360000.0;
     520                 : 
     521               0 :         psNode->origin.x = DGN_INT32( psDGN->abyElem + 62 );
     522               0 :         psNode->origin.y = DGN_INT32( psDGN->abyElem + 66 );
     523                 :       }
     524                 :     else
     525                 :       {
     526                 :               /* leave quaternion for later */
     527                 : 
     528               0 :               psNode->origin.x = DGN_INT32( psDGN->abyElem + 74 );
     529               0 :               psNode->origin.y = DGN_INT32( psDGN->abyElem + 78 );
     530               0 :               psNode->origin.z = DGN_INT32( psDGN->abyElem + 82 );
     531                 :       }
     532               0 :           DGNTransformPoint( psDGN, &(psNode->origin) );
     533                 : 
     534                 :       }
     535               0 :       break;
     536                 : 
     537                 :       case DGNT_GROUP_DATA:
     538               5 :         if( nLevel == DGN_GDL_COLOR_TABLE )
     539                 :         {
     540               0 :             psElement = DGNParseColorTable( psDGN );
     541                 :         }
     542                 :         else
     543                 :         {
     544               5 :             psElement = (DGNElemCore *) CPLCalloc(sizeof(DGNElemCore),1);
     545               5 :             psElement->stype = DGNST_CORE;
     546               5 :             DGNParseCore( psDGN, psElement );
     547                 :         }
     548               5 :         break;
     549                 : 
     550                 :       case DGNT_ELLIPSE:
     551                 :       {
     552                 :           DGNElemArc *psEllipse;
     553                 : 
     554               5 :           psEllipse = (DGNElemArc *) CPLCalloc(sizeof(DGNElemArc),1);
     555               5 :           psElement = (DGNElemCore *) psEllipse;
     556               5 :           psElement->stype = DGNST_ARC;
     557               5 :           DGNParseCore( psDGN, psElement );
     558                 : 
     559               5 :           memcpy( &(psEllipse->primary_axis), psDGN->abyElem + 36, 8 );
     560               5 :           DGN2IEEEDouble( &(psEllipse->primary_axis) );
     561               5 :           psEllipse->primary_axis *= psDGN->scale;
     562                 : 
     563               5 :           memcpy( &(psEllipse->secondary_axis), psDGN->abyElem + 44, 8 );
     564               5 :           DGN2IEEEDouble( &(psEllipse->secondary_axis) );
     565               5 :           psEllipse->secondary_axis *= psDGN->scale;
     566                 : 
     567               5 :           if( psDGN->dimension == 2 )
     568                 :           {
     569               5 :               psEllipse->rotation = DGN_INT32( psDGN->abyElem + 52 );
     570               5 :               psEllipse->rotation = psEllipse->rotation / 360000.0;
     571                 :               
     572               5 :               memcpy( &(psEllipse->origin.x), psDGN->abyElem + 56, 8 );
     573               5 :               DGN2IEEEDouble( &(psEllipse->origin.x) );
     574                 :               
     575               5 :               memcpy( &(psEllipse->origin.y), psDGN->abyElem + 64, 8 );
     576               5 :               DGN2IEEEDouble( &(psEllipse->origin.y) );
     577                 :           }
     578                 :           else
     579                 :           {
     580                 :               /* leave quaternion for later */
     581                 : 
     582               0 :               memcpy( &(psEllipse->origin.x), psDGN->abyElem + 68, 8 );
     583               0 :               DGN2IEEEDouble( &(psEllipse->origin.x) );
     584                 :               
     585               0 :               memcpy( &(psEllipse->origin.y), psDGN->abyElem + 76, 8 );
     586               0 :               DGN2IEEEDouble( &(psEllipse->origin.y) );
     587                 :               
     588               0 :               memcpy( &(psEllipse->origin.z), psDGN->abyElem + 84, 8 );
     589               0 :               DGN2IEEEDouble( &(psEllipse->origin.z) );
     590                 : 
     591               0 :               psEllipse->quat[0] = DGN_INT32( psDGN->abyElem + 52 );
     592               0 :               psEllipse->quat[1] = DGN_INT32( psDGN->abyElem + 56 );
     593               0 :               psEllipse->quat[2] = DGN_INT32( psDGN->abyElem + 60 );
     594               0 :               psEllipse->quat[3] = DGN_INT32( psDGN->abyElem + 64 );
     595                 :           }
     596                 : 
     597               5 :           DGNTransformPoint( psDGN, &(psEllipse->origin) );
     598                 : 
     599               5 :           psEllipse->startang = 0.0;
     600               5 :           psEllipse->sweepang = 360.0;
     601                 :       }
     602               5 :       break;
     603                 : 
     604                 :       case DGNT_ARC:
     605                 :       {
     606                 :           DGNElemArc *psEllipse;
     607                 :           GInt32     nSweepVal;
     608                 : 
     609               0 :           psEllipse = (DGNElemArc *) CPLCalloc(sizeof(DGNElemArc),1);
     610               0 :           psElement = (DGNElemCore *) psEllipse;
     611               0 :           psElement->stype = DGNST_ARC;
     612               0 :           DGNParseCore( psDGN, psElement );
     613                 : 
     614               0 :           psEllipse->startang = DGN_INT32( psDGN->abyElem + 36 );
     615               0 :           psEllipse->startang = psEllipse->startang / 360000.0;
     616               0 :           if( psDGN->abyElem[41] & 0x80 )
     617                 :           {
     618               0 :               psDGN->abyElem[41] &= 0x7f;
     619               0 :               nSweepVal = -1 * DGN_INT32( psDGN->abyElem + 40 );
     620                 :           }
     621                 :           else
     622               0 :               nSweepVal = DGN_INT32( psDGN->abyElem + 40 );
     623                 : 
     624               0 :           if( nSweepVal == 0 )
     625               0 :               psEllipse->sweepang = 360.0;
     626                 :           else
     627               0 :               psEllipse->sweepang = nSweepVal / 360000.0;
     628                 :           
     629               0 :           memcpy( &(psEllipse->primary_axis), psDGN->abyElem + 44, 8 );
     630               0 :           DGN2IEEEDouble( &(psEllipse->primary_axis) );
     631               0 :           psEllipse->primary_axis *= psDGN->scale;
     632                 : 
     633               0 :           memcpy( &(psEllipse->secondary_axis), psDGN->abyElem + 52, 8 );
     634               0 :           DGN2IEEEDouble( &(psEllipse->secondary_axis) );
     635               0 :           psEllipse->secondary_axis *= psDGN->scale;
     636                 :           
     637               0 :           if( psDGN->dimension == 2 )
     638                 :           {
     639               0 :               psEllipse->rotation = DGN_INT32( psDGN->abyElem + 60 );
     640               0 :               psEllipse->rotation = psEllipse->rotation / 360000.0;
     641                 :           
     642               0 :               memcpy( &(psEllipse->origin.x), psDGN->abyElem + 64, 8 );
     643               0 :               DGN2IEEEDouble( &(psEllipse->origin.x) );
     644                 :               
     645               0 :               memcpy( &(psEllipse->origin.y), psDGN->abyElem + 72, 8 );
     646               0 :               DGN2IEEEDouble( &(psEllipse->origin.y) );
     647                 :           }
     648                 :           else 
     649                 :           {
     650                 :               /* for now we don't try to handle quaternion */
     651               0 :               psEllipse->rotation = 0;
     652                 :           
     653               0 :               memcpy( &(psEllipse->origin.x), psDGN->abyElem + 76, 8 );
     654               0 :               DGN2IEEEDouble( &(psEllipse->origin.x) );
     655                 :               
     656               0 :               memcpy( &(psEllipse->origin.y), psDGN->abyElem + 84, 8 );
     657               0 :               DGN2IEEEDouble( &(psEllipse->origin.y) );
     658                 : 
     659               0 :               memcpy( &(psEllipse->origin.z), psDGN->abyElem + 92, 8 );
     660               0 :               DGN2IEEEDouble( &(psEllipse->origin.z) );
     661                 : 
     662               0 :               psEllipse->quat[0] = DGN_INT32( psDGN->abyElem + 60 );
     663               0 :               psEllipse->quat[1] = DGN_INT32( psDGN->abyElem + 64 );
     664               0 :               psEllipse->quat[2] = DGN_INT32( psDGN->abyElem + 68 );
     665               0 :               psEllipse->quat[3] = DGN_INT32( psDGN->abyElem + 72 );
     666                 :           }
     667                 : 
     668               0 :           DGNTransformPoint( psDGN, &(psEllipse->origin) );
     669                 :       }
     670               0 :       break;
     671                 : 
     672                 :       case DGNT_TEXT:
     673                 :       {
     674                 :           DGNElemText *psText;
     675                 :           int         num_chars, text_off;
     676                 : 
     677               5 :           if( psDGN->dimension == 2 )
     678               5 :               num_chars = psDGN->abyElem[58];
     679                 :           else
     680               0 :               num_chars = psDGN->abyElem[74];
     681                 : 
     682               5 :           psText = (DGNElemText *) CPLCalloc(sizeof(DGNElemText)+num_chars,1);
     683               5 :           psElement = (DGNElemCore *) psText;
     684               5 :           psElement->stype = DGNST_TEXT;
     685               5 :           DGNParseCore( psDGN, psElement );
     686                 : 
     687               5 :           psText->font_id = psDGN->abyElem[36];
     688               5 :           psText->justification = psDGN->abyElem[37];
     689              20 :           psText->length_mult = (DGN_INT32( psDGN->abyElem + 38 ))
     690              20 :               * psDGN->scale * 6.0 / 1000.0;
     691              20 :           psText->height_mult = (DGN_INT32( psDGN->abyElem + 42 ))
     692              20 :               * psDGN->scale * 6.0 / 1000.0;
     693                 : 
     694               5 :           if( psDGN->dimension == 2 )
     695                 :           {
     696               5 :               psText->rotation = DGN_INT32( psDGN->abyElem + 46 );
     697               5 :               psText->rotation = psText->rotation / 360000.0;
     698                 : 
     699               5 :               psText->origin.x = DGN_INT32( psDGN->abyElem + 50 );
     700               5 :               psText->origin.y = DGN_INT32( psDGN->abyElem + 54 );
     701               5 :               text_off = 60;
     702                 :           }
     703                 :           else
     704                 :           {
     705                 :               /* leave quaternion for later */
     706                 : 
     707               0 :               psText->origin.x = DGN_INT32( psDGN->abyElem + 62 );
     708               0 :               psText->origin.y = DGN_INT32( psDGN->abyElem + 66 );
     709               0 :               psText->origin.z = DGN_INT32( psDGN->abyElem + 70 );
     710               0 :               text_off = 76;
     711                 :           }
     712                 : 
     713               5 :           DGNTransformPoint( psDGN, &(psText->origin) );
     714                 : 
     715                 :           /* experimental multibyte support from Ason Kang (hiska@netian.com)*/
     716               5 :           if (*(psDGN->abyElem + text_off) == 0xFF 
     717                 :               && *(psDGN->abyElem + text_off + 1) == 0xFD) 
     718                 :           {
     719               0 :               int n=0;
     720               0 :               for (int i=0;i<num_chars/2-1;i++) {
     721                 :                   unsigned short w;
     722               0 :                   memcpy(&w,psDGN->abyElem + text_off + 2 + i*2 ,2);
     723               0 :                   w = CPL_LSBWORD16(w);
     724               0 :                   if (w<256) { // if alpa-numeric code area : Normal character 
     725               0 :                       *(psText->string + n) = (char) (w & 0xFF); 
     726               0 :                       n++; // skip 1 byte;
     727                 :                   }
     728                 :                   else { // if extend code area : 2 byte Korean character 
     729               0 :                       *(psText->string + n)     = (char) (w >> 8);   // hi
     730               0 :                       *(psText->string + n + 1) = (char) (w & 0xFF); // lo
     731               0 :                       n+=2; // 2 byte
     732                 :                   }
     733                 :               }
     734               0 :               psText->string[n] = '\0'; // terminate C string
     735                 :           }
     736                 :           else
     737                 :           {
     738               5 :               memcpy( psText->string, psDGN->abyElem + text_off, num_chars );
     739               5 :               psText->string[num_chars] = '\0';
     740                 :           }
     741                 :       }
     742               5 :       break;
     743                 : 
     744                 :       case DGNT_TCB:
     745              13 :         psElement = DGNParseTCB( psDGN );
     746              13 :         break;
     747                 : 
     748                 :       case DGNT_COMPLEX_CHAIN_HEADER:
     749                 :       case DGNT_COMPLEX_SHAPE_HEADER:
     750                 :       {
     751                 :           DGNElemComplexHeader *psHdr;
     752                 : 
     753                 :           psHdr = (DGNElemComplexHeader *) 
     754               1 :               CPLCalloc(sizeof(DGNElemComplexHeader),1);
     755               1 :           psElement = (DGNElemCore *) psHdr;
     756               1 :           psElement->stype = DGNST_COMPLEX_HEADER;
     757               1 :           DGNParseCore( psDGN, psElement );
     758                 : 
     759               1 :           psHdr->totlength = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
     760               1 :           psHdr->numelems = psDGN->abyElem[38] + psDGN->abyElem[39] * 256;
     761                 :       }
     762               1 :       break;
     763                 : 
     764                 :       case DGNT_TAG_VALUE:
     765                 :       {
     766                 :           DGNElemTagValue *psTag;
     767                 : 
     768                 :           psTag = (DGNElemTagValue *) 
     769               0 :               CPLCalloc(sizeof(DGNElemTagValue),1);
     770               0 :           psElement = (DGNElemCore *) psTag;
     771               0 :           psElement->stype = DGNST_TAG_VALUE;
     772               0 :           DGNParseCore( psDGN, psElement );
     773                 : 
     774               0 :           psTag->tagType = psDGN->abyElem[74] + psDGN->abyElem[75] * 256;
     775               0 :           memcpy( &(psTag->tagSet), psDGN->abyElem + 68, 4 );
     776               0 :           psTag->tagSet = CPL_LSBWORD32(psTag->tagSet);
     777               0 :           psTag->tagIndex = psDGN->abyElem[72] + psDGN->abyElem[73] * 256;
     778               0 :           psTag->tagLength = psDGN->abyElem[150] + psDGN->abyElem[151] * 256;
     779                 : 
     780               0 :           if( psTag->tagType == 1 )
     781                 :           {
     782                 :               psTag->tagValue.string = 
     783               0 :                   CPLStrdup( (char *) psDGN->abyElem + 154 );
     784                 :           }
     785               0 :           else if( psTag->tagType == 3 )
     786                 :           {
     787                 :               memcpy( &(psTag->tagValue.integer), 
     788               0 :                       psDGN->abyElem + 154, 4 );
     789                 :               psTag->tagValue.integer = 
     790               0 :                   CPL_LSBWORD32( psTag->tagValue.integer );
     791                 :           }
     792               0 :           else if( psTag->tagType == 4 )
     793                 :           {
     794                 :               memcpy( &(psTag->tagValue.real), 
     795               0 :                       psDGN->abyElem + 154, 8 );
     796               0 :               DGN2IEEEDouble( &(psTag->tagValue.real) );
     797                 :           }
     798                 :       }
     799               0 :       break;
     800                 : 
     801                 :       case DGNT_APPLICATION_ELEM:
     802              48 :         if( nLevel == 24 )
     803                 :         {
     804               0 :             psElement = DGNParseTagSet( psDGN );
     805                 :         }
     806                 :         else
     807                 :         {
     808              48 :             psElement = (DGNElemCore *) CPLCalloc(sizeof(DGNElemCore),1);
     809              48 :             psElement->stype = DGNST_CORE;
     810              48 :             DGNParseCore( psDGN, psElement );
     811                 :         }
     812              48 :         break;
     813                 : 
     814                 :       case DGNT_CONE:
     815                 :         {
     816                 :           DGNElemCone *psCone;
     817                 : 
     818               0 :           psCone = (DGNElemCone *) CPLCalloc(sizeof(DGNElemCone),1);
     819               0 :           psElement = (DGNElemCore *) psCone;
     820               0 :           psElement->stype = DGNST_CONE;
     821               0 :           DGNParseCore( psDGN, psElement );
     822                 : 
     823                 :           CPLAssert( psDGN->dimension == 3 );
     824               0 :           psCone->unknown = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
     825               0 :           psCone->quat[0] = DGN_INT32( psDGN->abyElem + 38 );
     826               0 :           psCone->quat[1] = DGN_INT32( psDGN->abyElem + 42 );
     827               0 :           psCone->quat[2] = DGN_INT32( psDGN->abyElem + 46 );
     828               0 :           psCone->quat[3] = DGN_INT32( psDGN->abyElem + 50 );
     829                 :  
     830               0 :           memcpy( &(psCone->center_1.x), psDGN->abyElem + 54, 8 );
     831               0 :           DGN2IEEEDouble( &(psCone->center_1.x) );
     832               0 :           memcpy( &(psCone->center_1.y), psDGN->abyElem + 62, 8 );
     833               0 :           DGN2IEEEDouble( &(psCone->center_1.y) );
     834               0 :           memcpy( &(psCone->center_1.z), psDGN->abyElem + 70, 8 );
     835               0 :           DGN2IEEEDouble( &(psCone->center_1.z) );
     836               0 :           memcpy( &(psCone->radius_1), psDGN->abyElem + 78, 8 );
     837               0 :           DGN2IEEEDouble( &(psCone->radius_1) );
     838                 : 
     839               0 :           memcpy( &(psCone->center_2.x), psDGN->abyElem + 86, 8 );
     840               0 :           DGN2IEEEDouble( &(psCone->center_2.x) );
     841               0 :           memcpy( &(psCone->center_2.y), psDGN->abyElem + 94, 8 );
     842               0 :           DGN2IEEEDouble( &(psCone->center_2.y) );
     843               0 :           memcpy( &(psCone->center_2.z), psDGN->abyElem + 102, 8 );
     844               0 :           DGN2IEEEDouble( &(psCone->center_2.z) );
     845               0 :           memcpy( &(psCone->radius_2), psDGN->abyElem + 110, 8 );
     846               0 :           DGN2IEEEDouble( &(psCone->radius_2) );
     847                 : 
     848               0 :           psCone->radius_1 *= psDGN->scale;
     849               0 :           psCone->radius_2 *= psDGN->scale;
     850               0 :           DGNTransformPoint( psDGN, &psCone->center_1 );
     851               0 :           DGNTransformPoint( psDGN, &psCone->center_2 );
     852                 :         }
     853               0 :         break;
     854                 : 
     855                 :       case DGNT_3DSURFACE_HEADER:
     856                 :       case DGNT_3DSOLID_HEADER:
     857                 :         {
     858                 :           DGNElemComplexHeader *psShape;
     859                 : 
     860                 :           psShape = 
     861               0 :             (DGNElemComplexHeader *) CPLCalloc(sizeof(DGNElemComplexHeader),1);
     862               0 :           psElement = (DGNElemCore *) psShape;
     863               0 :           psElement->stype = DGNST_COMPLEX_HEADER;
     864               0 :           DGNParseCore( psDGN, psElement );
     865                 : 
     866                 :           // Read complex header
     867               0 :           psShape->totlength = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
     868               0 :           psShape->numelems = psDGN->abyElem[38] + psDGN->abyElem[39] * 256;
     869               0 :           psShape->surftype = psDGN->abyElem[40];
     870               0 :           psShape->boundelms = psDGN->abyElem[41] + 1;
     871                 :         }
     872               0 :         break;
     873                 :       case DGNT_BSPLINE_SURFACE_HEADER:
     874                 :         {
     875                 :           DGNElemBSplineSurfaceHeader *psSpline;
     876                 : 
     877                 :           psSpline = (DGNElemBSplineSurfaceHeader *)
     878               0 :             CPLCalloc(sizeof(DGNElemBSplineSurfaceHeader), 1);
     879               0 :           psElement = (DGNElemCore *) psSpline;
     880               0 :           psElement->stype = DGNST_BSPLINE_SURFACE_HEADER;
     881               0 :           DGNParseCore( psDGN, psElement );
     882                 : 
     883                 :           // Read B-Spline surface header
     884               0 :           psSpline->desc_words = DGN_INT32(psDGN->abyElem + 36);
     885               0 :           psSpline->curve_type = psDGN->abyElem[41];
     886                 : 
     887                 :           // U
     888               0 :           psSpline->u_order = (psDGN->abyElem[40] & 0x0f) + 2;
     889               0 :           psSpline->u_properties = psDGN->abyElem[40] & 0xf0;
     890               0 :           psSpline->num_poles_u = psDGN->abyElem[42] + psDGN->abyElem[43]*256;
     891               0 :           psSpline->num_knots_u = psDGN->abyElem[44] + psDGN->abyElem[45]*256;
     892               0 :           psSpline->rule_lines_u = psDGN->abyElem[46] + psDGN->abyElem[47]*256;
     893                 : 
     894                 :           // V
     895               0 :           psSpline->v_order = (psDGN->abyElem[48] & 0x0f) + 2;
     896               0 :           psSpline->v_properties = psDGN->abyElem[48] & 0xf0;
     897               0 :           psSpline->num_poles_v = psDGN->abyElem[50] + psDGN->abyElem[51]*256;
     898               0 :           psSpline->num_knots_v = psDGN->abyElem[52] + psDGN->abyElem[53]*256;
     899               0 :           psSpline->rule_lines_v = psDGN->abyElem[54] + psDGN->abyElem[55]*256;
     900                 : 
     901               0 :           psSpline->num_bounds = psDGN->abyElem[56] + psDGN->abyElem[57]*556;
     902                 :         }
     903               0 :       break;
     904                 :       case DGNT_BSPLINE_CURVE_HEADER:
     905                 :         {
     906                 :           DGNElemBSplineCurveHeader *psSpline;
     907                 : 
     908                 :           psSpline = (DGNElemBSplineCurveHeader *)
     909               0 :             CPLCalloc(sizeof(DGNElemBSplineCurveHeader), 1);
     910               0 :           psElement = (DGNElemCore *) psSpline;
     911               0 :           psElement->stype = DGNST_BSPLINE_CURVE_HEADER;
     912               0 :           DGNParseCore( psDGN, psElement );
     913                 : 
     914                 :           // Read B-Spline curve header
     915               0 :           psSpline->desc_words = DGN_INT32(psDGN->abyElem + 36);
     916                 : 
     917                 :           // flags
     918               0 :           psSpline->order = (psDGN->abyElem[40] & 0x0f) + 2;
     919               0 :           psSpline->properties = psDGN->abyElem[40] & 0xf0;
     920               0 :           psSpline->curve_type = psDGN->abyElem[41];
     921                 : 
     922               0 :           psSpline->num_poles = psDGN->abyElem[42] + psDGN->abyElem[43]*256;
     923               0 :           psSpline->num_knots = psDGN->abyElem[44] + psDGN->abyElem[45]*256;
     924                 :         }
     925               0 :       break;
     926                 :       case DGNT_BSPLINE_SURFACE_BOUNDARY:
     927                 :         {
     928                 :           DGNElemBSplineSurfaceBoundary *psBounds;
     929               0 :           int numverts = psDGN->abyElem[38] + psDGN->abyElem[39]*256;
     930                 : 
     931                 :           psBounds = (DGNElemBSplineSurfaceBoundary *)
     932                 :             CPLCalloc(sizeof(DGNElemBSplineSurfaceBoundary)+
     933               0 :                       (numverts-1)*sizeof(DGNPoint), 1);
     934               0 :           psElement = (DGNElemCore *) psBounds;
     935               0 :           psElement->stype = DGNST_BSPLINE_SURFACE_BOUNDARY;
     936               0 :           DGNParseCore( psDGN, psElement );
     937                 : 
     938                 :           // Read B-Spline surface boundary
     939               0 :           psBounds->number = psDGN->abyElem[36] + psDGN->abyElem[37]*256;
     940               0 :           psBounds->numverts = numverts;
     941                 : 
     942               0 :           for (int i=0;i<psBounds->numverts;i++) {
     943               0 :             psBounds->vertices[i].x = DGN_INT32( psDGN->abyElem + 40 + i*8 );
     944               0 :             psBounds->vertices[i].y = DGN_INT32( psDGN->abyElem + 44 + i*8 );
     945               0 :             psBounds->vertices[i].z = 0;
     946                 :           }
     947                 :         }
     948               0 :       break;
     949                 :       case DGNT_BSPLINE_KNOT:
     950                 :       case DGNT_BSPLINE_WEIGHT_FACTOR:
     951                 :         {
     952                 :           DGNElemKnotWeight *psArray;
     953                 :           // FIXME: Is it OK to assume that the # of elements corresponds
     954                 :           // directly to the element size? kintel 20051215.
     955                 :           int attr_bytes = psDGN->nElemBytes - 
     956               0 :             (psDGN->abyElem[30] + psDGN->abyElem[31]*256)*2 - 32;
     957               0 :           int numelems = (psDGN->nElemBytes - 36 - attr_bytes)/4;
     958                 : 
     959                 :           psArray = (DGNElemKnotWeight *)
     960               0 :             CPLCalloc(sizeof(DGNElemKnotWeight) + (numelems-1)*sizeof(float), 1);
     961                 : 
     962               0 :           psElement = (DGNElemCore *) psArray;
     963               0 :           psElement->stype = DGNST_KNOT_WEIGHT;
     964               0 :           DGNParseCore( psDGN, psElement );
     965                 : 
     966                 :           // Read array
     967               0 :           for (int i=0;i<numelems;i++) {
     968               0 :             psArray->array[i] = 
     969               0 :               1.0f * DGN_INT32(psDGN->abyElem + 36 + i*4) / ((1L << 31) - 1);
     970                 :           }
     971                 :         }
     972               0 :       break;
     973                 :       case DGNT_SHARED_CELL_DEFN:
     974                 :       {
     975                 :           DGNElemSharedCellDefn *psShared;
     976                 : 
     977                 :           psShared = (DGNElemSharedCellDefn *) 
     978               0 :               CPLCalloc(sizeof(DGNElemSharedCellDefn),1);
     979               0 :           psElement = (DGNElemCore *) psShared;
     980               0 :           psElement->stype = DGNST_SHARED_CELL_DEFN;
     981               0 :           DGNParseCore( psDGN, psElement );
     982                 : 
     983               0 :           psShared->totlength = psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
     984                 :       }
     985               0 :       break;
     986                 :       default:
     987                 :       {
     988              14 :           psElement = (DGNElemCore *) CPLCalloc(sizeof(DGNElemCore),1);
     989              14 :           psElement->stype = DGNST_CORE;
     990              14 :           DGNParseCore( psDGN, psElement );
     991                 :       }
     992                 :       break;
     993                 :     }
     994                 : 
     995                 : /* -------------------------------------------------------------------- */
     996                 : /*      If the element structure type is "core" or if we are running    */
     997                 : /*      in "capture all" mode, record the complete binary image of      */
     998                 : /*      the element.                                                    */
     999                 : /* -------------------------------------------------------------------- */
    1000             101 :     if( psElement->stype == DGNST_CORE 
    1001                 :         || (psDGN->options & DGNO_CAPTURE_RAW_DATA) )
    1002                 :     {
    1003              68 :         psElement->raw_bytes = psDGN->nElemBytes;
    1004              68 :         psElement->raw_data = (unsigned char *)CPLMalloc(psElement->raw_bytes);
    1005                 : 
    1006              68 :         memcpy( psElement->raw_data, psDGN->abyElem, psElement->raw_bytes );
    1007                 :     }
    1008                 : 
    1009                 : /* -------------------------------------------------------------------- */
    1010                 : /*      Collect some additional generic information.                    */
    1011                 : /* -------------------------------------------------------------------- */
    1012             101 :     psElement->element_id = psDGN->next_element_id - 1;
    1013                 : 
    1014             101 :     psElement->offset = VSIFTell( psDGN->fp ) - psDGN->nElemBytes;
    1015             101 :     psElement->size = psDGN->nElemBytes;
    1016                 : 
    1017             101 :     return psElement;
    1018                 : }
    1019                 : 
    1020                 : /************************************************************************/
    1021                 : /*                           DGNReadElement()                           */
    1022                 : /************************************************************************/
    1023                 : 
    1024                 : /**
    1025                 :  * Read a DGN element.
    1026                 :  *
    1027                 :  * This function will return the next element in the file, starting with the
    1028                 :  * first.  It is affected by DGNGotoElement() calls. 
    1029                 :  *
    1030                 :  * The element is read into a structure which includes the DGNElemCore 
    1031                 :  * structure.  It is expected that applications will inspect the stype
    1032                 :  * field of the returned DGNElemCore and use it to cast the pointer to the
    1033                 :  * appropriate element structure type such as DGNElemMultiPoint. 
    1034                 :  *
    1035                 :  * @param hDGN the handle of the file to read from.
    1036                 :  *
    1037                 :  * @return pointer to element structure, or NULL on EOF or processing error.
    1038                 :  * The structure should be freed with DGNFreeElement() when no longer needed.
    1039                 :  */
    1040                 : 
    1041             105 : DGNElemCore *DGNReadElement( DGNHandle hDGN )
    1042                 : 
    1043                 : {
    1044             105 :     DGNInfo     *psDGN = (DGNInfo *) hDGN;
    1045             105 :     DGNElemCore *psElement = NULL;
    1046                 :     int         nType, nLevel;
    1047                 :     int         bInsideFilter;
    1048                 : 
    1049                 : /* -------------------------------------------------------------------- */
    1050                 : /*      Load the element data into the current buffer.  If a spatial    */
    1051                 : /*      filter is in effect, loop until we get something within our     */
    1052                 : /*      spatial constraints.                                            */
    1053                 : /* -------------------------------------------------------------------- */
    1054             104 :     do { 
    1055             108 :         bInsideFilter = TRUE;
    1056                 : 
    1057             108 :         if( !DGNLoadRawElement( psDGN, &nType, &nLevel ) )
    1058               4 :             return NULL;
    1059                 :         
    1060             104 :         if( psDGN->has_spatial_filter )
    1061                 :         {
    1062                 :             GUInt32     nXMin, nXMax, nYMin, nYMax;
    1063                 :             
    1064              15 :             if( !psDGN->sf_converted_to_uor )
    1065               0 :                 DGNSpatialFilterToUOR( psDGN );
    1066                 : 
    1067              15 :             if( !DGNGetRawExtents( psDGN, nType, NULL,
    1068                 :                                    &nXMin, &nYMin, NULL,
    1069                 :                                    &nXMax, &nYMax, NULL ) )
    1070                 :             {
    1071                 :                 /* If we don't have spatial characterists for the element
    1072                 :                    we will pass it through. */
    1073              11 :                 bInsideFilter = TRUE;
    1074                 :             }
    1075               4 :             else if( nXMin > psDGN->sf_max_x
    1076                 :                      || nYMin > psDGN->sf_max_y
    1077                 :                      || nXMax < psDGN->sf_min_x
    1078                 :                      || nYMax < psDGN->sf_min_y )
    1079               3 :                 bInsideFilter = FALSE;
    1080                 : 
    1081                 :             /*
    1082                 :             ** We want to select complex elements based on the extents of
    1083                 :             ** the header, not the individual elements.
    1084                 :             */
    1085              15 :             if( nType == DGNT_COMPLEX_CHAIN_HEADER
    1086                 :                 || nType == DGNT_COMPLEX_SHAPE_HEADER )
    1087                 :             {
    1088               0 :                 psDGN->in_complex_group = TRUE;
    1089               0 :                 psDGN->select_complex_group = bInsideFilter;
    1090                 :             }
    1091              15 :             else if( psDGN->abyElem[0] & 0x80 /* complex flag set */ )
    1092                 :             {
    1093               0 :                 if( psDGN->in_complex_group )
    1094               0 :                     bInsideFilter = psDGN->select_complex_group;
    1095                 :             }
    1096                 :             else
    1097              15 :                 psDGN->in_complex_group = FALSE;
    1098                 :         }
    1099                 :     } while( !bInsideFilter );
    1100                 : 
    1101                 : /* -------------------------------------------------------------------- */
    1102                 : /*      Convert into an element structure.                              */
    1103                 : /* -------------------------------------------------------------------- */
    1104             101 :     psElement = DGNProcessElement( psDGN, nType, nLevel );
    1105                 : 
    1106             101 :     return psElement;
    1107                 : }
    1108                 : 
    1109                 : /************************************************************************/
    1110                 : /*                       DGNElemTypeHasDispHdr()                        */
    1111                 : /************************************************************************/
    1112                 : 
    1113                 : /**
    1114                 :  * Does element type have display header.
    1115                 :  *
    1116                 :  * @param nElemType element type (0-63) to test. 
    1117                 :  *
    1118                 :  * @return TRUE if elements of passed in type have a display header after the
    1119                 :  * core element header, or FALSE otherwise. 
    1120                 :  */
    1121                 : 
    1122             119 : int DGNElemTypeHasDispHdr( int nElemType )
    1123                 : 
    1124                 : {
    1125             119 :     switch( nElemType )
    1126                 :     {
    1127                 :       case 0:
    1128                 :       case DGNT_TCB:
    1129                 :       case DGNT_CELL_LIBRARY:
    1130                 :       case DGNT_LEVEL_SYMBOLOGY:
    1131                 :       case 32:
    1132                 :       case 44:
    1133                 :       case 48:
    1134                 :       case 49:
    1135                 :       case 50:
    1136                 :       case 51:
    1137                 :       case 57:
    1138                 :       case 60:
    1139                 :       case 61:
    1140                 :       case 62:
    1141                 :       case 63:
    1142              26 :         return FALSE;
    1143                 :         
    1144                 :       default:
    1145              93 :         return TRUE;
    1146                 :     }
    1147                 : }
    1148                 : 
    1149                 : 
    1150                 : /************************************************************************/
    1151                 : /*                            DGNParseCore()                            */
    1152                 : /************************************************************************/
    1153                 : 
    1154             107 : int DGNParseCore( DGNInfo *psDGN, DGNElemCore *psElement )
    1155                 : 
    1156                 : {
    1157             107 :     GByte       *psData = psDGN->abyElem+0;
    1158                 : 
    1159             107 :     psElement->level = psData[0] & 0x3f;
    1160             107 :     psElement->complex = psData[0] & 0x80;
    1161             107 :     psElement->deleted = psData[1] & 0x80;
    1162             107 :     psElement->type = psData[1] & 0x7f;
    1163                 : 
    1164             107 :     if( psDGN->nElemBytes >= 36 && DGNElemTypeHasDispHdr( psElement->type ) )
    1165                 :     {
    1166              81 :         psElement->graphic_group = psData[28] + psData[29] * 256;
    1167              81 :         psElement->properties = psData[32] + psData[33] * 256;
    1168              81 :         psElement->style = psData[34] & 0x7;
    1169              81 :         psElement->weight = (psData[34] & 0xf8) >> 3;
    1170              81 :         psElement->color = psData[35];
    1171                 :     }
    1172                 :     else
    1173                 :     {
    1174              26 :         psElement->graphic_group = 0;
    1175              26 :         psElement->properties = 0;
    1176              26 :         psElement->style = 0;
    1177              26 :         psElement->weight = 0;
    1178              26 :         psElement->color = 0;
    1179                 :     }
    1180                 : 
    1181             107 :     if( psElement->properties & DGNPF_ATTRIBUTES )
    1182                 :     {
    1183                 :         int   nAttIndex;
    1184                 :         
    1185               5 :         nAttIndex = psData[30] + psData[31] * 256;
    1186                 : 
    1187               5 :         psElement->attr_bytes = psDGN->nElemBytes - nAttIndex*2 - 32;
    1188               5 :         if( psElement->attr_bytes > 0 )
    1189                 :         {
    1190                 :             psElement->attr_data = (unsigned char *) 
    1191               5 :                 CPLMalloc(psElement->attr_bytes);
    1192                 :             memcpy( psElement->attr_data, psData + nAttIndex * 2 + 32,
    1193               5 :                     psElement->attr_bytes );
    1194                 :         }
    1195                 :         else
    1196                 :         {
    1197                 :             CPLError(
    1198                 :                 CE_Warning, CPLE_AppDefined, 
    1199                 :                 "Computed %d bytes for attribute info on element,\n"
    1200                 :                 "perhaps this element type doesn't really have a disphdr?",
    1201               0 :                 psElement->attr_bytes );
    1202               0 :             psElement->attr_bytes = 0;
    1203                 :         }
    1204                 :     }
    1205                 :     
    1206             107 :     return TRUE;
    1207                 : }
    1208                 : 
    1209                 : /************************************************************************/
    1210                 : /*                         DGNParseColorTable()                         */
    1211                 : /************************************************************************/
    1212                 : 
    1213               0 : static DGNElemCore *DGNParseColorTable( DGNInfo * psDGN )
    1214                 : 
    1215                 : {
    1216                 :     DGNElemCore *psElement;
    1217                 :     DGNElemColorTable  *psColorTable;
    1218                 :             
    1219                 :     psColorTable = (DGNElemColorTable *) 
    1220               0 :         CPLCalloc(sizeof(DGNElemColorTable),1);
    1221               0 :     psElement = (DGNElemCore *) psColorTable;
    1222               0 :     psElement->stype = DGNST_COLORTABLE;
    1223                 : 
    1224               0 :     DGNParseCore( psDGN, psElement );
    1225                 : 
    1226                 :     psColorTable->screen_flag = 
    1227               0 :         psDGN->abyElem[36] + psDGN->abyElem[37] * 256;
    1228                 : 
    1229               0 :     memcpy( psColorTable->color_info[255], psDGN->abyElem+38, 3 );
    1230               0 :     memcpy( psColorTable->color_info, psDGN->abyElem+41, 765 ); 
    1231                 : 
    1232                 :     // We used to only install a color table as the default color
    1233                 :     // table if it was the first in the file.  But apparently we should
    1234                 :     // really be using the last one.  This doesn't necessarily accomplish
    1235                 :     // that either if the elements are being read out of order but it will
    1236                 :     // usually do better at least. 
    1237               0 :     memcpy( psDGN->color_table, psColorTable->color_info, 768 );
    1238               0 :     psDGN->got_color_table = 1;
    1239                 :     
    1240               0 :     return psElement;
    1241                 : }
    1242                 : 
    1243                 : /************************************************************************/
    1244                 : /*                           DGNParseTagSet()                           */
    1245                 : /************************************************************************/
    1246                 : 
    1247               0 : static DGNElemCore *DGNParseTagSet( DGNInfo * psDGN )
    1248                 : 
    1249                 : {
    1250                 :     DGNElemCore *psElement;
    1251                 :     DGNElemTagSet *psTagSet;
    1252                 :     int          nDataOffset, iTag;
    1253                 :             
    1254               0 :     psTagSet = (DGNElemTagSet *) CPLCalloc(sizeof(DGNElemTagSet),1);
    1255               0 :     psElement = (DGNElemCore *) psTagSet;
    1256               0 :     psElement->stype = DGNST_TAG_SET;
    1257                 : 
    1258               0 :     DGNParseCore( psDGN, psElement );
    1259                 : 
    1260                 : /* -------------------------------------------------------------------- */
    1261                 : /*      Parse the overall information.                                  */
    1262                 : /* -------------------------------------------------------------------- */
    1263                 :     psTagSet->tagCount = 
    1264               0 :         psDGN->abyElem[44] + psDGN->abyElem[45] * 256;
    1265                 :     psTagSet->flags = 
    1266               0 :         psDGN->abyElem[46] + psDGN->abyElem[47] * 256;
    1267               0 :     psTagSet->tagSetName = CPLStrdup( (const char *) (psDGN->abyElem + 48) );
    1268                 : 
    1269                 : /* -------------------------------------------------------------------- */
    1270                 : /*      Get the tag set number out of the attributes, if available.     */
    1271                 : /* -------------------------------------------------------------------- */
    1272               0 :     psTagSet->tagSet = -1;
    1273                 : 
    1274               0 :     if( psElement->attr_bytes >= 8 
    1275               0 :         && psElement->attr_data[0] == 0x03
    1276               0 :         && psElement->attr_data[1] == 0x10
    1277               0 :         && psElement->attr_data[2] == 0x2f
    1278               0 :         && psElement->attr_data[3] == 0x7d )
    1279               0 :         psTagSet->tagSet = psElement->attr_data[4]
    1280               0 :             + psElement->attr_data[5] * 256;
    1281                 : 
    1282                 : /* -------------------------------------------------------------------- */
    1283                 : /*      Parse each of the tag definitions.                              */
    1284                 : /* -------------------------------------------------------------------- */
    1285                 :     psTagSet->tagList = (DGNTagDef *) 
    1286               0 :         CPLMalloc(sizeof(DGNTagDef) * psTagSet->tagCount);
    1287                 : 
    1288               0 :     nDataOffset = 48 + strlen(psTagSet->tagSetName) + 1 + 1; 
    1289                 : 
    1290               0 :     for( iTag = 0; iTag < psTagSet->tagCount; iTag++ )
    1291                 :     {
    1292               0 :         DGNTagDef *tagDef = psTagSet->tagList + iTag;
    1293                 : 
    1294                 :         CPLAssert( nDataOffset < psDGN->nElemBytes );
    1295                 : 
    1296                 :         /* collect tag name. */
    1297               0 :         tagDef->name = CPLStrdup( (char *) psDGN->abyElem + nDataOffset );
    1298               0 :         nDataOffset += strlen(tagDef->name)+1;
    1299                 : 
    1300                 :         /* Get tag id */
    1301               0 :         tagDef->id = psDGN->abyElem[nDataOffset]
    1302               0 :             + psDGN->abyElem[nDataOffset+1] * 256;
    1303               0 :         nDataOffset += 2;
    1304                 : 
    1305                 :         /* Get User Prompt */
    1306               0 :         tagDef->prompt = CPLStrdup( (char *) psDGN->abyElem + nDataOffset );
    1307               0 :         nDataOffset += strlen(tagDef->prompt)+1;
    1308                 : 
    1309                 : 
    1310                 :         /* Get type */
    1311               0 :         tagDef->type = psDGN->abyElem[nDataOffset]
    1312               0 :             + psDGN->abyElem[nDataOffset+1] * 256;
    1313               0 :         nDataOffset += 2;
    1314                 : 
    1315                 :         /* skip five zeros */
    1316               0 :         nDataOffset += 5;
    1317                 : 
    1318                 :         /* Get the default */
    1319               0 :         if( tagDef->type == 1 )
    1320                 :         {
    1321                 :             tagDef->defaultValue.string = 
    1322               0 :                 CPLStrdup( (char *) psDGN->abyElem + nDataOffset );
    1323               0 :             nDataOffset += strlen(tagDef->defaultValue.string)+1;
    1324                 :         }
    1325               0 :         else if( tagDef->type == 3 || tagDef->type == 5 )
    1326                 :         {
    1327                 :             memcpy( &(tagDef->defaultValue.integer), 
    1328               0 :                     psDGN->abyElem + nDataOffset, 4 );
    1329                 :             tagDef->defaultValue.integer = 
    1330               0 :                 CPL_LSBWORD32( tagDef->defaultValue.integer );
    1331               0 :             nDataOffset += 4;
    1332                 :         }
    1333               0 :         else if( tagDef->type == 4 )
    1334                 :         {
    1335                 :             memcpy( &(tagDef->defaultValue.real), 
    1336               0 :                     psDGN->abyElem + nDataOffset, 8 );
    1337               0 :             DGN2IEEEDouble( &(tagDef->defaultValue.real) );
    1338               0 :             nDataOffset += 8;
    1339                 :         }
    1340                 :         else
    1341               0 :             nDataOffset += 4;
    1342                 :     }
    1343               0 :     return psElement;
    1344                 : }
    1345                 : 
    1346                 : /************************************************************************/
    1347                 : /*                            DGNParseTCB()                             */
    1348                 : /************************************************************************/
    1349                 : 
    1350              19 : static DGNElemCore *DGNParseTCB( DGNInfo * psDGN )
    1351                 : 
    1352                 : {
    1353                 :     DGNElemTCB *psTCB;
    1354                 :     DGNElemCore *psElement;
    1355                 :     int iView;
    1356                 : 
    1357              19 :     psTCB = (DGNElemTCB *) CPLCalloc(sizeof(DGNElemTCB),1);
    1358              19 :     psElement = (DGNElemCore *) psTCB;
    1359              19 :     psElement->stype = DGNST_TCB;
    1360              19 :     DGNParseCore( psDGN, psElement );
    1361                 : 
    1362              19 :     if( psDGN->abyElem[1214] & 0x40 )
    1363               0 :         psTCB->dimension = 3;
    1364                 :     else
    1365              19 :         psTCB->dimension = 2;
    1366                 :           
    1367              19 :     psTCB->subunits_per_master = DGN_INT32( psDGN->abyElem + 1112 );
    1368                 : 
    1369              19 :     psTCB->master_units[0] = (char) psDGN->abyElem[1120];
    1370              19 :     psTCB->master_units[1] = (char) psDGN->abyElem[1121];
    1371              19 :     psTCB->master_units[2] = '\0';
    1372                 : 
    1373              19 :     psTCB->uor_per_subunit = DGN_INT32( psDGN->abyElem + 1116 );
    1374                 : 
    1375              19 :     psTCB->sub_units[0] = (char) psDGN->abyElem[1122];
    1376              19 :     psTCB->sub_units[1] = (char) psDGN->abyElem[1123];
    1377              19 :     psTCB->sub_units[2] = '\0';
    1378                 : 
    1379                 :     /* Get global origin */
    1380              19 :     memcpy( &(psTCB->origin_x), psDGN->abyElem+1240, 8 );
    1381              19 :     memcpy( &(psTCB->origin_y), psDGN->abyElem+1248, 8 );
    1382              19 :     memcpy( &(psTCB->origin_z), psDGN->abyElem+1256, 8 );
    1383                 : 
    1384                 :     /* Transform to IEEE */
    1385              19 :     DGN2IEEEDouble( &(psTCB->origin_x) );
    1386              19 :     DGN2IEEEDouble( &(psTCB->origin_y) );
    1387              19 :     DGN2IEEEDouble( &(psTCB->origin_z) );
    1388                 : 
    1389                 :     /* Convert from UORs to master units. */
    1390              19 :     if( psTCB->uor_per_subunit != 0
    1391                 :         && psTCB->subunits_per_master != 0 )
    1392                 :     {
    1393                 :         psTCB->origin_x = psTCB->origin_x / 
    1394              12 :             (psTCB->uor_per_subunit * psTCB->subunits_per_master);
    1395                 :         psTCB->origin_y = psTCB->origin_y / 
    1396              12 :             (psTCB->uor_per_subunit * psTCB->subunits_per_master);
    1397                 :         psTCB->origin_z = psTCB->origin_z / 
    1398              12 :             (psTCB->uor_per_subunit * psTCB->subunits_per_master);
    1399                 :     }
    1400                 : 
    1401              19 :     if( !psDGN->got_tcb )
    1402                 :     {
    1403               5 :         psDGN->got_tcb = TRUE;
    1404               5 :         psDGN->dimension = psTCB->dimension;
    1405               5 :         psDGN->origin_x = psTCB->origin_x;
    1406               5 :         psDGN->origin_y = psTCB->origin_y;
    1407               5 :         psDGN->origin_z = psTCB->origin_z;
    1408                 : 
    1409               5 :         if( psTCB->uor_per_subunit != 0
    1410                 :             && psTCB->subunits_per_master != 0 )
    1411                 :             psDGN->scale = 1.0 
    1412               5 :                 / (psTCB->uor_per_subunit * psTCB->subunits_per_master);
    1413                 :     }
    1414                 : 
    1415                 :     /* Collect views */
    1416             171 :     for( iView = 0; iView < 8; iView++ )
    1417                 :     {
    1418             152 :         unsigned char *pabyRawView = psDGN->abyElem + 46 + iView*118;
    1419             152 :         DGNViewInfo *psView = psTCB->views + iView;
    1420                 :         int i;
    1421                 : 
    1422             152 :         psView->flags = pabyRawView[0] + pabyRawView[1] * 256;
    1423             152 :         memcpy( psView->levels, pabyRawView + 2, 8 );
    1424                 :         
    1425             152 :         psView->origin.x = DGN_INT32( pabyRawView + 10 );
    1426             152 :         psView->origin.y = DGN_INT32( pabyRawView + 14 );
    1427             152 :         psView->origin.z = DGN_INT32( pabyRawView + 18 );
    1428                 : 
    1429             152 :         DGNTransformPoint( psDGN, &(psView->origin) );
    1430                 : 
    1431             152 :         psView->delta.x = DGN_INT32( pabyRawView + 22 );
    1432             152 :         psView->delta.y = DGN_INT32( pabyRawView + 26 );
    1433             152 :         psView->delta.z = DGN_INT32( pabyRawView + 30 );
    1434                 : 
    1435             152 :         psView->delta.x *= psDGN->scale;
    1436             152 :         psView->delta.y *= psDGN->scale;
    1437             152 :         psView->delta.z *= psDGN->scale;
    1438                 : 
    1439             152 :         memcpy( psView->transmatrx, pabyRawView + 34, sizeof(double) * 9 );
    1440            1520 :         for( i = 0; i < 9; i++ )
    1441            1368 :             DGN2IEEEDouble( psView->transmatrx + i );
    1442                 : 
    1443             152 :         memcpy( &(psView->conversion), pabyRawView + 106, sizeof(double) );
    1444             152 :         DGN2IEEEDouble( &(psView->conversion) );
    1445                 : 
    1446             152 :         psView->activez = DGN_INT32( pabyRawView + 114 );
    1447                 :     }
    1448                 : 
    1449              19 :     return psElement;
    1450                 : }
    1451                 : 
    1452                 : /************************************************************************/
    1453                 : /*                           DGNFreeElement()                           */
    1454                 : /************************************************************************/
    1455                 : 
    1456                 : /**
    1457                 :  * Free an element structure.
    1458                 :  *
    1459                 :  * This function will deallocate all resources associated with any element
    1460                 :  * structure returned by DGNReadElement(). 
    1461                 :  *
    1462                 :  * @param hDGN handle to file from which the element was read.
    1463                 :  * @param psElement the element structure returned by DGNReadElement().
    1464                 :  */
    1465                 : 
    1466             124 : void DGNFreeElement( DGNHandle hDGN, DGNElemCore *psElement )
    1467                 : 
    1468                 : {
    1469             124 :     if( psElement->attr_data != NULL )
    1470               6 :         VSIFree( psElement->attr_data );
    1471                 : 
    1472             124 :     if( psElement->raw_data != NULL )
    1473              85 :         VSIFree( psElement->raw_data );
    1474                 : 
    1475             124 :     if( psElement->stype == DGNST_TAG_SET )
    1476                 :     {
    1477                 :         int             iTag;
    1478                 : 
    1479               0 :         DGNElemTagSet *psTagSet = (DGNElemTagSet *) psElement;
    1480               0 :         CPLFree( psTagSet->tagSetName );
    1481                 : 
    1482               0 :         for( iTag = 0; iTag < psTagSet->tagCount; iTag++ )
    1483                 :         {
    1484               0 :             CPLFree( psTagSet->tagList[iTag].name );
    1485               0 :             CPLFree( psTagSet->tagList[iTag].prompt );
    1486                 : 
    1487               0 :             if( psTagSet->tagList[iTag].type == 1 )
    1488               0 :                 CPLFree( psTagSet->tagList[iTag].defaultValue.string );
    1489                 :         }
    1490               0 :         CPLFree( psTagSet->tagList );
    1491                 :     }
    1492             124 :     else if( psElement->stype == DGNST_TAG_VALUE )
    1493                 :     {
    1494               0 :         if( ((DGNElemTagValue *) psElement)->tagType == 1 )
    1495               0 :             CPLFree( ((DGNElemTagValue *) psElement)->tagValue.string );
    1496                 :     }
    1497                 : 
    1498             124 :     CPLFree( psElement );
    1499             124 : }
    1500                 : 
    1501                 : /************************************************************************/
    1502                 : /*                             DGNRewind()                              */
    1503                 : /************************************************************************/
    1504                 : 
    1505                 : /**
    1506                 :  * Rewind element reading.
    1507                 :  *
    1508                 :  * Rewind the indicated DGN file, so the next element read with 
    1509                 :  * DGNReadElement() will be the first.  Does not require indexing like
    1510                 :  * the more general DGNReadElement() function.
    1511                 :  *
    1512                 :  * @param hDGN handle to file.
    1513                 :  */
    1514                 : 
    1515              17 : void DGNRewind( DGNHandle hDGN )
    1516                 : 
    1517                 : {
    1518              17 :     DGNInfo     *psDGN = (DGNInfo *) hDGN;
    1519                 : 
    1520              17 :     VSIRewind( psDGN->fp );
    1521                 : 
    1522              17 :     psDGN->next_element_id = 0;
    1523              17 :     psDGN->in_complex_group = FALSE;
    1524              17 : }
    1525                 : 
    1526                 : /************************************************************************/
    1527                 : /*                         DGNTransformPoint()                          */
    1528                 : /************************************************************************/
    1529                 : 
    1530             271 : void DGNTransformPoint( DGNInfo *psDGN, DGNPoint *psPoint )
    1531                 : 
    1532                 : {
    1533             271 :     psPoint->x = psPoint->x * psDGN->scale - psDGN->origin_x;
    1534             271 :     psPoint->y = psPoint->y * psDGN->scale - psDGN->origin_y;
    1535             271 :     psPoint->z = psPoint->z * psDGN->scale - psDGN->origin_z;
    1536             271 : }
    1537                 : 
    1538                 : /************************************************************************/
    1539                 : /*                      DGNInverseTransformPoint()                      */
    1540                 : /************************************************************************/
    1541                 : 
    1542               2 : void DGNInverseTransformPoint( DGNInfo *psDGN, DGNPoint *psPoint )
    1543                 : 
    1544                 : {
    1545               2 :     psPoint->x = (psPoint->x + psDGN->origin_x) / psDGN->scale;
    1546               2 :     psPoint->y = (psPoint->y + psDGN->origin_y) / psDGN->scale;
    1547               2 :     psPoint->z = (psPoint->z + psDGN->origin_z) / psDGN->scale;
    1548                 : 
    1549               2 :     psPoint->x = MAX(-2147483647,MIN(2147483647,psPoint->x));
    1550               2 :     psPoint->y = MAX(-2147483647,MIN(2147483647,psPoint->y));
    1551               2 :     psPoint->z = MAX(-2147483647,MIN(2147483647,psPoint->z));
    1552               2 : }
    1553                 : 
    1554                 : /************************************************************************/
    1555                 : /*                   DGNInverseTransformPointToInt()                    */
    1556                 : /************************************************************************/
    1557                 : 
    1558              94 : void DGNInverseTransformPointToInt( DGNInfo *psDGN, DGNPoint *psPoint,
    1559                 :                                     unsigned char *pabyTarget )
    1560                 : 
    1561                 : {
    1562                 :     double     adfCT[3];
    1563                 :     int        i;
    1564                 : 
    1565              94 :     adfCT[0] = (psPoint->x + psDGN->origin_x) / psDGN->scale;
    1566              94 :     adfCT[1] = (psPoint->y + psDGN->origin_y) / psDGN->scale;
    1567              94 :     adfCT[2] = (psPoint->z + psDGN->origin_z) / psDGN->scale;
    1568                 : 
    1569             282 :     for( i = 0; i < psDGN->dimension; i++ )
    1570                 :     {
    1571                 :         GInt32 nCTI;
    1572             188 :         unsigned char *pabyCTI = (unsigned char *) &nCTI;
    1573                 : 
    1574             188 :         nCTI = (GInt32) MAX(-2147483647,MIN(2147483647,adfCT[i]));
    1575                 :         
    1576                 : #ifdef WORDS_BIGENDIAN 
    1577                 :         pabyTarget[i*4+0] = pabyCTI[1];
    1578                 :         pabyTarget[i*4+1] = pabyCTI[0];
    1579                 :         pabyTarget[i*4+2] = pabyCTI[3];
    1580                 :         pabyTarget[i*4+3] = pabyCTI[2];
    1581                 : #else
    1582             188 :         pabyTarget[i*4+3] = pabyCTI[1];
    1583             188 :         pabyTarget[i*4+2] = pabyCTI[0];
    1584             188 :         pabyTarget[i*4+1] = pabyCTI[3];
    1585             188 :         pabyTarget[i*4+0] = pabyCTI[2];
    1586                 : #endif        
    1587                 :     }
    1588              94 : }
    1589                 : 
    1590                 : /************************************************************************/
    1591                 : /*                             DGNLoadTCB()                             */
    1592                 : /************************************************************************/
    1593                 : 
    1594                 : /**
    1595                 :  * Load TCB if not already loaded. 
    1596                 :  *
    1597                 :  * This function will load the TCB element if it is not already loaded.
    1598                 :  * It is used primarily to ensure the TCB is loaded before doing any operations
    1599                 :  * that require TCB values (like creating new elements). 
    1600                 :  *
    1601                 :  * @return FALSE on failure or TRUE on success.
    1602                 :  */
    1603                 : 
    1604              18 : int DGNLoadTCB( DGNHandle hDGN )
    1605                 : 
    1606                 : {
    1607              18 :     DGNInfo     *psDGN = (DGNInfo *) hDGN;
    1608                 : 
    1609              18 :     if( psDGN->got_tcb )
    1610              17 :         return TRUE;
    1611                 : 
    1612               3 :     while( !psDGN->got_tcb )
    1613                 :     {
    1614               1 :         DGNElemCore *psElem = DGNReadElement( hDGN );
    1615               1 :         if( psElem == NULL )
    1616                 :         {
    1617                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1618               0 :                       "DGNLoadTCB() - unable to find TCB in file." );
    1619               0 :             return FALSE;
    1620                 :         }
    1621               1 :         DGNFreeElement( hDGN, psElem );
    1622                 :     }
    1623                 : 
    1624               1 :     return TRUE;
    1625                 : }
    1626                 : 
    1627                 : /************************************************************************/
    1628                 : /*                         DGNGetElementIndex()                         */
    1629                 : /************************************************************************/
    1630                 : 
    1631                 : /**
    1632                 :  * Fetch element index.
    1633                 :  *
    1634                 :  * This function will return an array with brief information about every
    1635                 :  * element in a DGN file.  It requires one pass through the entire file to
    1636                 :  * generate (this is not repeated on subsequent calls). 
    1637                 :  *
    1638                 :  * The returned array of DGNElementInfo structures contain the level, type, 
    1639                 :  * stype, and other flags for each element in the file.  This can facilitate
    1640                 :  * application level code representing the number of elements of various types
    1641                 :  * effeciently. 
    1642                 :  *
    1643                 :  * Note that while building the index requires one pass through the whole file,
    1644                 :  * it does not generally request much processing for each element. 
    1645                 :  *
    1646                 :  * @param hDGN the file to get an index for.
    1647                 :  * @param pnElementCount the integer to put the total element count into. 
    1648                 :  *
    1649                 :  * @return a pointer to an internal array of DGNElementInfo structures (there 
    1650                 :  * will be *pnElementCount entries in the array), or NULL on failure.  The
    1651                 :  * returned array should not be modified or freed, and will last only as long
    1652                 :  * as the DGN file remains open. 
    1653                 :  */
    1654                 : 
    1655              16 : const DGNElementInfo *DGNGetElementIndex( DGNHandle hDGN, int *pnElementCount )
    1656                 : 
    1657                 : {
    1658              16 :     DGNInfo     *psDGN = (DGNInfo *) hDGN;
    1659                 : 
    1660              16 :     DGNBuildIndex( psDGN );
    1661                 : 
    1662              16 :     if( pnElementCount != NULL )
    1663               0 :         *pnElementCount = psDGN->element_count;
    1664                 :     
    1665              16 :     return psDGN->element_index;
    1666                 : }
    1667                 : 
    1668                 : /************************************************************************/
    1669                 : /*                           DGNGetExtents()                            */
    1670                 : /************************************************************************/
    1671                 : 
    1672                 : /**
    1673                 :  * Fetch overall file extents.
    1674                 :  *
    1675                 :  * The extents are collected for each element while building an index, so
    1676                 :  * if an index has not already been built, it will be built when 
    1677                 :  * DGNGetExtents() is called.  
    1678                 :  * 
    1679                 :  * The Z min/max values are generally meaningless (0 and 0xffffffff in uor
    1680                 :  * space). 
    1681                 :  * 
    1682                 :  * @param hDGN the file to get extents for.
    1683                 :  * @param padfExtents pointer to an array of six doubles into which are loaded
    1684                 :  * the values xmin, ymin, zmin, xmax, ymax, and zmax.
    1685                 :  *
    1686                 :  * @return TRUE on success or FALSE on failure.
    1687                 :  */
    1688                 : 
    1689               0 : int DGNGetExtents( DGNHandle hDGN, double * padfExtents )
    1690                 : 
    1691                 : {
    1692               0 :     DGNInfo     *psDGN = (DGNInfo *) hDGN;
    1693                 :     DGNPoint    sMin, sMax;
    1694                 : 
    1695               0 :     DGNBuildIndex( psDGN );
    1696                 : 
    1697               0 :     if( !psDGN->got_bounds )
    1698               0 :         return FALSE;
    1699                 : 
    1700               0 :     sMin.x = psDGN->min_x - 2147483648.0;
    1701               0 :     sMin.y = psDGN->min_y - 2147483648.0;
    1702               0 :     sMin.z = psDGN->min_z - 2147483648.0;
    1703                 :     
    1704               0 :     DGNTransformPoint( psDGN, &sMin );
    1705                 : 
    1706               0 :     padfExtents[0] = sMin.x;
    1707               0 :     padfExtents[1] = sMin.y;
    1708               0 :     padfExtents[2] = sMin.z;
    1709                 :     
    1710               0 :     sMax.x = psDGN->max_x - 2147483648.0;
    1711               0 :     sMax.y = psDGN->max_y - 2147483648.0;
    1712               0 :     sMax.z = psDGN->max_z - 2147483648.0;
    1713                 : 
    1714               0 :     DGNTransformPoint( psDGN, &sMax );
    1715                 : 
    1716               0 :     padfExtents[3] = sMax.x;
    1717               0 :     padfExtents[4] = sMax.y;
    1718               0 :     padfExtents[5] = sMax.z;
    1719                 : 
    1720               0 :     return TRUE;
    1721                 : }
    1722                 : 
    1723                 : /************************************************************************/
    1724                 : /*                           DGNBuildIndex()                            */
    1725                 : /************************************************************************/
    1726                 : 
    1727              34 : void DGNBuildIndex( DGNInfo *psDGN )
    1728                 : 
    1729                 : {
    1730                 :     int nMaxElements, nType, nLevel;
    1731                 :     long nLastOffset;
    1732                 :     GUInt32 anRegion[6];
    1733                 : 
    1734              34 :     if( psDGN->index_built ) 
    1735              30 :         return;
    1736                 : 
    1737               4 :     psDGN->index_built = TRUE;
    1738                 :     
    1739               4 :     DGNRewind( psDGN );
    1740                 : 
    1741               4 :     nMaxElements = 0;
    1742                 : 
    1743               4 :     nLastOffset = VSIFTell( psDGN->fp );
    1744              57 :     while( DGNLoadRawElement( psDGN, &nType, &nLevel ) )
    1745                 :     {
    1746                 :         DGNElementInfo  *psEI;
    1747                 : 
    1748              49 :         if( psDGN->element_count == nMaxElements )
    1749                 :         {
    1750               4 :             nMaxElements = (int) (nMaxElements * 1.5) + 500;
    1751                 :             
    1752                 :             psDGN->element_index = (DGNElementInfo *) 
    1753                 :                 CPLRealloc( psDGN->element_index, 
    1754               4 :                             nMaxElements * sizeof(DGNElementInfo) );
    1755                 :         }
    1756                 : 
    1757              49 :         psEI = psDGN->element_index + psDGN->element_count;
    1758              49 :         psEI->level = (unsigned char) nLevel;
    1759              49 :         psEI->type = (unsigned char) nType;
    1760              49 :         psEI->flags = 0;
    1761              49 :         psEI->offset = (long) nLastOffset;
    1762                 : 
    1763              49 :         if( psDGN->abyElem[0] & 0x80 )
    1764               3 :             psEI->flags |= DGNEIF_COMPLEX;
    1765                 : 
    1766              49 :         if( psDGN->abyElem[1] & 0x80 )
    1767               0 :             psEI->flags |= DGNEIF_DELETED;
    1768                 : 
    1769              57 :         if( nType == DGNT_LINE || nType == DGNT_LINE_STRING
    1770                 :             || nType == DGNT_SHAPE || nType == DGNT_CURVE
    1771                 :             || nType == DGNT_BSPLINE_POLE )
    1772               8 :             psEI->stype = DGNST_MULTIPOINT;
    1773                 : 
    1774              41 :         else if( nType == DGNT_GROUP_DATA && nLevel == DGN_GDL_COLOR_TABLE )
    1775                 :         {
    1776               0 :             DGNElemCore *psCT = DGNParseColorTable( psDGN );
    1777               0 :             DGNFreeElement( (DGNHandle) psDGN, psCT );
    1778               0 :             psEI->stype = DGNST_COLORTABLE;
    1779                 :         }
    1780              43 :         else if( nType == DGNT_ELLIPSE || nType == DGNT_ARC )
    1781               2 :             psEI->stype = DGNST_ARC;
    1782                 :         
    1783              40 :         else if( nType == DGNT_COMPLEX_SHAPE_HEADER 
    1784                 :                  || nType == DGNT_COMPLEX_CHAIN_HEADER
    1785                 :                  || nType == DGNT_3DSURFACE_HEADER
    1786                 :                  || nType == DGNT_3DSOLID_HEADER)
    1787               1 :             psEI->stype = DGNST_COMPLEX_HEADER;
    1788                 :         
    1789              38 :         else if( nType == DGNT_TEXT )
    1790               3 :             psEI->stype = DGNST_TEXT;
    1791                 : 
    1792              35 :         else if( nType == DGNT_TAG_VALUE )
    1793               0 :             psEI->stype = DGNST_TAG_VALUE;
    1794                 : 
    1795              35 :         else if( nType == DGNT_APPLICATION_ELEM )
    1796                 :         {
    1797              21 :             if( nLevel == 24 )
    1798               0 :                 psEI->stype = DGNST_TAG_SET;
    1799                 :             else
    1800              21 :                 psEI->stype = DGNST_CORE;
    1801                 :         }
    1802              14 :         else if( nType == DGNT_TCB )
    1803                 :         {
    1804               6 :             DGNElemCore *psTCB = DGNParseTCB( psDGN );
    1805               6 :             DGNFreeElement( (DGNHandle) psDGN, psTCB );
    1806               6 :             psEI->stype = DGNST_TCB;
    1807                 :         }
    1808               8 :         else if( nType == DGNT_CONE )
    1809               0 :             psEI->stype = DGNST_CONE;
    1810                 :         else
    1811               8 :             psEI->stype = DGNST_CORE;
    1812                 : 
    1813              49 :         if( !(psEI->flags & DGNEIF_DELETED)
    1814                 :             && !(psEI->flags & DGNEIF_COMPLEX) 
    1815                 :             && DGNGetRawExtents( psDGN, nType, NULL,
    1816                 :                                  anRegion+0, anRegion+1, anRegion+2,
    1817                 :                                  anRegion+3, anRegion+4, anRegion+5 ) )
    1818                 :         {
    1819                 : #ifdef notdef
    1820                 :             printf( "panRegion[%d]=%.1f,%.1f,%.1f,%.1f,%.1f,%.1f\n", 
    1821                 :                     psDGN->element_count,
    1822                 :                     anRegion[0] - 2147483648.0,
    1823                 :                     anRegion[1] - 2147483648.0,
    1824                 :                     anRegion[2] - 2147483648.0,
    1825                 :                     anRegion[3] - 2147483648.0,
    1826                 :                     anRegion[4] - 2147483648.0,
    1827                 :                     anRegion[5] - 2147483648.0 );
    1828                 : #endif            
    1829              11 :             if( psDGN->got_bounds )
    1830                 :             {
    1831               8 :                 psDGN->min_x = MIN(psDGN->min_x, anRegion[0]);
    1832               8 :                 psDGN->min_y = MIN(psDGN->min_y, anRegion[1]);
    1833               8 :                 psDGN->min_z = MIN(psDGN->min_z, anRegion[2]);
    1834               8 :                 psDGN->max_x = MAX(psDGN->max_x, anRegion[3]);
    1835               8 :                 psDGN->max_y = MAX(psDGN->max_y, anRegion[4]);
    1836               8 :                 psDGN->max_z = MAX(psDGN->max_z, anRegion[5]);
    1837                 :             }
    1838                 :             else
    1839                 :             {
    1840               3 :                 memcpy( &(psDGN->min_x), anRegion, sizeof(GInt32) * 6 );
    1841               3 :                 psDGN->got_bounds = TRUE;
    1842                 :             }
    1843                 :         }
    1844                 : 
    1845              49 :         psDGN->element_count++;
    1846                 : 
    1847              49 :         nLastOffset = VSIFTell( psDGN->fp );
    1848                 :     }
    1849                 : 
    1850               4 :     DGNRewind( psDGN );
    1851                 : 
    1852               4 :     psDGN->max_element_count = nMaxElements;
    1853                 : }
    1854                 : 

Generated by: LCOV version 1.7