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

Last change on this file was 35163, checked in by goatbar, 10 days ago

Cleanup constructors in ogrsf_frmts/ avc bna counchdb csv dgn dods dxf edigeo

  • Use initializer lists
  • Fix formatting

ctors found via https://gist.github.com/schwehr/f16520a0c55d17444da6f0fe68d2a5e8

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