LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/dgn - ogrdgnlayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 428 288 67.3 %
Date: 2012-12-26 Functions: 18 11 61.1 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrdgnlayer.cpp 24142 2012-03-19 20:27:18Z warmerdam $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  Implements OGRDGNLayer class.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2000, Frank Warmerdam (warmerdam@pobox.com)
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "ogr_dgn.h"
      31                 : #include "cpl_conv.h"
      32                 : #include "ogr_featurestyle.h"
      33                 : #include "ogr_api.h"
      34                 : 
      35                 : CPL_CVSID("$Id: ogrdgnlayer.cpp 24142 2012-03-19 20:27:18Z warmerdam $");
      36                 : 
      37                 : /************************************************************************/
      38                 : /*                           OGRDGNLayer()                              */
      39                 : /************************************************************************/
      40                 : 
      41               4 : OGRDGNLayer::OGRDGNLayer( const char * pszName, DGNHandle hDGN,
      42               4 :                           int bUpdate )
      43                 :     
      44                 : {
      45               4 :     this->hDGN = hDGN;
      46               4 :     this->bUpdate = bUpdate;
      47                 : 
      48                 : /* -------------------------------------------------------------------- */
      49                 : /*      Work out what link format we are using.                         */
      50                 : /* -------------------------------------------------------------------- */
      51                 :     OGRFieldType eLinkFieldType;
      52                 : 
      53               4 :     pszLinkFormat = (char *) CPLGetConfigOption( "DGN_LINK_FORMAT", "FIRST" );
      54               4 :     if( EQUAL(pszLinkFormat,"FIRST") )
      55               4 :         eLinkFieldType = OFTInteger;
      56               0 :     else if( EQUAL(pszLinkFormat,"LIST") )
      57               0 :         eLinkFieldType = OFTIntegerList;
      58               0 :     else if( EQUAL(pszLinkFormat,"STRING") )
      59               0 :         eLinkFieldType = OFTString;
      60                 :     else
      61                 :     {
      62                 :         CPLError( CE_Warning, CPLE_AppDefined, 
      63                 :                   "DGN_LINK_FORMAT=%s, but only FIRST, LIST or STRING supported.",
      64               0 :                   pszLinkFormat );
      65               0 :         pszLinkFormat = (char *) "FIRST";
      66               0 :         eLinkFieldType = OFTInteger;
      67                 :     }
      68               4 :     pszLinkFormat = CPLStrdup(pszLinkFormat);
      69                 : 
      70                 : /* -------------------------------------------------------------------- */
      71                 : /*      Create the feature definition.                                  */
      72                 : /* -------------------------------------------------------------------- */
      73               4 :     poFeatureDefn = new OGRFeatureDefn( pszName );
      74               4 :     poFeatureDefn->Reference();
      75                 :     
      76               4 :     OGRFieldDefn        oField( "", OFTInteger );
      77                 : 
      78                 : /* -------------------------------------------------------------------- */
      79                 : /*      Element type                                                    */
      80                 : /* -------------------------------------------------------------------- */
      81               4 :     oField.SetName( "Type" );
      82               4 :     oField.SetType( OFTInteger );
      83               4 :     oField.SetWidth( 2 );
      84               4 :     oField.SetPrecision( 0 );
      85               4 :     poFeatureDefn->AddFieldDefn( &oField );
      86                 : 
      87                 : /* -------------------------------------------------------------------- */
      88                 : /*      Level number.                                                   */
      89                 : /* -------------------------------------------------------------------- */
      90               4 :     oField.SetName( "Level" );
      91               4 :     oField.SetType( OFTInteger );
      92               4 :     oField.SetWidth( 2 );
      93               4 :     oField.SetPrecision( 0 );
      94               4 :     poFeatureDefn->AddFieldDefn( &oField );
      95                 : 
      96                 : /* -------------------------------------------------------------------- */
      97                 : /*      graphic group                                                   */
      98                 : /* -------------------------------------------------------------------- */
      99               4 :     oField.SetName( "GraphicGroup" );
     100               4 :     oField.SetType( OFTInteger );
     101               4 :     oField.SetWidth( 4 );
     102               4 :     oField.SetPrecision( 0 );
     103               4 :     poFeatureDefn->AddFieldDefn( &oField );
     104                 : 
     105                 : /* -------------------------------------------------------------------- */
     106                 : /*      ColorIndex                                                      */
     107                 : /* -------------------------------------------------------------------- */
     108               4 :     oField.SetName( "ColorIndex" );
     109               4 :     oField.SetType( OFTInteger );
     110               4 :     oField.SetWidth( 3 );
     111               4 :     oField.SetPrecision( 0 );
     112               4 :     poFeatureDefn->AddFieldDefn( &oField );
     113                 : 
     114                 : /* -------------------------------------------------------------------- */
     115                 : /*      Weight                                                          */
     116                 : /* -------------------------------------------------------------------- */
     117               4 :     oField.SetName( "Weight" );
     118               4 :     oField.SetType( OFTInteger );
     119               4 :     oField.SetWidth( 2 );
     120               4 :     oField.SetPrecision( 0 );
     121               4 :     poFeatureDefn->AddFieldDefn( &oField );
     122                 : 
     123                 : /* -------------------------------------------------------------------- */
     124                 : /*      Style                                                           */
     125                 : /* -------------------------------------------------------------------- */
     126               4 :     oField.SetName( "Style" );
     127               4 :     oField.SetType( OFTInteger );
     128               4 :     oField.SetWidth( 1 );
     129               4 :     oField.SetPrecision( 0 );
     130               4 :     poFeatureDefn->AddFieldDefn( &oField );
     131                 : 
     132                 : /* -------------------------------------------------------------------- */
     133                 : /*      EntityNum                                                       */
     134                 : /* -------------------------------------------------------------------- */
     135               4 :     oField.SetName( "EntityNum" );
     136               4 :     oField.SetType( eLinkFieldType );
     137               4 :     oField.SetWidth( 0 );
     138               4 :     oField.SetPrecision( 0 );
     139               4 :     poFeatureDefn->AddFieldDefn( &oField );
     140                 : 
     141                 : /* -------------------------------------------------------------------- */
     142                 : /*      MSLink                                                          */
     143                 : /* -------------------------------------------------------------------- */
     144               4 :     oField.SetName( "MSLink" );
     145               4 :     oField.SetType( eLinkFieldType );
     146               4 :     oField.SetWidth( 0 );
     147               4 :     oField.SetPrecision( 0 );
     148               4 :     poFeatureDefn->AddFieldDefn( &oField );
     149                 : 
     150                 : /* -------------------------------------------------------------------- */
     151                 : /*      Text                                                            */
     152                 : /* -------------------------------------------------------------------- */
     153               4 :     oField.SetName( "Text" );
     154               4 :     oField.SetType( OFTString );
     155               4 :     oField.SetWidth( 0 );
     156               4 :     oField.SetPrecision( 0 );
     157               4 :     poFeatureDefn->AddFieldDefn( &oField );
     158                 : 
     159                 : /* -------------------------------------------------------------------- */
     160                 : /*      Create template feature for evaluating simple expressions.      */
     161                 : /* -------------------------------------------------------------------- */
     162               4 :     bHaveSimpleQuery = FALSE;
     163               4 :     poEvalFeature = new OGRFeature( poFeatureDefn );
     164                 : 
     165                 :     /* TODO: I am intending to keep track of simple attribute queries (ones
     166                 :        using only FID, Type and Level and short circuiting their operation
     167                 :        based on the index.  However, there are some complexities with
     168                 :        complex elements, and spatial queries that have caused me to put it
     169                 :        off for now.
     170                 :     */
     171               4 : }
     172                 : 
     173                 : /************************************************************************/
     174                 : /*                           ~OGRDGNLayer()                             */
     175                 : /************************************************************************/
     176                 : 
     177               4 : OGRDGNLayer::~OGRDGNLayer()
     178                 : 
     179                 : {
     180               4 :     if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
     181                 :     {
     182                 :         CPLDebug( "Mem", "%d features read on layer '%s'.",
     183                 :                   (int) m_nFeaturesRead, 
     184               3 :                   poFeatureDefn->GetName() );
     185                 :     }
     186                 : 
     187               4 :     delete poEvalFeature;
     188                 : 
     189               4 :     poFeatureDefn->Release();
     190                 : 
     191               4 :     CPLFree( pszLinkFormat );
     192               4 : }
     193                 : 
     194                 : /************************************************************************/
     195                 : /*                          SetSpatialFilter()                          */
     196                 : /************************************************************************/
     197                 : 
     198               4 : void OGRDGNLayer::SetSpatialFilter( OGRGeometry * poGeomIn )
     199                 : 
     200                 : {
     201               4 :     if( !InstallFilter(poGeomIn) )
     202               2 :         return;
     203                 : 
     204               2 :     if( m_poFilterGeom != NULL )
     205                 :     {
     206                 :         DGNSetSpatialFilter( hDGN, 
     207                 :                              m_sFilterEnvelope.MinX, 
     208                 :                              m_sFilterEnvelope.MinY, 
     209                 :                              m_sFilterEnvelope.MaxX, 
     210               1 :                              m_sFilterEnvelope.MaxY );
     211                 :     }
     212                 :     else
     213                 :     {
     214               1 :         DGNSetSpatialFilter( hDGN, 0.0, 0.0, 0.0, 0.0 );
     215                 :     }
     216                 : 
     217               2 :     ResetReading();
     218                 : }
     219                 : 
     220                 : /************************************************************************/
     221                 : /*                            ResetReading()                            */
     222                 : /************************************************************************/
     223                 : 
     224               9 : void OGRDGNLayer::ResetReading()
     225                 : 
     226                 : {
     227               9 :     iNextShapeId = 0;
     228               9 :     DGNRewind( hDGN );
     229               9 : }
     230                 : 
     231                 : /************************************************************************/
     232                 : /*                             GetFeature()                             */
     233                 : /************************************************************************/
     234                 : 
     235               0 : OGRFeature *OGRDGNLayer::GetFeature( long nFeatureId )
     236                 : 
     237                 : {
     238                 :     OGRFeature *poFeature;
     239                 :     DGNElemCore *psElement;
     240                 : 
     241               0 :     if( !DGNGotoElement( hDGN, nFeatureId ) )
     242               0 :         return NULL;
     243                 : 
     244                 :     // We should likely clear the spatial search region as it affects 
     245                 :     // DGNReadElement() but I will defer that for now. 
     246                 : 
     247               0 :     psElement = DGNReadElement( hDGN );
     248               0 :     poFeature = ElementToFeature( psElement );
     249               0 :     DGNFreeElement( hDGN, psElement );
     250                 : 
     251               0 :     if( poFeature == NULL )
     252               0 :         return NULL;
     253                 : 
     254               0 :     if( poFeature->GetFID() != nFeatureId )
     255                 :     {
     256               0 :         delete poFeature;
     257               0 :         return NULL;
     258                 :     }
     259                 : 
     260               0 :     return poFeature;
     261                 : }
     262                 : 
     263                 : /************************************************************************/
     264                 : /*                           ConsiderBrush()                            */
     265                 : /*                                                                      */
     266                 : /*      Method to set the style for a polygon, including a brush if     */
     267                 : /*      appropriate.                                                    */
     268                 : /************************************************************************/
     269                 : 
     270               6 : void OGRDGNLayer::ConsiderBrush( DGNElemCore *psElement, const char *pszPen,
     271                 :                                  OGRFeature *poFeature )
     272                 : 
     273                 : {
     274                 :     int         gv_red, gv_green, gv_blue;
     275                 :     char                szFullStyle[256];
     276                 :     int                 nFillColor;
     277                 : 
     278               6 :     if( DGNGetShapeFillInfo( hDGN, psElement, &nFillColor ) 
     279                 :         && DGNLookupColor( hDGN, nFillColor, 
     280                 :                            &gv_red, &gv_green, &gv_blue ) )
     281                 :     {
     282                 :         sprintf( szFullStyle, 
     283                 :                  "BRUSH(fc:#%02x%02x%02x,id:\"ogr-brush-0\")",
     284               4 :                  gv_red, gv_green, gv_blue );
     285                 :               
     286               4 :         if( nFillColor != psElement->color )
     287                 :         {
     288               0 :             strcat( szFullStyle, ";" );
     289               0 :             strcat( szFullStyle, pszPen );
     290                 :         }
     291               4 :         poFeature->SetStyleString( szFullStyle );
     292                 :     }
     293                 :     else
     294               2 :         poFeature->SetStyleString( pszPen );
     295               6 : }
     296                 : 
     297                 : /************************************************************************/
     298                 : /*                          ElementToFeature()                          */
     299                 : /************************************************************************/
     300                 : 
     301              88 : OGRFeature *OGRDGNLayer::ElementToFeature( DGNElemCore *psElement )
     302                 : 
     303                 : {
     304              88 :     OGRFeature  *poFeature = new OGRFeature( poFeatureDefn );
     305                 : 
     306              88 :     poFeature->SetFID( psElement->element_id );
     307              88 :     poFeature->SetField( "Type", psElement->type );
     308              88 :     poFeature->SetField( "Level", psElement->level );
     309              88 :     poFeature->SetField( "GraphicGroup", psElement->graphic_group );
     310              88 :     poFeature->SetField( "ColorIndex", psElement->color );
     311              88 :     poFeature->SetField( "Weight", psElement->weight );
     312              88 :     poFeature->SetField( "Style", psElement->style );
     313                 :     
     314                 : 
     315              88 :     m_nFeaturesRead++;
     316                 : 
     317                 : /* -------------------------------------------------------------------- */
     318                 : /*      Collect linkage information                                     */
     319                 : /* -------------------------------------------------------------------- */
     320                 : #define MAX_LINK 100    
     321                 :     int anEntityNum[MAX_LINK], anMSLink[MAX_LINK];
     322                 :     unsigned char *pabyData;
     323              88 :     int iLink=0, nLinkCount=0;
     324                 : 
     325              88 :     anEntityNum[0] = 0;
     326              88 :     anMSLink[0] = 0;
     327                 : 
     328                 :     pabyData = DGNGetLinkage( hDGN, psElement, iLink, NULL, 
     329              88 :                               anEntityNum+iLink, anMSLink+iLink, NULL );
     330             181 :     while( pabyData && nLinkCount < MAX_LINK )
     331                 :     {
     332               5 :         iLink++;
     333                 : 
     334               5 :         if( anEntityNum[nLinkCount] != 0 || anMSLink[nLinkCount] != 0 )
     335               0 :             nLinkCount++;
     336                 : 
     337               5 :         anEntityNum[nLinkCount] = 0;
     338               5 :         anMSLink[nLinkCount] = 0;
     339                 : 
     340                 :         pabyData = DGNGetLinkage( hDGN, psElement, iLink, NULL, 
     341                 :                                   anEntityNum+nLinkCount, anMSLink+nLinkCount, 
     342               5 :                                   NULL );
     343                 :     }
     344                 : 
     345                 : /* -------------------------------------------------------------------- */
     346                 : /*      Apply attribute linkage to feature.                             */
     347                 : /* -------------------------------------------------------------------- */
     348              88 :     if( nLinkCount > 0 )
     349                 :     {
     350               0 :         if( EQUAL(pszLinkFormat,"FIRST") )
     351                 :         {
     352               0 :             poFeature->SetField( "EntityNum", anEntityNum[0] );
     353               0 :             poFeature->SetField( "MSLink", anMSLink[0] );
     354                 :         }
     355               0 :         else if( EQUAL(pszLinkFormat,"LIST") )
     356                 :         {
     357               0 :             poFeature->SetField( "EntityNum", nLinkCount, anEntityNum );
     358               0 :             poFeature->SetField( "MSLink", nLinkCount, anMSLink );
     359                 :         }
     360               0 :         else if( EQUAL(pszLinkFormat,"STRING") )
     361                 :         {
     362                 :             char szEntityList[MAX_LINK*9], szMSLinkList[MAX_LINK*9];
     363               0 :             int nEntityLen = 0, nMSLinkLen = 0;
     364                 : 
     365               0 :             for( iLink = 0; iLink < nLinkCount; iLink++ )
     366                 :             {
     367               0 :                 if( iLink != 0 )
     368                 :                 {
     369               0 :                     szEntityList[nEntityLen++] = ',';
     370               0 :                     szMSLinkList[nMSLinkLen++] = ',';
     371                 :                 }
     372                 : 
     373               0 :                 sprintf( szEntityList + nEntityLen, "%d", anEntityNum[iLink]);
     374               0 :                 sprintf( szMSLinkList + nMSLinkLen, "%d", anMSLink[iLink] );
     375                 :                 
     376               0 :                 nEntityLen += strlen(szEntityList + nEntityLen );
     377               0 :                 nMSLinkLen += strlen(szMSLinkList + nMSLinkLen );
     378                 :             }
     379                 : 
     380               0 :             poFeature->SetField( "EntityNum", szEntityList );
     381               0 :             poFeature->SetField( "MSLink", szMSLinkList );
     382                 :         }
     383                 :     }
     384                 : 
     385                 : /* -------------------------------------------------------------------- */
     386                 : /*      Lookup color.                                                   */
     387                 : /* -------------------------------------------------------------------- */
     388                 :     char        gv_color[128];
     389                 :     int         gv_red, gv_green, gv_blue;
     390                 :     char        szFSColor[128], szPen[256];
     391                 : 
     392              88 :     szFSColor[0] = '\0';
     393              88 :     if( DGNLookupColor( hDGN, psElement->color, 
     394                 :                         &gv_red, &gv_green, &gv_blue ) )
     395                 :     {
     396                 :         sprintf( gv_color, "%f %f %f 1.0", 
     397              88 :                  gv_red / 255.0, gv_green / 255.0, gv_blue / 255.0 );
     398                 : 
     399                 :         sprintf( szFSColor, "c:#%02x%02x%02x", 
     400              88 :                  gv_red, gv_green, gv_blue );
     401                 :     }
     402                 : 
     403                 : /* -------------------------------------------------------------------- */
     404                 : /*      Generate corresponding PEN style.                               */
     405                 : /* -------------------------------------------------------------------- */
     406              88 :     if( psElement->style == DGNS_SOLID )
     407              82 :         sprintf( szPen, "PEN(id:\"ogr-pen-0\"" );
     408               6 :     else if( psElement->style == DGNS_DOTTED )
     409               6 :         sprintf( szPen, "PEN(id:\"ogr-pen-5\"" );
     410               0 :     else if( psElement->style == DGNS_MEDIUM_DASH )
     411               0 :         sprintf( szPen, "PEN(id:\"ogr-pen-2\"" );
     412               0 :     else if( psElement->style == DGNS_LONG_DASH )
     413               0 :         sprintf( szPen, "PEN(id:\"ogr-pen-4\"" );
     414               0 :     else if( psElement->style == DGNS_DOT_DASH )
     415               0 :         sprintf( szPen, "PEN(id:\"ogr-pen-6\"" );
     416               0 :     else if( psElement->style == DGNS_SHORT_DASH )
     417               0 :         sprintf( szPen, "PEN(id:\"ogr-pen-3\"" );
     418               0 :     else if( psElement->style == DGNS_DASH_DOUBLE_DOT )
     419               0 :         sprintf( szPen, "PEN(id:\"ogr-pen-7\"" );
     420               0 :     else if( psElement->style == DGNS_LONG_DASH_SHORT_DASH )
     421               0 :         sprintf( szPen, "PEN(p:\"10px 5px 4px 5px\"" );
     422                 :     else
     423               0 :         sprintf( szPen, "PEN(id:\"ogr-pen-0\"" );
     424                 : 
     425              88 :     if( strlen(szFSColor) > 0 )
     426              88 :         sprintf( szPen+strlen(szPen), ",%s", szFSColor );
     427                 : 
     428              88 :     if( psElement->weight > 1 )
     429               0 :         sprintf( szPen+strlen(szPen), ",w:%dpx", psElement->weight );
     430                 :         
     431              88 :     strcat( szPen, ")" );
     432                 : 
     433              88 :     switch( psElement->stype )
     434                 :     {
     435                 :       case DGNST_MULTIPOINT:
     436              10 :         if( psElement->type == DGNT_SHAPE )
     437                 :         {
     438               5 :             OGRLinearRing       *poLine = new OGRLinearRing();
     439              10 :             OGRPolygon          *poPolygon = new OGRPolygon();
     440               5 :             DGNElemMultiPoint *psEMP = (DGNElemMultiPoint *) psElement;
     441                 :             
     442               5 :             poLine->setNumPoints( psEMP->num_vertices );
     443              30 :             for( int i = 0; i < psEMP->num_vertices; i++ )
     444                 :             {
     445                 :                 poLine->setPoint( i, 
     446                 :                                   psEMP->vertices[i].x,
     447                 :                                   psEMP->vertices[i].y,
     448              25 :                                   psEMP->vertices[i].z );
     449                 :             }
     450                 : 
     451               5 :             poPolygon->addRingDirectly( poLine );
     452                 : 
     453               5 :             poFeature->SetGeometryDirectly( poPolygon );
     454                 : 
     455               5 :             ConsiderBrush( psElement, szPen, poFeature );
     456                 :         }
     457               5 :         else if( psElement->type == DGNT_CURVE )
     458                 :         {
     459               0 :             DGNElemMultiPoint *psEMP = (DGNElemMultiPoint *) psElement;
     460               0 :             OGRLineString       *poLine = new OGRLineString();
     461                 :             DGNPoint            *pasPoints;
     462                 :             int                 nPoints;
     463                 : 
     464               0 :             nPoints = 5 * psEMP->num_vertices;
     465               0 :             pasPoints = (DGNPoint *) CPLMalloc(sizeof(DGNPoint) * nPoints);
     466                 :             
     467               0 :             DGNStrokeCurve( hDGN, psEMP, nPoints, pasPoints );
     468                 : 
     469               0 :             poLine->setNumPoints( nPoints );
     470               0 :             for( int i = 0; i < nPoints; i++ )
     471                 :             {
     472                 :                 poLine->setPoint( i, 
     473               0 :                                   pasPoints[i].x,
     474               0 :                                   pasPoints[i].y,
     475               0 :                                   pasPoints[i].z );
     476                 :             }
     477                 : 
     478               0 :             poFeature->SetGeometryDirectly( poLine );
     479               0 :             CPLFree( pasPoints );
     480                 : 
     481               0 :             poFeature->SetStyleString( szPen );
     482                 :         }
     483                 :         else
     484                 :         {
     485               5 :             OGRLineString       *poLine = new OGRLineString();
     486               5 :             DGNElemMultiPoint *psEMP = (DGNElemMultiPoint *) psElement;
     487                 :             
     488               5 :             if( psEMP->num_vertices > 0 )
     489                 :             {
     490               5 :                 poLine->setNumPoints( psEMP->num_vertices );
     491              85 :                 for( int i = 0; i < psEMP->num_vertices; i++ )
     492                 :                 {
     493                 :                     poLine->setPoint( i, 
     494                 :                                       psEMP->vertices[i].x,
     495                 :                                       psEMP->vertices[i].y,
     496              80 :                                       psEMP->vertices[i].z );
     497                 :                 }
     498                 :                 
     499               5 :                 poFeature->SetGeometryDirectly( poLine );
     500                 :             }
     501                 : 
     502               5 :             poFeature->SetStyleString( szPen );
     503                 :         }
     504              10 :         break;
     505                 : 
     506                 :       case DGNST_ARC:
     507                 :       {
     508               5 :           OGRLineString *poLine = new OGRLineString();
     509               5 :           DGNElemArc    *psArc = (DGNElemArc *) psElement;
     510                 :           DGNPoint      asPoints[90];
     511                 :           int           nPoints;
     512                 : 
     513               5 :           nPoints = (int) (MAX(1,ABS(psArc->sweepang) / 5) + 1);
     514               5 :           DGNStrokeArc( hDGN, psArc, nPoints, asPoints );
     515                 : 
     516               5 :           poLine->setNumPoints( nPoints );
     517             370 :           for( int i = 0; i < nPoints; i++ )
     518                 :           {
     519                 :               poLine->setPoint( i, 
     520                 :                                 asPoints[i].x,
     521                 :                                 asPoints[i].y,
     522             365 :                                 asPoints[i].z );
     523                 :           }
     524                 : 
     525               5 :           poFeature->SetGeometryDirectly( poLine );
     526               5 :           poFeature->SetStyleString( szPen );
     527                 :       }
     528               5 :       break;
     529                 : 
     530                 :       case DGNST_TEXT:
     531                 :       {
     532               5 :           OGRPoint      *poPoint = new OGRPoint();
     533               5 :           DGNElemText   *psText = (DGNElemText *) psElement;
     534                 :           char          *pszOgrFS;
     535                 : 
     536               5 :           poPoint->setX( psText->origin.x );
     537               5 :           poPoint->setY( psText->origin.y );
     538               5 :           poPoint->setZ( psText->origin.z );
     539                 : 
     540               5 :           poFeature->SetGeometryDirectly( poPoint );
     541                 : 
     542               5 :           pszOgrFS = (char *) CPLMalloc(strlen(psText->string) + 150);
     543                 : 
     544                 :           // setup the basic label.
     545               5 :           sprintf( pszOgrFS, "LABEL(t:\"%s\"",  psText->string );
     546                 : 
     547                 :           // set the color if we have it. 
     548               5 :           if( strlen(szFSColor) > 0 )
     549               5 :               sprintf( pszOgrFS+strlen(pszOgrFS), ",%s", szFSColor );
     550                 : 
     551                 :           // Add the size info in ground units.
     552               5 :           if( ABS(psText->height_mult) >= 6.0 )
     553                 :               sprintf( pszOgrFS+strlen(pszOgrFS), ",s:%dg", 
     554               0 :                        (int) psText->height_mult );
     555               5 :           else if( ABS(psText->height_mult) > 0.1 )
     556                 :               sprintf( pszOgrFS+strlen(pszOgrFS), ",s:%.3fg", 
     557               5 :                        psText->height_mult );
     558                 :           else
     559                 :               sprintf( pszOgrFS+strlen(pszOgrFS), ",s:%.12fg", 
     560               0 :                        psText->height_mult );
     561                 : 
     562                 :           // Add the font name. Name it MstnFont<FONTNUMBER> if not available
     563                 :           // in the font list. #3392
     564                 :           static const char *papszFontList[] =
     565                 :           { "STANDARD", "WORKING", "FANCY", "ENGINEERING", "NEWZERO", "STENCEL", //0-5
     566                 :             "USTN_FANCY", "COMPRESSED", "STENCEQ", NULL, "hand", "ARCH", //6-11
     567                 :             "ARCHB", NULL, NULL, "IGES1001", "IGES1002", "IGES1003", //12-17
     568                 :             "CENTB", "MICROS", NULL, NULL, "ISOFRACTIONS", "ITALICS", //18-23
     569                 :             "ISO30", NULL, "GREEK", "ISOREC", "Isoeq", NULL, //24-29
     570                 :             "ISO_FONTLEFT", "ISO_FONTRIGHT", "INTL_ENGINEERING", "INTL_WORKING", "ISOITEQ", NULL, //30-35
     571                 :             "USTN FONT 26", NULL, NULL, NULL, NULL, "ARCHITECTURAL", //36-41
     572                 :             "BLOCK_OUTLINE", "LOW_RES_FILLED", NULL, NULL, NULL, NULL, //42-47
     573                 :             NULL, NULL, "UPPERCASE", NULL, NULL, NULL, //48-53
     574                 :             NULL, NULL, NULL, NULL, NULL, NULL, //54-49
     575                 :             "FONT060", "din", "dinit", "helvl", "HELVLIT", "helv", //60-65
     576                 :             "HELVIT", "cent", "CENTIT", "SCRIPT", NULL, NULL, //66-71
     577                 :             NULL, NULL, NULL, NULL, "MICROQ", "dotfont", //72-77
     578                 :             "DOTIT", NULL, NULL, NULL, NULL, NULL, //78-83
     579                 :             NULL, NULL, NULL, NULL, NULL, NULL, //84-89
     580                 :             NULL, NULL, "FONT092", NULL, "FONT094", NULL, //90-95
     581                 :             NULL, NULL, NULL, NULL, "ANSI_SYMBOLS", "FEATURE_CONTROL_SYSMBOLS", //96-101
     582                 :             "SYMB_FAST", NULL, NULL, "INTL_ISO", "INTL_ISO_EQUAL", "INTL_ISO_ITALIC", //102-107
     583                 :             "INTL_ISO_ITALIC_EQUAL" }; //108
     584                 : 
     585              10 :           if(psText->font_id <= 108 && papszFontList[psText->font_id] != NULL )
     586                 :           {
     587                 :               sprintf( pszOgrFS+strlen(pszOgrFS), ",f:%s",
     588               5 :                        papszFontList[psText->font_id] );
     589                 :           }
     590                 :           else
     591                 :           {
     592                 :               sprintf( pszOgrFS+strlen(pszOgrFS), ",f:MstnFont%d",
     593               0 :                        psText->font_id );
     594                 :           }
     595                 : 
     596                 :           // Add the angle, if not horizontal
     597               5 :           if( psText->rotation != 0.0 )
     598                 :               sprintf( pszOgrFS+strlen(pszOgrFS), ",a:%d", 
     599               0 :                        (int) (psText->rotation+0.5) );
     600                 : 
     601               5 :           strcat( pszOgrFS, ")" );
     602                 : 
     603               5 :           poFeature->SetStyleString( pszOgrFS );
     604               5 :           CPLFree( pszOgrFS );
     605                 : 
     606               5 :           poFeature->SetField( "Text", psText->string );
     607                 :       }
     608               5 :       break;
     609                 : 
     610                 :       case DGNST_COMPLEX_HEADER:
     611                 :       {
     612               1 :           DGNElemComplexHeader *psHdr = (DGNElemComplexHeader *) psElement;
     613                 :           int           iChild;
     614               1 :           OGRMultiLineString  oChildren;
     615                 : 
     616                 :           /* collect subsequent child geometries. */
     617                 :           // we should disable the spatial filter ... add later.
     618               3 :           for( iChild = 0; iChild < psHdr->numelems; iChild++ )
     619                 :           {
     620               2 :               OGRFeature *poChildFeature = NULL;
     621                 :               DGNElemCore *psChildElement;
     622                 : 
     623               2 :               psChildElement = DGNReadElement( hDGN );
     624                 :               // should verify complex bit set, not another header.
     625                 : 
     626               2 :               if( psChildElement != NULL )
     627                 :               {
     628               2 :                   poChildFeature = ElementToFeature( psChildElement );
     629               2 :                   DGNFreeElement( hDGN, psChildElement );
     630                 :               }
     631                 : 
     632               2 :               if( poChildFeature != NULL
     633                 :                   && poChildFeature->GetGeometryRef() != NULL )
     634                 :               {
     635                 :                   OGRGeometry *poGeom;
     636                 : 
     637               2 :                   poGeom = poChildFeature->GetGeometryRef();
     638               2 :                   if( wkbFlatten(poGeom->getGeometryType()) == wkbLineString )
     639               2 :                       oChildren.addGeometry( poGeom );
     640                 :               }
     641                 : 
     642               2 :               if( poChildFeature != NULL )
     643               2 :                   delete poChildFeature;
     644                 :           }
     645                 : 
     646                 :           // Try to assemble into polygon geometry.
     647                 :           OGRGeometry *poGeom;
     648                 : 
     649               1 :           if( psElement->type == DGNT_COMPLEX_SHAPE_HEADER )
     650                 :               poGeom = (OGRPolygon *) 
     651                 :                   OGRBuildPolygonFromEdges( (OGRGeometryH) &oChildren, 
     652               0 :                                             TRUE, TRUE, 100000, NULL );
     653                 :           else
     654               1 :               poGeom = oChildren.clone();
     655                 : 
     656               1 :           if( poGeom != NULL )
     657               1 :               poFeature->SetGeometryDirectly( poGeom );
     658                 : 
     659               1 :           ConsiderBrush( psElement, szPen, poFeature );
     660                 :       }
     661                 :       break;
     662                 : 
     663                 :       default:
     664                 :         break;
     665                 :     }
     666                 :     
     667                 : /* -------------------------------------------------------------------- */
     668                 : /*      Fixup geometry dimension.                                       */
     669                 : /* -------------------------------------------------------------------- */
     670              88 :     if( poFeature->GetGeometryRef() != NULL )
     671                 :         poFeature->GetGeometryRef()->setCoordinateDimension( 
     672              21 :             DGNGetDimension( hDGN ) );
     673                 : 
     674              88 :     return poFeature;
     675                 : }
     676                 : 
     677                 : /************************************************************************/
     678                 : /*                           GetNextFeature()                           */
     679                 : /************************************************************************/
     680                 : 
     681              16 : OGRFeature *OGRDGNLayer::GetNextFeature()
     682                 : 
     683                 : {
     684                 :     DGNElemCore *psElement;
     685                 : 
     686              16 :     DGNGetElementIndex( hDGN, NULL );
     687                 : 
     688             105 :     while( (psElement = DGNReadElement( hDGN )) != NULL )
     689                 :     {
     690                 :         OGRFeature      *poFeature;
     691                 : 
     692              86 :         if( psElement->deleted )
     693                 :         {
     694               0 :             DGNFreeElement( hDGN, psElement );
     695               0 :             continue;
     696                 :         }
     697                 : 
     698              86 :         poFeature = ElementToFeature( psElement );
     699              86 :         DGNFreeElement( hDGN, psElement );
     700                 : 
     701              86 :         if( poFeature == NULL )
     702               0 :             continue;
     703                 : 
     704              86 :         if( poFeature->GetGeometryRef() == NULL )
     705                 :         {
     706              67 :             delete poFeature;
     707              67 :             continue;
     708                 :         }
     709                 : 
     710              19 :         if( (m_poAttrQuery == NULL
     711                 :              || m_poAttrQuery->Evaluate( poFeature ))
     712                 :             && FilterGeometry( poFeature->GetGeometryRef() ) )
     713              13 :             return poFeature;
     714                 : 
     715               6 :         delete poFeature;
     716                 :     }        
     717                 : 
     718               3 :     return NULL;
     719                 : }
     720                 : 
     721                 : /************************************************************************/
     722                 : /*                           TestCapability()                           */
     723                 : /************************************************************************/
     724                 : 
     725               0 : int OGRDGNLayer::TestCapability( const char * pszCap )
     726                 : 
     727                 : {
     728               0 :     if( EQUAL(pszCap,OLCRandomRead) )
     729               0 :         return TRUE;
     730                 : 
     731               0 :     else if( EQUAL(pszCap,OLCSequentialWrite) )
     732               0 :         return bUpdate;
     733               0 :     else if( EQUAL(pszCap,OLCRandomWrite) )
     734               0 :         return FALSE; /* maybe later? */
     735                 : 
     736               0 :     else if( EQUAL(pszCap,OLCFastFeatureCount) )
     737               0 :         return m_poFilterGeom == NULL || m_poAttrQuery == NULL;
     738                 : 
     739               0 :     else if( EQUAL(pszCap,OLCFastSpatialFilter) )
     740               0 :         return FALSE;
     741                 : 
     742               0 :     else if( EQUAL(pszCap,OLCFastGetExtent) )
     743               0 :         return TRUE;
     744                 : 
     745                 :     else 
     746               0 :         return FALSE;
     747                 : }
     748                 : 
     749                 : /************************************************************************/
     750                 : /*                          GetFeatureCount()                           */
     751                 : /************************************************************************/
     752                 : 
     753               0 : int OGRDGNLayer::GetFeatureCount( int bForce )
     754                 : 
     755                 : {
     756                 : /* -------------------------------------------------------------------- */
     757                 : /*      If any odd conditions are in effect collect the information     */
     758                 : /*      normally.                                                       */
     759                 : /* -------------------------------------------------------------------- */
     760               0 :     if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
     761               0 :         return OGRLayer::GetFeatureCount( bForce );
     762                 : 
     763                 : /* -------------------------------------------------------------------- */
     764                 : /*      Otherwise scan the index.                                       */
     765                 : /* -------------------------------------------------------------------- */
     766               0 :     int nElementCount, i, nFeatureCount = 0;
     767               0 :     int bInComplexShape = FALSE;
     768               0 :     const DGNElementInfo *pasIndex = DGNGetElementIndex(hDGN,&nElementCount);
     769                 : 
     770               0 :     for( i = 0; i < nElementCount; i++ )
     771                 :     {
     772               0 :         if( pasIndex[i].flags & DGNEIF_DELETED )
     773               0 :             continue;
     774                 : 
     775               0 :         switch( pasIndex[i].stype )
     776                 :         {
     777                 :           case DGNST_MULTIPOINT:
     778                 :           case DGNST_ARC:
     779                 :           case DGNST_TEXT:
     780               0 :             if( !(pasIndex[i].flags & DGNEIF_COMPLEX) || !bInComplexShape )
     781                 :             {
     782               0 :                 nFeatureCount++;
     783               0 :                 bInComplexShape = FALSE;
     784                 :             }
     785               0 :             break;
     786                 : 
     787                 :           case DGNST_COMPLEX_HEADER:
     788               0 :             nFeatureCount++;
     789               0 :             bInComplexShape = TRUE;
     790                 :             break;
     791                 : 
     792                 :           default:
     793                 :             break;
     794                 :         }
     795                 :     }
     796                 : 
     797               0 :     return nFeatureCount;
     798                 : }
     799                 : 
     800                 : /************************************************************************/
     801                 : /*                             GetExtent()                              */
     802                 : /************************************************************************/
     803                 : 
     804               0 : OGRErr OGRDGNLayer::GetExtent( OGREnvelope *psExtent, int bForce )
     805                 : 
     806                 : {
     807                 :     double      adfExtents[6];
     808                 : 
     809               0 :     if( !DGNGetExtents( hDGN, adfExtents ) )
     810               0 :         return OGRERR_FAILURE;
     811                 :     
     812               0 :     psExtent->MinX = adfExtents[0];
     813               0 :     psExtent->MinY = adfExtents[1];
     814               0 :     psExtent->MaxX = adfExtents[3];
     815               0 :     psExtent->MaxY = adfExtents[4];
     816                 :     
     817               0 :     return OGRERR_NONE;
     818                 : }
     819                 : 
     820                 : /************************************************************************/
     821                 : /*                      LineStringToElementGroup()                      */
     822                 : /*                                                                      */
     823                 : /*      Convert an OGR line string to one or more DGN elements.  If     */
     824                 : /*      the input is too long for a single element (more than 38        */
     825                 : /*      points) we split it into multiple LINE_STRING elements, and     */
     826                 : /*      prefix with a complex group header element.                     */
     827                 : /*                                                                      */
     828                 : /*      This method can create handle creating shapes, or line          */
     829                 : /*      strings for the aggregate object, but the components of a       */
     830                 : /*      complex shape group are always line strings.                    */
     831                 : /************************************************************************/
     832                 : 
     833                 : #define MAX_ELEM_POINTS 38
     834                 : 
     835               3 : DGNElemCore **OGRDGNLayer::LineStringToElementGroup( OGRLineString *poLS,
     836                 :                                                      int nGroupType )
     837                 : 
     838                 : {
     839               3 :     int nTotalPoints = poLS->getNumPoints();
     840               3 :     int iNextPoint = 0, iGeom = 0;
     841                 :     DGNElemCore **papsGroup;
     842                 : 
     843                 :     papsGroup = (DGNElemCore **) 
     844               3 :         CPLCalloc( sizeof(void*), (nTotalPoints/(MAX_ELEM_POINTS-1))+3 );
     845                 : 
     846              10 :     for( iNextPoint = 0; iNextPoint < nTotalPoints;  )
     847                 :     {
     848                 :         DGNPoint asPoints[38];
     849               4 :         int nThisCount = 0;
     850                 : 
     851                 :         // we need to repeat end points of elements.
     852               4 :         if( iNextPoint != 0 )
     853               1 :             iNextPoint--;
     854                 : 
     855              85 :         for( ; iNextPoint < nTotalPoints && nThisCount < MAX_ELEM_POINTS; 
     856                 :              iNextPoint++, nThisCount++ )
     857                 :         {
     858              81 :             asPoints[nThisCount].x = poLS->getX( iNextPoint );
     859              81 :             asPoints[nThisCount].y = poLS->getY( iNextPoint );
     860              81 :             asPoints[nThisCount].z = poLS->getZ( iNextPoint );
     861                 :         }
     862                 :         
     863               4 :         if( nTotalPoints <= MAX_ELEM_POINTS )
     864                 :             papsGroup[0] = DGNCreateMultiPointElem( hDGN, nGroupType,
     865               2 :                                                  nThisCount, asPoints);
     866                 :         else
     867               2 :             papsGroup[++iGeom] = 
     868                 :                 DGNCreateMultiPointElem( hDGN, DGNT_LINE_STRING,
     869               4 :                                          nThisCount, asPoints);
     870                 :     }
     871                 : 
     872                 : /* -------------------------------------------------------------------- */
     873                 : /*      We needed to make into a group.  Create the complex header      */
     874                 : /*      from the rest of the group.                                     */
     875                 : /* -------------------------------------------------------------------- */
     876               3 :     if( papsGroup[0] == NULL )
     877                 :     {
     878               1 :         if( nGroupType == DGNT_SHAPE )
     879               0 :             nGroupType = DGNT_COMPLEX_SHAPE_HEADER;
     880                 :         else
     881               1 :             nGroupType = DGNT_COMPLEX_CHAIN_HEADER;
     882                 :         
     883                 :         papsGroup[0] = 
     884                 :             DGNCreateComplexHeaderFromGroup( hDGN, nGroupType, 
     885               1 :                                              iGeom, papsGroup + 1 );
     886                 :     }
     887                 : 
     888               3 :     return papsGroup;
     889                 : }
     890                 : 
     891                 : /************************************************************************/
     892                 : /*                           TranslateLabel()                           */
     893                 : /*                                                                      */
     894                 : /*      Translate LABEL feature.                                        */
     895                 : /************************************************************************/
     896                 : 
     897               1 : DGNElemCore **OGRDGNLayer::TranslateLabel( OGRFeature *poFeature )
     898                 : 
     899                 : {
     900                 :     DGNElemCore **papsGroup;
     901               1 :     OGRPoint *poPoint = (OGRPoint *) poFeature->GetGeometryRef();
     902               1 :     OGRStyleMgr oMgr;
     903                 :     OGRStyleLabel *poLabel;
     904               1 :     const char *pszText = poFeature->GetFieldAsString( "Text" );
     905               1 :     double dfRotation = 0.0;
     906               1 :     double dfCharHeight = 100.0;
     907                 :     const char *pszFontName;
     908               1 :     int nFontID = 1; // 1 is the default font for DGN. Not 0.
     909                 : 
     910               1 :     oMgr.InitFromFeature( poFeature );
     911               1 :     poLabel = (OGRStyleLabel *) oMgr.GetPart( 0 );
     912               1 :     if( poLabel != NULL && poLabel->GetType() != OGRSTCLabel )
     913                 :     {
     914               0 :         delete poLabel;
     915               0 :         poLabel = NULL;
     916                 :     }
     917                 : 
     918               1 :     if( poLabel != NULL )
     919                 :     {
     920                 :         GBool bDefault;
     921                 : 
     922               1 :         if( poLabel->TextString(bDefault) != NULL && !bDefault )
     923               1 :             pszText = poLabel->TextString(bDefault);
     924               1 :         dfRotation = poLabel->Angle(bDefault);
     925                 : 
     926               1 :         poLabel->Size( bDefault );
     927               1 :         if( !bDefault && poLabel->GetUnit() == OGRSTUGround )
     928               0 :             dfCharHeight = poLabel->Size(bDefault);
     929                 :         // this part is really kind of bogus.
     930               1 :         if( !bDefault && poLabel->GetUnit() == OGRSTUMM )
     931               1 :             dfCharHeight = poLabel->Size(bDefault)/1000.0;
     932                 : 
     933                 :         /* get font id */
     934                 :         static const char  *papszFontNumbers[] =
     935                 :           { "STANDARD=0", "WORKING=1", "FANCY=2", "ENGINEERING=3", "NEWZERO=4",
     936                 :             "STENCEL=5", "USTN_FANCY=7", "COMPRESSED=8", "STENCEQ=9", "hand=10",
     937                 :             "ARCH=11", "ARCHB=12", "IGES1001=15", "IGES1002=16", "IGES1003=17", 
     938                 :             "CENTB=18", "MICROS=19", "ISOFRACTIONS=22", "ITALICS=23",
     939                 :             "ISO30=24", "GREEK=25", "ISOREC=26", "Isoeq=27", "ISO_FONTLEFT=30",
     940                 :             "ISO_FONTRIGHT=31", "INTL_ENGINEERING=32", "INTL_WORKING=33",
     941                 :             "ISOITEQ=34", "USTN FONT 26=36", "ARCHITECTURAL=41",
     942                 :             "BLOCK_OUTLINE=42", "LOW_RES_FILLED=43", "UPPERCASE50",
     943                 :             "FONT060=60", "din=61", "dinit=62", "helvl=63", "HELVLIT=64",
     944                 :             "helv=65", "HELVIT=66", "cent=67", "CENTIT=68", "SCRIPT=69", 
     945                 :             "MICROQ=76", "dotfont=77", "DOTIT=78", "FONT092=92", "FONT094=94",
     946                 :             "ANSI_SYMBOLS=100", "FEATURE_CONTROL_SYSMBOLS=101", "SYMB_FAST=102",
     947                 :             "INTL_ISO=105", "INTL_ISO_EQUAL=106", "INTL_ISO_ITALIC=107", 
     948                 :             "INTL_ISO_ITALIC_EQUAL=108", NULL }; 
     949                 : 
     950               1 :         pszFontName = poLabel->FontName( bDefault );
     951               1 :         if( !bDefault && pszFontName != NULL )
     952                 :         {
     953                 :             const char *pszFontNumber = 
     954               1 :                 CSLFetchNameValue((char**)papszFontNumbers, pszFontName);
     955                 : 
     956               1 :             if( pszFontNumber != NULL )
     957                 :             {
     958               1 :                 nFontID = atoi( pszFontNumber );
     959                 :             }
     960                 :         }
     961                 :     }
     962                 : 
     963               1 :     papsGroup = (DGNElemCore **) CPLCalloc(sizeof(void*),2);
     964                 :     papsGroup[0] = 
     965                 :         DGNCreateTextElem( hDGN, pszText, nFontID, DGNJ_LEFT_BOTTOM, 
     966                 :                            dfCharHeight, dfCharHeight, dfRotation, NULL,
     967                 :                            poPoint->getX(), 
     968                 :                            poPoint->getY(), 
     969               1 :                            poPoint->getZ() );
     970                 : 
     971               1 :     if( poLabel )
     972               1 :         delete poLabel;
     973                 : 
     974               1 :     return papsGroup;
     975                 : }
     976                 : 
     977                 : /************************************************************************/
     978                 : /*                           CreateFeature()                            */
     979                 : /*                                                                      */
     980                 : /*      Create a new feature and write to file.                         */
     981                 : /************************************************************************/
     982                 : 
     983               4 : OGRErr OGRDGNLayer::CreateFeature( OGRFeature *poFeature )
     984                 : 
     985                 : {
     986               4 :     if( !bUpdate )
     987                 :     {
     988                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     989               0 :                   "Attempt to create feature on read-only DGN file." );
     990               0 :         return OGRERR_FAILURE;
     991                 :     }
     992                 :     
     993               4 :     if( poFeature->GetGeometryRef() == NULL )
     994                 :     {
     995                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     996                 :                   "Features with empty, geometry collection geometries not\n"
     997               0 :                   "supported in DGN format." );
     998               0 :         return OGRERR_FAILURE;
     999                 :     }
    1000                 : 
    1001               4 :     return CreateFeatureWithGeom( poFeature, poFeature->GetGeometryRef() );
    1002                 : }
    1003                 : 
    1004                 : /************************************************************************/
    1005                 : /*                       CreateFeatureWithGeom()                        */
    1006                 : /*                                                                      */
    1007                 : /*      Create an element or element group from a given geometry and    */
    1008                 : /*      the given feature.  This method recurses to handle              */
    1009                 : /*      collections as essentially independent features.                */
    1010                 : /************************************************************************/
    1011                 : 
    1012               4 : OGRErr OGRDGNLayer::CreateFeatureWithGeom( OGRFeature *poFeature,
    1013                 :                                            OGRGeometry *poGeom)
    1014                 : 
    1015                 : {
    1016                 : /* -------------------------------------------------------------------- */
    1017                 : /*      Translate the geometry.                                         */
    1018                 : /* -------------------------------------------------------------------- */
    1019               4 :     DGNElemCore **papsGroup = NULL;
    1020                 :     int i;
    1021               4 :     const char *pszStyle = poFeature->GetStyleString();
    1022                 : 
    1023               4 :     if( wkbFlatten(poGeom->getGeometryType()) == wkbPoint )
    1024                 :     {
    1025               1 :         OGRPoint *poPoint = (OGRPoint *) poGeom;
    1026               1 :         const char *pszText = poFeature->GetFieldAsString("Text");
    1027                 : 
    1028               1 :         if( (pszText == NULL || strlen(pszText) == 0)
    1029                 :             && (pszStyle == NULL || strstr(pszStyle,"LABEL") == NULL) )
    1030                 :         {
    1031                 :             DGNPoint asPoints[2];
    1032                 : 
    1033               0 :             papsGroup = (DGNElemCore **) CPLCalloc(sizeof(void*),2);
    1034                 : 
    1035                 :             // Treat a non text point as a degenerate line.
    1036               0 :             asPoints[0].x = poPoint->getX();
    1037               0 :             asPoints[0].y = poPoint->getY();
    1038               0 :             asPoints[0].z = poPoint->getZ();
    1039               0 :             asPoints[1] = asPoints[0];
    1040                 :             
    1041                 :             papsGroup[0] = DGNCreateMultiPointElem( hDGN, DGNT_LINE, 
    1042               0 :                                                     2, asPoints );
    1043                 :         }
    1044                 :         else
    1045                 :         {
    1046               1 :             papsGroup = TranslateLabel( poFeature );
    1047                 :         }
    1048                 :     }
    1049               3 :     else if( wkbFlatten(poGeom->getGeometryType()) == wkbLineString )
    1050                 :     {
    1051                 :         papsGroup = LineStringToElementGroup( (OGRLineString *) poGeom, 
    1052               2 :                                               DGNT_LINE_STRING );
    1053                 :     }
    1054               1 :     else if( wkbFlatten(poGeom->getGeometryType()) == wkbPolygon )
    1055                 :     {
    1056               1 :         OGRPolygon *poPoly = ((OGRPolygon *) poGeom);
    1057                 : 
    1058                 :         // Ignore all but the exterior ring. 
    1059                 :         papsGroup = LineStringToElementGroup( poPoly->getExteriorRing(),
    1060               1 :                                               DGNT_SHAPE );
    1061                 :     }
    1062               0 :     else if( wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon 
    1063               0 :              || wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint
    1064               0 :              || wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString
    1065               0 :              || wkbFlatten(poGeom->getGeometryType()) == wkbGeometryCollection)
    1066                 :     {
    1067               0 :         OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeom;
    1068                 :         int iGeom;
    1069                 : 
    1070               0 :         for( iGeom = 0; iGeom < poGC->getNumGeometries(); iGeom++ )
    1071                 :         {
    1072                 :             OGRErr eErr = CreateFeatureWithGeom( poFeature, 
    1073               0 :                                                  poGC->getGeometryRef(iGeom) );
    1074               0 :             if( eErr != OGRERR_NONE )
    1075               0 :                 return eErr;
    1076                 :         }
    1077                 : 
    1078               0 :         return OGRERR_NONE;
    1079                 :     }
    1080                 :     else
    1081                 :     {
    1082                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    1083                 :                   "Unsupported geometry type (%s) for DGN.",
    1084               0 :                   OGRGeometryTypeToName( poGeom->getGeometryType() ) );
    1085               0 :         return OGRERR_FAILURE;
    1086                 :     }
    1087                 : 
    1088                 : /* -------------------------------------------------------------------- */
    1089                 : /*      Add other attributes.                                           */
    1090                 : /* -------------------------------------------------------------------- */
    1091               4 :     int nLevel = poFeature->GetFieldAsInteger( "Level" );
    1092               4 :     int nGraphicGroup = poFeature->GetFieldAsInteger( "GraphicGroup" );
    1093               4 :     int nColor = poFeature->GetFieldAsInteger( "ColorIndex" );
    1094               4 :     int nWeight = poFeature->GetFieldAsInteger( "Weight" );
    1095               4 :     int nStyle = poFeature->GetFieldAsInteger( "Style" );
    1096                 : 
    1097               4 :     nLevel = MAX(0,MIN(63,nLevel));
    1098               4 :     nColor = MAX(0,MIN(255,nColor));
    1099               4 :     nWeight = MAX(0,MIN(31,nWeight));
    1100               4 :     nStyle = MAX(0,MIN(7,nStyle));
    1101                 : 
    1102                 :     DGNUpdateElemCore( hDGN, papsGroup[0], nLevel, nGraphicGroup, nColor, 
    1103               4 :                        nWeight, nStyle );
    1104                 :     
    1105                 : /* -------------------------------------------------------------------- */
    1106                 : /*      Write to file.                                                  */
    1107                 : /* -------------------------------------------------------------------- */
    1108              10 :     for( i = 0; papsGroup[i] != NULL; i++ )
    1109                 :     {
    1110               6 :         DGNWriteElement( hDGN, papsGroup[i] );
    1111                 : 
    1112               6 :         if( i == 0 )
    1113               4 :             poFeature->SetFID( papsGroup[i]->element_id );
    1114                 : 
    1115               6 :         DGNFreeElement( hDGN, papsGroup[i] );
    1116                 :     }
    1117                 : 
    1118               4 :     CPLFree( papsGroup );
    1119                 : 
    1120               4 :     return OGRERR_NONE;
    1121                 : }

Generated by: LCOV version 1.7