source: trunk/gdal/ogr/ogrsf_frmts/dxf/ogrdxfwriterlayer.cpp

Last change on this file was 35382, checked in by goatbar, 3 weeks ago

Clean dxf.

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