LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/dxf - ogrdxfwriterlayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 349 236 67.6 %
Date: 2012-04-28 Functions: 21 14 66.7 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrdxfwriterlayer.cpp 22779 2011-07-23 18:53:29Z warmerdam $
       3                 :  *
       4                 :  * Project:  DXF Translator
       5                 :  * Purpose:  Implements OGRDXFWriterLayer - the OGRLayer class used for
       6                 :  *           writing a DXF file.
       7                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       8                 :  *
       9                 :  ******************************************************************************
      10                 :  * Copyright (c) 2009, Frank Warmerdam <warmerdam@pobox.com>
      11                 :  *
      12                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      13                 :  * copy of this software and associated documentation files (the "Software"),
      14                 :  * to deal in the Software without restriction, including without limitation
      15                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16                 :  * and/or sell copies of the Software, and to permit persons to whom the
      17                 :  * Software is furnished to do so, subject to the following conditions:
      18                 :  *
      19                 :  * The above copyright notice and this permission notice shall be included
      20                 :  * in all copies or substantial portions of the Software.
      21                 :  *
      22                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28                 :  * DEALINGS IN THE SOFTWARE.
      29                 :  ****************************************************************************/
      30                 : 
      31                 : #include "ogr_dxf.h"
      32                 : #include "cpl_conv.h"
      33                 : #include "cpl_string.h"
      34                 : #include "ogr_featurestyle.h"
      35                 : 
      36                 : CPL_CVSID("$Id: ogrdxfwriterlayer.cpp 22779 2011-07-23 18:53:29Z warmerdam $");
      37                 : 
      38                 : #ifndef PI
      39                 : #define PI  3.14159265358979323846
      40                 : #endif 
      41                 : 
      42                 : /************************************************************************/
      43                 : /*                         OGRDXFWriterLayer()                          */
      44                 : /************************************************************************/
      45                 : 
      46              10 : OGRDXFWriterLayer::OGRDXFWriterLayer( OGRDXFWriterDS *poDS, VSILFILE *fp )
      47                 : 
      48                 : {
      49              10 :     this->fp = fp;
      50              10 :     this->poDS = poDS;
      51                 : 
      52              10 :     nNextAutoID = 1;
      53                 : 
      54              10 :     poFeatureDefn = new OGRFeatureDefn( "entities" );
      55              10 :     poFeatureDefn->Reference();
      56                 : 
      57              10 :     OGRFieldDefn  oLayerField( "Layer", OFTString );
      58              10 :     poFeatureDefn->AddFieldDefn( &oLayerField );
      59                 : 
      60              10 :     OGRFieldDefn  oClassField( "SubClasses", OFTString );
      61              10 :     poFeatureDefn->AddFieldDefn( &oClassField );
      62                 : 
      63              10 :     OGRFieldDefn  oExtendedField( "ExtendedEntity", OFTString );
      64              10 :     poFeatureDefn->AddFieldDefn( &oExtendedField );
      65                 : 
      66              10 :     OGRFieldDefn  oLinetypeField( "Linetype", OFTString );
      67              10 :     poFeatureDefn->AddFieldDefn( &oLinetypeField );
      68                 : 
      69              10 :     OGRFieldDefn  oEntityHandleField( "EntityHandle", OFTString );
      70              10 :     poFeatureDefn->AddFieldDefn( &oEntityHandleField );
      71                 : 
      72              10 :     OGRFieldDefn  oTextField( "Text", OFTString );
      73              10 :     poFeatureDefn->AddFieldDefn( &oTextField );
      74                 : 
      75              10 :     OGRFieldDefn  oBlockField( "BlockName", OFTString );
      76              10 :     poFeatureDefn->AddFieldDefn( &oBlockField );
      77                 :     
      78              10 :     OGRFieldDefn  oScaleField( "BlockScale", OFTRealList );
      79              10 :     poFeatureDefn->AddFieldDefn( &oScaleField );
      80                 :     
      81              10 :     OGRFieldDefn  oBlockAngleField( "BlockAngle", OFTReal );
      82              10 :     poFeatureDefn->AddFieldDefn( &oBlockAngleField );
      83              10 : }
      84                 : 
      85                 : /************************************************************************/
      86                 : /*                         ~OGRDXFWriterLayer()                         */
      87                 : /************************************************************************/
      88                 : 
      89              10 : OGRDXFWriterLayer::~OGRDXFWriterLayer()
      90                 : 
      91                 : {
      92              10 :     if( poFeatureDefn )
      93              10 :         poFeatureDefn->Release();
      94              10 : }
      95                 : 
      96                 : /************************************************************************/
      97                 : /*                              ResetFP()                               */
      98                 : /*                                                                      */
      99                 : /*      Redirect output.  Mostly used for writing block definitions.    */
     100                 : /************************************************************************/
     101                 : 
     102               2 : void OGRDXFWriterLayer::ResetFP( VSILFILE *fpNew )
     103                 : 
     104                 : {
     105               2 :     fp = fpNew;
     106               2 : }
     107                 : 
     108                 : /************************************************************************/
     109                 : /*                           TestCapability()                           */
     110                 : /************************************************************************/
     111                 : 
     112               0 : int OGRDXFWriterLayer::TestCapability( const char * pszCap )
     113                 : 
     114                 : {
     115               0 :     if( EQUAL(pszCap,OLCStringsAsUTF8) )
     116               0 :         return TRUE;
     117               0 :     else if( EQUAL(pszCap,OLCSequentialWrite) )
     118               0 :         return TRUE;
     119                 :     else 
     120               0 :         return FALSE;
     121                 : }
     122                 : 
     123                 : /************************************************************************/
     124                 : /*                            CreateField()                             */
     125                 : /*                                                                      */
     126                 : /*      This is really a dummy as our fields are precreated.            */
     127                 : /************************************************************************/
     128                 : 
     129               0 : OGRErr OGRDXFWriterLayer::CreateField( OGRFieldDefn *poField,
     130                 :                                        int bApproxOK )
     131                 : 
     132                 : {
     133               0 :     if( poFeatureDefn->GetFieldIndex(poField->GetNameRef()) >= 0
     134                 :         && bApproxOK )
     135               0 :         return OGRERR_NONE;
     136                 : 
     137                 :     CPLError( CE_Failure, CPLE_AppDefined,
     138                 :               "DXF layer does not support arbitrary field creation, field '%s' not created.",
     139               0 :               poField->GetNameRef() );
     140                 : 
     141               0 :     return OGRERR_FAILURE;
     142                 : }
     143                 : 
     144                 : /************************************************************************/
     145                 : /*                             WriteValue()                             */
     146                 : /************************************************************************/
     147                 : 
     148             130 : int OGRDXFWriterLayer::WriteValue( int nCode, const char *pszValue )
     149                 : 
     150                 : {
     151             130 :     CPLString osLinePair;
     152                 : 
     153             130 :     osLinePair.Printf( "%3d\n", nCode );
     154                 : 
     155             130 :     if( strlen(pszValue) < 255 )
     156             130 :         osLinePair += pszValue;
     157                 :     else
     158               0 :         osLinePair.append( pszValue, 255 );
     159                 : 
     160             130 :     osLinePair += "\n";
     161                 : 
     162                 :     return VSIFWriteL( osLinePair.c_str(), 
     163             130 :                        1, osLinePair.size(), fp ) == osLinePair.size();
     164                 : }
     165                 : 
     166                 : /************************************************************************/
     167                 : /*                             WriteValue()                             */
     168                 : /************************************************************************/
     169                 : 
     170              68 : int OGRDXFWriterLayer::WriteValue( int nCode, int nValue )
     171                 : 
     172                 : {
     173              68 :     CPLString osLinePair;
     174                 : 
     175              68 :     osLinePair.Printf( "%3d\n%d\n", nCode, nValue );
     176                 : 
     177                 :     return VSIFWriteL( osLinePair.c_str(), 
     178              68 :                        1, osLinePair.size(), fp ) == osLinePair.size();
     179                 : }
     180                 : 
     181                 : /************************************************************************/
     182                 : /*                             WriteValue()                             */
     183                 : /************************************************************************/
     184                 : 
     185             116 : int OGRDXFWriterLayer::WriteValue( int nCode, double dfValue )
     186                 : 
     187                 : {
     188                 :     char szLinePair[64];
     189                 : 
     190             116 :     snprintf(szLinePair, sizeof(szLinePair), "%3d\n%.15g\n", nCode, dfValue );
     191             116 :     char* pszComma = strchr(szLinePair, ',');
     192             116 :     if (pszComma)
     193               0 :         *pszComma = '.';
     194             116 :     size_t nLen = strlen(szLinePair);
     195                 : 
     196                 :     return VSIFWriteL( szLinePair, 
     197             116 :                        1, nLen, fp ) == nLen;
     198                 : }
     199                 : 
     200                 : /************************************************************************/
     201                 : /*                             WriteCore()                              */
     202                 : /*                                                                      */
     203                 : /*      Write core fields common to all sorts of elements.              */
     204                 : /************************************************************************/
     205                 : 
     206              28 : OGRErr OGRDXFWriterLayer::WriteCore( OGRFeature *poFeature )
     207                 : 
     208                 : {
     209                 : /* -------------------------------------------------------------------- */
     210                 : /*      Write out an entity id.  I'm not sure why this is critical,     */
     211                 : /*      but it seems that VoloView will just quietly fail to open       */
     212                 : /*      dxf files without entity ids set on most/all entities.          */
     213                 : /*      Also, for reasons I don't understand these ids seem to have     */
     214                 : /*      to start somewhere around 0x50 hex (80 decimal).                */
     215                 : /* -------------------------------------------------------------------- */
     216              28 :     poFeature->SetFID( poDS->WriteEntityID(fp,poFeature->GetFID()) );
     217                 : 
     218                 : /* -------------------------------------------------------------------- */
     219                 : /*      For now we assign everything to the default layer - layer       */
     220                 : /*      "0" - if there is no layer property on the source features.     */
     221                 : /* -------------------------------------------------------------------- */
     222              28 :     const char *pszLayer = poFeature->GetFieldAsString( "Layer" );
     223              46 :     if( pszLayer == NULL || strlen(pszLayer) == 0 )
     224                 :     {
     225              18 :         WriteValue( 8, "0" );
     226                 :     }
     227                 :     else
     228                 :     {
     229                 :         const char *pszExists = 
     230              10 :             poDS->oHeaderDS.LookupLayerProperty( pszLayer, "Exists" );
     231              10 :         if( (pszExists == NULL || strlen(pszExists) == 0)
     232                 :             && CSLFindString( poDS->papszLayersToCreate, pszLayer ) == -1 )
     233                 :         {
     234                 :             poDS->papszLayersToCreate = 
     235               6 :                 CSLAddString( poDS->papszLayersToCreate, pszLayer );
     236                 :         }
     237                 : 
     238              10 :         WriteValue( 8, pszLayer );
     239                 :     }
     240                 : 
     241              28 :     return OGRERR_NONE;
     242                 : }
     243                 : 
     244                 : /************************************************************************/
     245                 : /*                            WriteINSERT()                             */
     246                 : /************************************************************************/
     247                 : 
     248               8 : OGRErr OGRDXFWriterLayer::WriteINSERT( OGRFeature *poFeature )
     249                 : 
     250                 : {
     251               8 :     WriteValue( 0, "INSERT" );
     252               8 :     WriteCore( poFeature );
     253               8 :     WriteValue( 100, "AcDbEntity" );
     254               8 :     WriteValue( 100, "AcDbBlockReference" );
     255               8 :     WriteValue( 2, poFeature->GetFieldAsString("BlockName") );
     256                 :     
     257                 : /* -------------------------------------------------------------------- */
     258                 : /*      Write location.                                                 */
     259                 : /* -------------------------------------------------------------------- */
     260               8 :     OGRPoint *poPoint = (OGRPoint *) poFeature->GetGeometryRef();
     261                 : 
     262               8 :     WriteValue( 10, poPoint->getX() );
     263               8 :     if( !WriteValue( 20, poPoint->getY() ) ) 
     264               0 :         return OGRERR_FAILURE;
     265                 : 
     266               8 :     if( poPoint->getGeometryType() == wkbPoint25D )
     267                 :     {
     268               0 :         if( !WriteValue( 30, poPoint->getZ() ) )
     269               0 :             return OGRERR_FAILURE;
     270                 :     }
     271                 :     
     272                 : /* -------------------------------------------------------------------- */
     273                 : /*      Write scaling.                                                  */
     274                 : /* -------------------------------------------------------------------- */
     275                 :     int nScaleCount;
     276                 :     const double *padfScale = 
     277               8 :         poFeature->GetFieldAsDoubleList( "BlockScale", &nScaleCount );
     278                 : 
     279               8 :     if( nScaleCount == 3 )
     280                 :     {
     281               2 :         WriteValue( 41, padfScale[0] );
     282               2 :         WriteValue( 42, padfScale[1] );
     283               2 :         WriteValue( 43, padfScale[2] );
     284                 :     }
     285                 : 
     286                 : /* -------------------------------------------------------------------- */
     287                 : /*      Write rotation.                                                 */
     288                 : /* -------------------------------------------------------------------- */
     289               8 :     double dfAngle = poFeature->GetFieldAsDouble( "BlockAngle" );
     290                 : 
     291               8 :     if( dfAngle != 0.0 )
     292                 :     {
     293               2 :         WriteValue( 50, dfAngle ); // degrees
     294                 :     }
     295                 : 
     296               8 :     return OGRERR_NONE;
     297                 : }
     298                 : 
     299                 : /************************************************************************/
     300                 : /*                             WritePOINT()                             */
     301                 : /************************************************************************/
     302                 : 
     303               2 : OGRErr OGRDXFWriterLayer::WritePOINT( OGRFeature *poFeature )
     304                 : 
     305                 : {
     306               2 :     WriteValue( 0, "POINT" );
     307               2 :     WriteCore( poFeature );
     308               2 :     WriteValue( 100, "AcDbEntity" );
     309               2 :     WriteValue( 100, "AcDbPoint" );
     310                 : 
     311               2 :     OGRPoint *poPoint = (OGRPoint *) poFeature->GetGeometryRef();
     312                 : 
     313               2 :     WriteValue( 10, poPoint->getX() );
     314               2 :     if( !WriteValue( 20, poPoint->getY() ) ) 
     315               0 :         return OGRERR_FAILURE;
     316                 : 
     317               2 :     if( poPoint->getGeometryType() == wkbPoint25D )
     318                 :     {
     319               0 :         if( !WriteValue( 30, poPoint->getZ() ) )
     320               0 :             return OGRERR_FAILURE;
     321                 :     }
     322                 :     
     323               2 :     return OGRERR_NONE;
     324                 : }
     325                 : 
     326                 : /************************************************************************/
     327                 : /*                             TextEscape()                             */
     328                 : /*                                                                      */
     329                 : /*      Translate UTF8 to Win1252 and escape special characters like    */
     330                 : /*      newline and space with DXF style escapes.  Note that            */
     331                 : /*      non-win1252 unicode characters are translated using the         */
     332                 : /*      unicode escape sequence.                                        */
     333                 : /************************************************************************/
     334                 : 
     335               0 : CPLString OGRDXFWriterLayer::TextEscape( const char *pszInput )
     336                 : 
     337                 : {
     338               0 :     CPLString osResult;
     339                 :     wchar_t *panInput = CPLRecodeToWChar( pszInput, 
     340                 :                                           CPL_ENC_UTF8, 
     341               0 :                                           CPL_ENC_UCS2 );
     342                 :     int i;
     343                 : 
     344                 : 
     345               0 :     for( i = 0; panInput[i] != 0; i++ )
     346                 :     {
     347               0 :         if( panInput[i] == '\n' )
     348               0 :             osResult += "\\P";
     349               0 :         else if( panInput[i] == ' ' )
     350               0 :             osResult += "\\~";
     351               0 :         else if( panInput[i] == '\\' )
     352               0 :             osResult += "\\\\";
     353               0 :         else if( panInput[i] > 255 )
     354                 :         {
     355               0 :             CPLString osUnicode;
     356               0 :             osUnicode.Printf( "\\U+%04x", (int) panInput[i] );
     357               0 :             osResult += osUnicode;
     358                 :         }
     359                 :         else
     360               0 :             osResult += (char) panInput[i];
     361                 :     }
     362                 : 
     363               0 :     CPLFree(panInput);
     364                 :     
     365               0 :     return osResult;
     366                 : }
     367                 : 
     368                 : /************************************************************************/
     369                 : /*                             WriteTEXT()                              */
     370                 : /************************************************************************/
     371                 : 
     372               0 : OGRErr OGRDXFWriterLayer::WriteTEXT( OGRFeature *poFeature )
     373                 : 
     374                 : {
     375               0 :     WriteValue( 0, "MTEXT" );
     376               0 :     WriteCore( poFeature );
     377               0 :     WriteValue( 100, "AcDbEntity" );
     378               0 :     WriteValue( 100, "AcDbMText" );
     379                 : 
     380                 : /* -------------------------------------------------------------------- */
     381                 : /*      Do we have styling information?                                 */
     382                 : /* -------------------------------------------------------------------- */
     383               0 :     OGRStyleTool *poTool = NULL;
     384               0 :     OGRStyleMgr oSM;
     385                 : 
     386               0 :     if( poFeature->GetStyleString() != NULL )
     387                 :     {
     388               0 :         oSM.InitFromFeature( poFeature );
     389                 : 
     390               0 :         if( oSM.GetPartCount() > 0 )
     391               0 :             poTool = oSM.GetPart(0);
     392                 :     }
     393                 : 
     394                 : /* ==================================================================== */
     395                 : /*      Process the LABEL tool.                                         */
     396                 : /* ==================================================================== */
     397               0 :     if( poTool && poTool->GetType() == OGRSTCLabel )
     398                 :     {
     399               0 :         OGRStyleLabel *poLabel = (OGRStyleLabel *) poTool;
     400                 :         GBool  bDefault;
     401                 : 
     402                 : /* -------------------------------------------------------------------- */
     403                 : /*      Color                                                           */
     404                 : /* -------------------------------------------------------------------- */
     405               0 :         if( poLabel->ForeColor(bDefault) != NULL && !bDefault )
     406                 :             WriteValue( 62, ColorStringToDXFColor( 
     407               0 :                             poLabel->ForeColor(bDefault) ) );
     408                 : 
     409                 : /* -------------------------------------------------------------------- */
     410                 : /*      Angle                                                           */
     411                 : /* -------------------------------------------------------------------- */
     412               0 :         double dfAngle = poLabel->Angle(bDefault);
     413                 : 
     414                 :         // The DXF2000 reference says this is in radians, but in files
     415                 :         // I see it seems to be in degrees. Perhaps this is version dependent?
     416               0 :         if( !bDefault )
     417               0 :             WriteValue( 50, dfAngle );
     418                 : 
     419                 : /* -------------------------------------------------------------------- */
     420                 : /*      Height - We need to fetch this in georeferenced units - I'm     */
     421                 : /*      doubt the default translation mechanism will be much good.      */
     422                 : /* -------------------------------------------------------------------- */
     423               0 :         poTool->SetUnit( OGRSTUGround );
     424               0 :         double dfHeight = poLabel->Size(bDefault);
     425                 : 
     426               0 :         if( !bDefault )
     427               0 :             WriteValue( 40, dfHeight );
     428                 : 
     429                 : /* -------------------------------------------------------------------- */
     430                 : /*      Anchor / Attachment Point                                       */
     431                 : /* -------------------------------------------------------------------- */
     432               0 :         int nAnchor = poLabel->Anchor(bDefault);
     433                 :         
     434               0 :         if( !bDefault )
     435                 :         {
     436                 :             const static int anAnchorMap[] = 
     437                 :                 { -1, 7, 8, 9, 4, 5, 6, 1, 2, 3, 7, 8, 9 };
     438                 : 
     439               0 :             if( nAnchor > 0 && nAnchor < 13 )
     440               0 :                 WriteValue( 71, anAnchorMap[nAnchor] );
     441                 :         }
     442                 : 
     443                 : /* -------------------------------------------------------------------- */
     444                 : /*      Escape the text, and convert to ISO8859.                        */
     445                 : /* -------------------------------------------------------------------- */
     446               0 :         const char *pszText = poLabel->TextString( bDefault );
     447                 : 
     448               0 :         if( pszText != NULL && !bDefault )
     449                 :         {
     450               0 :             CPLString osEscaped = TextEscape( pszText );
     451               0 :             WriteValue( 1, osEscaped );
     452                 :         }
     453                 :     }
     454                 : 
     455               0 :     delete poTool;
     456                 : 
     457                 : /* -------------------------------------------------------------------- */
     458                 : /*      Write the location.                                             */
     459                 : /* -------------------------------------------------------------------- */
     460               0 :     OGRPoint *poPoint = (OGRPoint *) poFeature->GetGeometryRef();
     461                 : 
     462               0 :     WriteValue( 10, poPoint->getX() );
     463               0 :     if( !WriteValue( 20, poPoint->getY() ) ) 
     464               0 :         return OGRERR_FAILURE;
     465                 : 
     466               0 :     if( poPoint->getGeometryType() == wkbPoint25D )
     467                 :     {
     468               0 :         if( !WriteValue( 30, poPoint->getZ() ) )
     469               0 :             return OGRERR_FAILURE;
     470                 :     }
     471                 :     
     472               0 :     return OGRERR_NONE;
     473                 : 
     474                 : }
     475                 : 
     476                 : /************************************************************************/
     477                 : /*                     PrepareLineTypeDefinition()                      */
     478                 : /************************************************************************/
     479                 : CPLString 
     480               4 : OGRDXFWriterLayer::PrepareLineTypeDefinition( OGRFeature *poFeature, 
     481                 :                                               OGRStyleTool *poTool )
     482                 : 
     483                 : {
     484               4 :     CPLString osDef;
     485               4 :     OGRStylePen *poPen = (OGRStylePen *) poTool;
     486                 :     GBool  bDefault;
     487                 :     const char *pszPattern;
     488                 :     
     489                 : /* -------------------------------------------------------------------- */
     490                 : /*      Fetch pattern.                                                  */
     491                 : /* -------------------------------------------------------------------- */
     492               4 :     pszPattern = poPen->Pattern( bDefault );
     493               4 :     if( bDefault || strlen(pszPattern) == 0 ) 
     494               0 :         return "";
     495                 : 
     496                 : /* -------------------------------------------------------------------- */
     497                 : /*      Split into pen up / pen down bits.                              */
     498                 : /* -------------------------------------------------------------------- */
     499               4 :     char **papszTokens = CSLTokenizeString(pszPattern);
     500                 :     int i;
     501               4 :     double dfTotalLength = 0;
     502                 : 
     503              12 :     for( i = 0; papszTokens != NULL && papszTokens[i] != NULL; i++ )
     504                 :     {
     505               8 :         const char *pszToken = papszTokens[i];
     506                 :         const char *pszUnit;
     507               8 :         CPLString osAmount;
     508               8 :         CPLString osDXFEntry;
     509                 : 
     510                 :         // Split amount and unit.
     511               8 :         for( pszUnit = pszToken; 
     512                 :              strchr( "0123456789.", *pszUnit) != NULL;
     513                 :              pszUnit++ ) {}
     514                 : 
     515               8 :         osAmount.assign(pszToken,(int) (pszUnit-pszToken));
     516                 :         
     517                 :         // If the unit is other than 'g' we really should be trying to 
     518                 :         // do some type of transformation - but what to do?  Pretty hard.
     519                 :         
     520                 :         // 
     521                 : 
     522                 :         // Even entries are "pen down" represented as negative in DXF.
     523               8 :         if( i%2 == 0 )
     524               4 :             osDXFEntry.Printf( " 49\n-%s\n 74\n0\n", osAmount.c_str() );
     525                 :         else
     526               4 :             osDXFEntry.Printf( " 49\n%s\n 74\n0\n", osAmount.c_str() );
     527                 :         
     528               8 :         osDef += osDXFEntry;
     529                 : 
     530               8 :         dfTotalLength += atof(osAmount);
     531                 :     }
     532                 : 
     533                 : /* -------------------------------------------------------------------- */
     534                 : /*      Prefix 73 and 40 items to the definition.                       */
     535                 : /* -------------------------------------------------------------------- */
     536               4 :     CPLString osPrefix;
     537                 :     
     538                 :     osPrefix.Printf( " 73\n%d\n 40\n%.6g\n", 
     539                 :                      CSLCount(papszTokens), 
     540               4 :                      dfTotalLength );
     541               4 :     osDef = osPrefix + osDef;
     542                 : 
     543               4 :     CSLDestroy( papszTokens );
     544                 : 
     545               4 :     return osDef;
     546                 : }
     547                 : 
     548                 : /************************************************************************/
     549                 : /*                           WritePOLYLINE()                            */
     550                 : /************************************************************************/
     551                 : 
     552              14 : OGRErr OGRDXFWriterLayer::WritePOLYLINE( OGRFeature *poFeature,
     553                 :                                          OGRGeometry *poGeom )
     554                 : 
     555                 : {
     556                 : /* -------------------------------------------------------------------- */
     557                 : /*      For now we handle multilinestrings by writing a series of       */
     558                 : /*      entities.                                                       */
     559                 : /* -------------------------------------------------------------------- */
     560              14 :     if( poGeom == NULL )
     561              14 :         poGeom = poFeature->GetGeometryRef();
     562                 : 
     563              14 :     if ( poGeom->IsEmpty() )
     564                 :     {
     565               0 :         return OGRERR_NONE;
     566                 :     }
     567                 :             
     568              28 :     if( wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon 
     569              14 :         || wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString )
     570                 :     {
     571               0 :         OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeom;
     572                 :         int iGeom;
     573               0 :         OGRErr eErr = OGRERR_NONE;
     574                 : 
     575               0 :         for( iGeom = 0; 
     576                 :              eErr == OGRERR_NONE && iGeom < poGC->getNumGeometries(); 
     577                 :              iGeom++ )
     578                 :         {
     579               0 :             eErr = WritePOLYLINE( poFeature, poGC->getGeometryRef( iGeom ) );
     580                 :         }
     581                 : 
     582               0 :         return eErr;
     583                 :     }
     584                 : 
     585                 : /* -------------------------------------------------------------------- */
     586                 : /*      Polygons are written with on entity per ring.                   */
     587                 : /* -------------------------------------------------------------------- */
     588              14 :     if( wkbFlatten(poGeom->getGeometryType()) == wkbPolygon )
     589                 :     {
     590               0 :         OGRPolygon *poPoly = (OGRPolygon *) poGeom;
     591                 :         int iGeom;
     592                 :         OGRErr eErr;
     593                 : 
     594               0 :         eErr = WritePOLYLINE( poFeature, poPoly->getExteriorRing() );
     595               0 :         for( iGeom = 0; 
     596                 :              eErr == OGRERR_NONE && iGeom < poPoly->getNumInteriorRings(); 
     597                 :              iGeom++ )
     598                 :         {
     599               0 :             eErr = WritePOLYLINE( poFeature, poPoly->getInteriorRing(iGeom) );
     600                 :         }
     601                 : 
     602               0 :         return eErr;
     603                 :     }
     604                 : 
     605                 : /* -------------------------------------------------------------------- */
     606                 : /*      Do we now have a geometry we can work with?                     */
     607                 : /* -------------------------------------------------------------------- */
     608              14 :     if( wkbFlatten(poGeom->getGeometryType()) != wkbLineString )
     609               0 :         return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
     610                 : 
     611              14 :     OGRLineString *poLS = (OGRLineString *) poGeom;
     612                 : 
     613                 : /* -------------------------------------------------------------------- */
     614                 : /*      Write as a lightweight polygon.                                 */
     615                 : /* -------------------------------------------------------------------- */
     616              14 :     WriteValue( 0, "LWPOLYLINE" );
     617              14 :     WriteCore( poFeature );
     618              14 :     WriteValue( 100, "AcDbEntity" );
     619              14 :     WriteValue( 100, "AcDbPolyline" );
     620              14 :     if( EQUAL( poGeom->getGeometryName(), "LINEARRING" ) )
     621               0 :         WriteValue( 70, 1 );
     622                 :     else
     623              14 :         WriteValue( 70, 0 );
     624              14 :     WriteValue( 90, poLS->getNumPoints() );
     625                 : 
     626                 : /* -------------------------------------------------------------------- */
     627                 : /*      Do we have styling information?                                 */
     628                 : /* -------------------------------------------------------------------- */
     629              14 :     OGRStyleTool *poTool = NULL;
     630              14 :     OGRStyleMgr oSM;
     631                 : 
     632              14 :     if( poFeature->GetStyleString() != NULL )
     633                 :     {
     634               6 :         oSM.InitFromFeature( poFeature );
     635                 : 
     636               6 :         if( oSM.GetPartCount() > 0 )
     637               6 :             poTool = oSM.GetPart(0);
     638                 :     }
     639                 : 
     640                 : /* -------------------------------------------------------------------- */
     641                 : /*      Handle a PEN tool to control drawing color and width.           */
     642                 : /*      Perhaps one day also dottedness, etc.                           */
     643                 : /* -------------------------------------------------------------------- */
     644              14 :     if( poTool && poTool->GetType() == OGRSTCPen )
     645                 :     {
     646               6 :         OGRStylePen *poPen = (OGRStylePen *) poTool;
     647                 :         GBool  bDefault;
     648                 : 
     649               6 :         if( poPen->Color(bDefault) != NULL && !bDefault )
     650               6 :             WriteValue( 62, ColorStringToDXFColor( poPen->Color(bDefault) ) );
     651                 : 
     652                 :         // we want to fetch the width in ground units. 
     653               6 :         poPen->SetUnit( OGRSTUGround, 1.0 );
     654               6 :         double dfWidth = poPen->Width(bDefault);
     655                 : 
     656               6 :         if( !bDefault )
     657               6 :             WriteValue( 370, (int) floor(dfWidth * 100 + 0.5) );
     658                 :     }
     659                 : 
     660                 : /* -------------------------------------------------------------------- */
     661                 : /*      Do we have a Linetype for the feature?                          */
     662                 : /* -------------------------------------------------------------------- */
     663              14 :     CPLString osLineType = poFeature->GetFieldAsString( "Linetype" );
     664                 : 
     665              14 :     if( osLineType.size() > 0 
     666                 :         && (poDS->oHeaderDS.LookupLineType( osLineType ) != NULL 
     667                 :             || oNewLineTypes.count(osLineType) > 0 ) )
     668                 :     {
     669                 :         // Already define -> just reference it.
     670               2 :         WriteValue( 6, osLineType );
     671                 :     }
     672              12 :     else if( poTool != NULL && poTool->GetType() == OGRSTCPen )
     673                 :     {
     674                 :         CPLString osDefinition = PrepareLineTypeDefinition( poFeature, 
     675               4 :                                                             poTool );
     676                 : 
     677               4 :         if( osDefinition != "" && osLineType == "" )
     678                 :         {
     679                 :             // Is this definition already created and named?
     680               2 :             std::map<CPLString,CPLString>::iterator it;
     681                 : 
     682               4 :             for( it = oNewLineTypes.begin();
     683                 :                  it != oNewLineTypes.end();
     684                 :                  it++ )
     685                 :             {
     686               2 :                 if( (*it).second == osDefinition )
     687                 :                 {
     688               0 :                     osLineType = (*it).first;
     689               0 :                     break;
     690                 :                 }
     691                 :             }
     692                 : 
     693                 :             // create an automatic name for it.
     694               2 :             if( osLineType == "" )
     695                 :             {
     696               2 :                 do 
     697                 :                 { 
     698               2 :                     osLineType.Printf( "AutoLineType-%d", nNextAutoID++ );
     699                 :                 }
     700                 :                 while( poDS->oHeaderDS.LookupLineType(osLineType) != NULL );
     701                 :             }
     702                 :         }
     703                 : 
     704                 :         // If it isn't already defined, add it now.
     705               4 :         if( osDefinition != "" && oNewLineTypes.count(osLineType) == 0 )
     706                 :         {
     707               4 :             oNewLineTypes[osLineType] = osDefinition;
     708               4 :             WriteValue( 6, osLineType );
     709               4 :         }
     710                 :     }
     711                 : 
     712                 : /* -------------------------------------------------------------------- */
     713                 : /*      Write the vertices                                              */
     714                 : /* -------------------------------------------------------------------- */
     715                 :     int iVert;
     716                 : 
     717              42 :     for( iVert = 0; iVert < poLS->getNumPoints(); iVert++ )
     718                 :     {
     719              28 :         WriteValue( 10, poLS->getX(iVert) );
     720              28 :         if( !WriteValue( 20, poLS->getY(iVert) ) ) 
     721               0 :             return OGRERR_FAILURE;
     722                 : 
     723              28 :         if( poLS->getGeometryType() == wkbLineString25D )
     724                 :         {
     725               0 :             if( !WriteValue( 38, poLS->getZ(iVert) ) )
     726               0 :                 return OGRERR_FAILURE;
     727                 :         }
     728                 :     }
     729                 :     
     730              14 :     delete poTool;
     731                 : 
     732              14 :     return OGRERR_NONE;
     733                 : 
     734                 : #ifdef notdef
     735                 : /* -------------------------------------------------------------------- */
     736                 : /*      Alternate unmaintained implementation as a polyline entity.     */
     737                 : /* -------------------------------------------------------------------- */
     738                 :     WriteValue( 0, "POLYLINE" );
     739                 :     WriteCore( poFeature );
     740                 :     WriteValue( 100, "AcDbEntity" );
     741                 :     WriteValue( 100, "AcDbPolyline" );
     742                 :     if( EQUAL( poGeom->getGeometryName(), "LINEARRING" ) )
     743                 :         WriteValue( 70, 1 );
     744                 :     else
     745                 :         WriteValue( 70, 0 );
     746                 :     WriteValue( 66, "1" );
     747                 : 
     748                 :     int iVert;
     749                 : 
     750                 :     for( iVert = 0; iVert < poLS->getNumPoints(); iVert++ )
     751                 :     {
     752                 :         WriteValue( 0, "VERTEX" );
     753                 :         WriteValue( 8, "0" );
     754                 :         WriteValue( 10, poLS->getX(iVert) );
     755                 :         if( !WriteValue( 20, poLS->getY(iVert) ) ) 
     756                 :             return OGRERR_FAILURE;
     757                 : 
     758                 :         if( poLS->getGeometryType() == wkbLineString25D )
     759                 :         {
     760                 :             if( !WriteValue( 30, poLS->getZ(iVert) ) )
     761                 :                 return OGRERR_FAILURE;
     762                 :         }
     763                 :     }
     764                 : 
     765                 :     WriteValue( 0, "SEQEND" );
     766                 :     WriteValue( 8, "0" );
     767                 :     
     768                 :     return OGRERR_NONE;
     769                 : #endif
     770                 : }
     771                 : 
     772                 : /************************************************************************/
     773                 : /*                             WriteHATCH()                             */
     774                 : /************************************************************************/
     775                 : 
     776               4 : OGRErr OGRDXFWriterLayer::WriteHATCH( OGRFeature *poFeature,
     777                 :                                       OGRGeometry *poGeom )
     778                 : 
     779                 : {
     780                 : /* -------------------------------------------------------------------- */
     781                 : /*      For now we handle multipolygons by writing a series of          */
     782                 : /*      entities.                                                       */
     783                 : /* -------------------------------------------------------------------- */
     784               4 :     if( poGeom == NULL )
     785               4 :         poGeom = poFeature->GetGeometryRef();
     786                 : 
     787               4 :     if ( poGeom->IsEmpty() )
     788                 :     {
     789               0 :         return OGRERR_NONE;
     790                 :     }
     791                 :             
     792               4 :     if( wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon )
     793                 :     {
     794               0 :         OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeom;
     795                 :         int iGeom;
     796               0 :         OGRErr eErr = OGRERR_NONE;
     797                 : 
     798               0 :         for( iGeom = 0; 
     799                 :              eErr == OGRERR_NONE && iGeom < poGC->getNumGeometries(); 
     800                 :              iGeom++ )
     801                 :         {
     802               0 :             eErr = WriteHATCH( poFeature, poGC->getGeometryRef( iGeom ) );
     803                 :         }
     804                 : 
     805               0 :         return eErr;
     806                 :     }
     807                 : 
     808                 : /* -------------------------------------------------------------------- */
     809                 : /*      Do we now have a geometry we can work with?                     */
     810                 : /* -------------------------------------------------------------------- */
     811               4 :     if( wkbFlatten(poGeom->getGeometryType()) != wkbPolygon )
     812               0 :         return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
     813                 : 
     814                 : /* -------------------------------------------------------------------- */
     815                 : /*      Write as a hatch.                                               */
     816                 : /* -------------------------------------------------------------------- */
     817               4 :     WriteValue( 0, "HATCH" );
     818               4 :     WriteCore( poFeature );
     819               4 :     WriteValue( 100, "AcDbEntity" );
     820               4 :     WriteValue( 100, "AcDbHatch" );
     821               4 :     WriteValue( 2, "SOLID" ); // fill pattern
     822               4 :     WriteValue( 70, 1 ); // solid fill
     823               4 :     WriteValue( 71, 0 ); // associativity 
     824                 : 
     825                 : /* -------------------------------------------------------------------- */
     826                 : /*      Do we have styling information?                                 */
     827                 : /* -------------------------------------------------------------------- */
     828               4 :     OGRStyleTool *poTool = NULL;
     829               4 :     OGRStyleMgr oSM;
     830                 : 
     831               4 :     if( poFeature->GetStyleString() != NULL )
     832                 :     {
     833               0 :         oSM.InitFromFeature( poFeature );
     834                 : 
     835               0 :         if( oSM.GetPartCount() > 0 )
     836               0 :             poTool = oSM.GetPart(0);
     837                 :     }
     838                 : 
     839                 : /* -------------------------------------------------------------------- */
     840                 : /*      Handle a PEN tool to control drawing color and width.           */
     841                 : /*      Perhaps one day also dottedness, etc.                           */
     842                 : /* -------------------------------------------------------------------- */
     843                 : #ifdef notdef
     844                 :     if( poTool && poTool->GetType() == OGRSTCPen )
     845                 :     {
     846                 :         OGRStylePen *poPen = (OGRStylePen *) poTool;
     847                 :         GBool  bDefault;
     848                 : 
     849                 :         if( poPen->Color(bDefault) != NULL && !bDefault )
     850                 :             WriteValue( 62, ColorStringToDXFColor( poPen->Color(bDefault) ) );
     851                 :         
     852                 :         double dfWidthInMM = poPen->Width(bDefault);
     853                 : 
     854                 :         if( !bDefault )
     855                 :             WriteValue( 370, (int) floor(dfWidthInMM * 100 + 0.5) );
     856                 :     }
     857                 : 
     858                 : /* -------------------------------------------------------------------- */
     859                 : /*      Do we have a Linetype for the feature?                          */
     860                 : /* -------------------------------------------------------------------- */
     861                 :     CPLString osLineType = poFeature->GetFieldAsString( "Linetype" );
     862                 : 
     863                 :     if( osLineType.size() > 0 
     864                 :         && (poDS->oHeaderDS.LookupLineType( osLineType ) != NULL 
     865                 :             || oNewLineTypes.count(osLineType) > 0 ) )
     866                 :     {
     867                 :         // Already define -> just reference it.
     868                 :         WriteValue( 6, osLineType );
     869                 :     }
     870                 :     else if( poTool != NULL && poTool->GetType() == OGRSTCPen )
     871                 :     {
     872                 :         CPLString osDefinition = PrepareLineTypeDefinition( poFeature, 
     873                 :                                                             poTool );
     874                 : 
     875                 :         if( osDefinition != "" && osLineType == "" )
     876                 :         {
     877                 :             // Is this definition already created and named?
     878                 :             std::map<CPLString,CPLString>::iterator it;
     879                 : 
     880                 :             for( it = oNewLineTypes.begin();
     881                 :                  it != oNewLineTypes.end();
     882                 :                  it++ )
     883                 :             {
     884                 :                 if( (*it).second == osDefinition )
     885                 :                 {
     886                 :                     osLineType = (*it).first;
     887                 :                     break;
     888                 :                 }
     889                 :             }
     890                 : 
     891                 :             // create an automatic name for it.
     892                 :             if( osLineType == "" )
     893                 :             {
     894                 :                 do 
     895                 :                 { 
     896                 :                     osLineType.Printf( "AutoLineType-%d", nNextAutoID++ );
     897                 :                 }
     898                 :                 while( poDS->oHeaderDS.LookupLineType(osLineType) != NULL );
     899                 :             }
     900                 :         }
     901                 : 
     902                 :         // If it isn't already defined, add it now.
     903                 :         if( osDefinition != "" && oNewLineTypes.count(osLineType) == 0 )
     904                 :         {
     905                 :             oNewLineTypes[osLineType] = osDefinition;
     906                 :             WriteValue( 6, osLineType );
     907                 :         }
     908                 :     }
     909                 :     delete poTool;
     910                 : #endif
     911                 : 
     912                 : /* -------------------------------------------------------------------- */
     913                 : /*      Process the loops (rings).                                      */
     914                 : /* -------------------------------------------------------------------- */
     915               4 :     OGRPolygon *poPoly = (OGRPolygon *) poGeom;
     916                 : 
     917               4 :     WriteValue( 91, poPoly->getNumInteriorRings() + 1 );
     918                 : 
     919               8 :     for( int iRing = -1; iRing < poPoly->getNumInteriorRings(); iRing++ )
     920                 :     {
     921                 :         OGRLinearRing *poLR;
     922                 : 
     923               4 :         if( iRing == -1 )
     924               4 :             poLR = poPoly->getExteriorRing();
     925                 :         else
     926               0 :             poLR = poPoly->getInteriorRing( iRing );
     927                 : 
     928               4 :         WriteValue( 92, 2 ); // Polyline
     929               4 :         WriteValue( 72, 0 ); // has bulge
     930               4 :         WriteValue( 73, 1 ); // is closed
     931               4 :         WriteValue( 93, poLR->getNumPoints() );
     932                 :         
     933              20 :         for( int iVert = 0; iVert < poLR->getNumPoints(); iVert++ )
     934                 :         {
     935              16 :             WriteValue( 10, poLR->getX(iVert) );
     936              16 :             WriteValue( 20, poLR->getY(iVert) );
     937                 :         }
     938                 :     }
     939                 :     
     940               4 :     return OGRERR_NONE;
     941                 : 
     942                 : #ifdef notdef
     943                 : /* -------------------------------------------------------------------- */
     944                 : /*      Alternate unmaintained implementation as a polyline entity.     */
     945                 : /* -------------------------------------------------------------------- */
     946                 :     WriteValue( 0, "POLYLINE" );
     947                 :     WriteCore( poFeature );
     948                 :     WriteValue( 100, "AcDbEntity" );
     949                 :     WriteValue( 100, "AcDbPolyline" );
     950                 :     if( EQUAL( poGeom->getGeometryName(), "LINEARRING" ) )
     951                 :         WriteValue( 70, 1 );
     952                 :     else
     953                 :         WriteValue( 70, 0 );
     954                 :     WriteValue( 66, "1" );
     955                 : 
     956                 :     int iVert;
     957                 : 
     958                 :     for( iVert = 0; iVert < poLS->getNumPoints(); iVert++ )
     959                 :     {
     960                 :         WriteValue( 0, "VERTEX" );
     961                 :         WriteValue( 8, "0" );
     962                 :         WriteValue( 10, poLS->getX(iVert) );
     963                 :         if( !WriteValue( 20, poLS->getY(iVert) ) ) 
     964                 :             return OGRERR_FAILURE;
     965                 : 
     966                 :         if( poLS->getGeometryType() == wkbLineString25D )
     967                 :         {
     968                 :             if( !WriteValue( 30, poLS->getZ(iVert) ) )
     969                 :                 return OGRERR_FAILURE;
     970                 :         }
     971                 :     }
     972                 : 
     973                 :     WriteValue( 0, "SEQEND" );
     974                 :     WriteValue( 8, "0" );
     975                 :     
     976                 :     return OGRERR_NONE;
     977                 : #endif
     978                 : }
     979                 : 
     980                 : /************************************************************************/
     981                 : /*                           CreateFeature()                            */
     982                 : /************************************************************************/
     983                 : 
     984              30 : OGRErr OGRDXFWriterLayer::CreateFeature( OGRFeature *poFeature )
     985                 : 
     986                 : {
     987              30 :     OGRGeometry *poGeom = poFeature->GetGeometryRef();
     988              30 :     OGRwkbGeometryType eGType = wkbNone;
     989                 :     
     990              30 :     if( poGeom != NULL )
     991              30 :         eGType = wkbFlatten(poGeom->getGeometryType());
     992                 : 
     993              30 :     if( eGType == wkbPoint )
     994                 :     {
     995              10 :         const char *pszBlockName = poFeature->GetFieldAsString("BlockName");
     996                 : 
     997                 :         // we don't want to treat as a block ref if we are writing blocks layer
     998              18 :         if( pszBlockName != NULL
     999                 :             && poDS->poBlocksLayer != NULL 
    1000               8 :             && poFeature->GetDefnRef() == poDS->poBlocksLayer->GetLayerDefn())
    1001               0 :             pszBlockName = NULL;
    1002                 : 
    1003                 :         // We don't want to treat as a blocks ref if the block is not defined
    1004              10 :         if( pszBlockName 
    1005                 :             && poDS->oHeaderDS.LookupBlock(pszBlockName) == NULL )
    1006                 :         {
    1007               6 :             if( poDS->poBlocksLayer == NULL
    1008                 :                 || poDS->poBlocksLayer->FindBlock(pszBlockName) == NULL )
    1009               2 :                 pszBlockName = NULL;
    1010                 :         }
    1011                 :                                   
    1012              10 :         if( pszBlockName != NULL )
    1013               8 :             return WriteINSERT( poFeature );
    1014                 :             
    1015               2 :         else if( poFeature->GetStyleString() != NULL
    1016               0 :             && EQUALN(poFeature->GetStyleString(),"LABEL",5) )
    1017               0 :             return WriteTEXT( poFeature );
    1018                 :         else
    1019               2 :             return WritePOINT( poFeature );
    1020                 :     }
    1021              20 :     else if( eGType == wkbLineString 
    1022                 :              || eGType == wkbMultiLineString )
    1023              14 :         return WritePOLYLINE( poFeature );
    1024                 : 
    1025               6 :     else if( eGType == wkbPolygon 
    1026                 :              || eGType == wkbMultiPolygon )
    1027               4 :         return WriteHATCH( poFeature );
    1028                 : 
    1029                 :     // Explode geometry collections into multiple entities.
    1030               2 :     else if( eGType == wkbGeometryCollection )
    1031                 :     {
    1032                 :         OGRGeometryCollection *poGC = (OGRGeometryCollection *)
    1033               2 :             poFeature->StealGeometry();
    1034                 :         int iGeom;
    1035                 : 
    1036               6 :         for( iGeom = 0; iGeom < poGC->getNumGeometries(); iGeom++ )
    1037                 :         {
    1038               4 :             poFeature->SetGeometry( poGC->getGeometryRef(iGeom) );
    1039                 :                                     
    1040               4 :             OGRErr eErr = CreateFeature( poFeature );
    1041                 :             
    1042               4 :             if( eErr != OGRERR_NONE )
    1043               0 :                 return eErr;
    1044                 : 
    1045                 :         }
    1046                 :         
    1047               2 :         poFeature->SetGeometryDirectly( poGC );
    1048               2 :         return OGRERR_NONE;
    1049                 :     }
    1050                 :     else 
    1051                 :     {
    1052                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1053                 :                   "No known way to write feature with geometry '%s'.",
    1054               0 :                   OGRGeometryTypeToName(eGType) );
    1055               0 :         return OGRERR_FAILURE;
    1056                 :     }
    1057                 : }
    1058                 : 
    1059                 : /************************************************************************/
    1060                 : /*                       ColorStringToDXFColor()                        */
    1061                 : /************************************************************************/
    1062                 : 
    1063               6 : int OGRDXFWriterLayer::ColorStringToDXFColor( const char *pszRGB )
    1064                 : 
    1065                 : {
    1066                 : /* -------------------------------------------------------------------- */
    1067                 : /*      Parse the RGB string.                                           */
    1068                 : /* -------------------------------------------------------------------- */
    1069               6 :     if( pszRGB == NULL )
    1070               0 :         return -1;
    1071                 : 
    1072               6 :     int nRed, nGreen, nBlue, nTransparency = 255;
    1073                 : 
    1074                 :     int nCount  = sscanf(pszRGB,"#%2x%2x%2x%2x",&nRed,&nGreen,&nBlue, 
    1075               6 :                          &nTransparency);
    1076                 :    
    1077               6 :     if (nCount < 3 )
    1078               0 :         return -1;
    1079                 : 
    1080                 : /* -------------------------------------------------------------------- */
    1081                 : /*      Find near color in DXF palette.                                 */
    1082                 : /* -------------------------------------------------------------------- */
    1083               6 :     const unsigned char *pabyDXFColors = ACGetColorTable();
    1084                 :     int i;
    1085               6 :     int nMinDist = 768;
    1086               6 :     int nBestColor = -1;
    1087                 : 
    1088            1536 :     for( i = 1; i < 256; i++ )
    1089                 :     {
    1090            1530 :         int nDist = ABS(nRed - pabyDXFColors[i*3+0])
    1091            1530 :             + ABS(nGreen - pabyDXFColors[i*3+1])
    1092            4590 :             + ABS(nBlue  - pabyDXFColors[i*3+2]);
    1093                 : 
    1094            1530 :         if( nDist < nMinDist )
    1095                 :         {
    1096              12 :             nBestColor = i;
    1097              12 :             nMinDist = nDist;
    1098                 :         }
    1099                 :     }
    1100                 :     
    1101               6 :     return nBestColor;
    1102                 : }

Generated by: LCOV version 1.7