diff --git a/autotest/ogr/data/block-insert-order.dxf b/autotest/ogr/data/block-insert-order.dxf new file mode 100644 index 000000000000..23601b8ca790 --- /dev/null +++ b/autotest/ogr/data/block-insert-order.dxf @@ -0,0 +1,722 @@ + 0 +SECTION + 2 +HEADER + 9 +$ACADVER + 1 +AC1009 + 0 +ENDSEC + 0 +SECTION + 2 +TABLES + 0 +TABLE + 2 +VPORT + 70 + 1 + 0 +VPORT + 2 +*ACTIVE + 70 + 0 + 10 +0.0 + 20 +0.0 + 11 +1.0 + 21 +1.0 + 12 +18.9973091232442 + 22 +8.8158683010775594 + 13 +0.0 + 23 +0.0 + 14 +0.5 + 24 +0.5 + 15 +0.5 + 25 +0.5 + 16 +0.0 + 26 +0.0 + 36 +1.0 + 17 +0.0 + 27 +0.0 + 37 +0.0 + 40 +25.402675667279428 + 41 +2.0256081946222788 + 42 +50.0 + 43 +0.0 + 44 +0.0 + 50 +0.0 + 51 +0.0 + 71 + 0 + 72 + 1000 + 73 + 1 + 74 + 3 + 75 + 1 + 76 + 1 + 77 + 0 + 78 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +LTYPE + 70 + 3 + 0 +LTYPE + 2 +CONTINUOUS + 70 + 0 + 3 +Solid line + 72 + 65 + 73 + 0 + 40 +0.0 + 0 +LTYPE + 2 +DASHED2 + 70 + 0 + 3 +Dashed (.5x) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + 72 + 65 + 73 + 2 + 40 +0.375 + 49 +0.25 + 49 +-0.125 + 0 +ENDTAB + 0 +TABLE + 2 +LAYER + 70 + 1 + 0 +LAYER + 2 +0 + 70 + 0 + 62 + 7 + 6 +CONTINUOUS + 0 +ENDTAB + 0 +TABLE + 2 +STYLE + 70 + 3 + 0 +STYLE + 2 +STANDARD + 70 + 0 + 40 +0.0 + 41 +1.0 + 50 +0.0 + 71 + 0 + 42 +0.2 + 3 +txt + 4 + + 0 +STYLE + 2 +ANNOTATIVE + 70 + 0 + 40 +0.0 + 41 +1.0 + 50 +0.0 + 71 + 0 + 42 +0.2 + 3 +txt + 4 + + 0 +STYLE + 2 +LEGEND + 70 + 0 + 40 +0.0 + 41 +1.0 + 50 +0.0 + 71 + 0 + 42 +0.2 + 3 +txt + 4 + + 0 +ENDTAB + 0 +TABLE + 2 +VIEW + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +UCS + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +DIMSTYLE + 70 + 3 + 0 +DIMSTYLE + 2 +STANDARD + 70 + 0 + 3 + + 4 + + 5 + + 6 + + 7 + + 40 +1.0 + 41 +0.18 + 42 +0.0625 + 43 +0.38 + 44 +0.18 + 45 +0.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 +140 +0.18 +141 +0.09 +142 +0.0 +143 +25.399999999999999 +144 +1.0 +145 +0.0 +146 +1.0 +147 +0.09 + 71 + 0 + 72 + 0 + 73 + 1 + 74 + 1 + 75 + 0 + 76 + 0 + 77 + 0 + 78 + 0 +170 + 0 +171 + 2 +172 + 0 +173 + 0 +174 + 0 +175 + 0 +176 + 0 +177 + 0 +178 + 0 + 0 +DIMSTYLE + 2 +ANNOTATIVE + 70 + 0 + 3 + + 4 + + 5 + + 6 + + 7 + + 40 +0.0 + 41 +0.18 + 42 +0.0625 + 43 +0.38 + 44 +0.18 + 45 +0.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 +140 +0.18 +141 +0.09 +142 +0.0 +143 +25.399999999999999 +144 +1.0 +145 +0.0 +146 +1.0 +147 +0.09 + 71 + 0 + 72 + 0 + 73 + 1 + 74 + 1 + 75 + 0 + 76 + 0 + 77 + 0 + 78 + 0 +170 + 0 +171 + 2 +172 + 0 +173 + 0 +174 + 0 +175 + 0 +176 + 0 +177 + 0 +178 + 0 + 0 +ENDTAB + 0 +ENDSEC + 0 +SECTION + 2 +BLOCKS + 0 +BLOCK + 8 +0 + 2 +$MODEL_SPACE + 70 + 0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +$MODEL_SPACE + 1 + + 0 +ENDBLK + 5 +21 + 8 +0 + 0 +BLOCK + 67 + 1 + 8 +0 + 2 +$PAPER_SPACE + 70 + 0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +$PAPER_SPACE + 1 + + 0 +ENDBLK + 5 +5B + 67 + 1 + 8 +0 + 0 +BLOCK + 8 +0 + 2 +BLOCK1 + 70 + 0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +BLOCK1 + 1 + + 0 +INSERT + 5 +5E8 + 8 +0 + 2 +BLOCK2 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 41 +2.0 + 42 +0.5 + 0 +ENDBLK + 5 +5C4 + 8 +0 + 0 +BLOCK + 8 +0 + 2 +BLOCK2 + 70 + 0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +BLOCK2 + 1 + + 0 +CIRCLE + 5 +5DF + 8 +0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 40 +2.0 + 0 +ENDBLK + 5 +5D8 + 8 +0 + 0 +BLOCK + 8 +0 + 2 +BLOCK3 + 70 + 0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +BLOCK3 + 1 + + 0 +INSERT + 5 +6E8 + 8 +0 + 2 +BLOCK4 + 10 +5.0 + 20 +5.0 + 30 +0.0 + 0 +INSERT + 5 +6E9 + 8 +0 + 2 +BLOCK4 + 10 +5.0 + 20 +5.0 + 30 +0.0 + 41 +0.4 + 42 +1.0 + 43 +1.5 + 50 +40.0 + 0 +INSERT + 5 +6EA + 8 +0 + 2 +BLOCK4 + 10 +5.0 + 20 +5.0 + 30 +0.0 + 41 +0.4 + 42 +1.0 + 43 +1.5 + 50 +40.0 +210 +0.6 +220 +0.565685424949238 +230 +0.565685424949238 + 0 +ENDBLK + 5 +6C4 + 8 +0 + 0 +BLOCK + 8 +0 + 2 +BLOCK4 + 70 + 0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +BLOCK4 + 1 + + 0 +CIRCLE + 5 +6DF + 8 +0 + 10 +1.0 + 20 +2.0 + 30 +3.0 + 40 +2.0 +210 +-0.565685424949238 +220 +0.6 +230 +0.565685424949238 + 0 +ENDBLK + 5 +6D8 + 8 +0 + 0 +ENDSEC + 0 +SECTION + 2 +ENTITIES + 0 +INSERT + 5 +5EA + 8 +0 + 2 +BLOCK1 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 0 +INSERT + 5 +6EA + 8 +0 + 2 +BLOCK3 + 10 +-1.0 + 20 +-2.0 + 30 +-3.0 + 50 +100.0 + 0 +ENDSEC + 0 +EOF diff --git a/autotest/ogr/ogr_dxf.py b/autotest/ogr/ogr_dxf.py index 9897edaf4723..01b90655caca 100755 --- a/autotest/ogr/ogr_dxf.py +++ b/autotest/ogr/ogr_dxf.py @@ -724,6 +724,16 @@ def ogr_dxf_16(): gdaltest.post_reason( 'did not get expected layer name.' ) return 'fail' + # STAR geometry + feat = dxf_layer.GetNextFeature() + + if feat.GetField('Block') != 'STAR': + gdaltest.post_reason( 'Did not get expected block name.' ) + return 'fail' + + if ogrtest.check_feature_geometry( feat, 'MULTILINESTRING ((-0.028147497671066 1.041457413829428 0,0.619244948763444 -1.069604911500494 0),(0.619244948763444 -1.069604911500494 0,-0.957014920816232 0.478507460408116 0),(-0.957014920816232 0.478507460408116 0,1.041457413829428 0.365917469723853 0),(1.041457413829428 0.365917469723853 0,-0.478507460408116 -1.041457413829428 0),(-0.478507460408116 -1.041457413829428 0,-0.056294995342131 1.013309916158363 0))' ): + return 'fail' + # First MTEXT feat = dxf_layer.GetNextFeature() if feat.GetField( 'Text' ) != gdaltest.sample_text: @@ -751,16 +761,6 @@ def ogr_dxf_16(): if ogrtest.check_feature_geometry( feat, 'POINT (0.879677852348995 -0.263903355704699 0)' ): return 'fail' - # STAR geometry - feat = dxf_layer.GetNextFeature() - - if feat.GetField('BlockName') != 'STAR': - gdaltest.post_reason( 'Did not get expected block name.' ) - return 'fail' - - if ogrtest.check_feature_geometry( feat, 'MULTILINESTRING ((-0.028147497671066 1.041457413829428 0,0.619244948763444 -1.069604911500494 0),(0.619244948763444 -1.069604911500494 0,-0.957014920816232 0.478507460408116 0),(-0.957014920816232 0.478507460408116 0,1.041457413829428 0.365917469723853 0),(1.041457413829428 0.365917469723853 0,-0.478507460408116 -1.041457413829428 0),(-0.478507460408116 -1.041457413829428 0,-0.056294995342131 1.013309916158363 0))' ): - return 'fail' - feat = None # cleanup @@ -783,21 +783,21 @@ def ogr_dxf_17(): dst_feat = ogr.Feature( feature_def = blyr.GetLayerDefn() ) dst_feat.SetGeometryDirectly( ogr.CreateGeometryFromWkt( 'GEOMETRYCOLLECTION( LINESTRING(0 0,1 1),LINESTRING(1 0,0 1))' ) ) - dst_feat.SetField( 'BlockName', 'XMark' ) + dst_feat.SetField( 'Block', 'XMark' ) blyr.CreateFeature( dst_feat ) # Block with 2 polygons dst_feat = ogr.Feature( feature_def = blyr.GetLayerDefn() ) dst_feat.SetGeometryDirectly( ogr.CreateGeometryFromWkt( 'GEOMETRYCOLLECTION( POLYGON((10 10,10 20,20 20,20 10,10 10)),POLYGON((10 -10,10 -20,20 -20,20 -10,10 -10)))' ) ) - dst_feat.SetField( 'BlockName', 'Block2' ) + dst_feat.SetField( 'Block', 'Block2' ) blyr.CreateFeature( dst_feat ) # Block with point and line dst_feat = ogr.Feature( feature_def = blyr.GetLayerDefn() ) dst_feat.SetGeometryDirectly( ogr.CreateGeometryFromWkt( 'GEOMETRYCOLLECTION( POINT(1 2),LINESTRING(0 0,1 1))' ) ) - dst_feat.SetField( 'BlockName', 'Block3' ) + dst_feat.SetField( 'Block', 'Block3' ) blyr.CreateFeature( dst_feat ) # Write a block reference feature. @@ -2716,6 +2716,88 @@ def ogr_dxf_41(): return 'success' +############################################################################### +# Test insertion of blocks within blocks (#7106) + +def ogr_dxf_42(): + + # Inlining, merging + ds = ogr.Open('data/block-insert-order.dxf') + lyr = ds.GetLayer(0) + if lyr.GetFeatureCount() != 2: + gdaltest.post_reason( 'Defaults: Expected 2 features, found %d' % lyr.GetFeatureCount() ) + return 'fail' + + # No inlining, merging + gdal.SetConfigOption('DXF_INLINE_BLOCKS', 'FALSE') + ds = ogr.Open('data/block-insert-order.dxf') + gdal.SetConfigOption('DXF_INLINE_BLOCKS', None) + + lyr = ds.GetLayerByName('entities') + if lyr.GetFeatureCount() != 2: + gdaltest.post_reason( 'No inlining: Expected 2 features on entities, found %d' % lyr.GetFeatureCount() ) + return 'fail' + + f = lyr.GetNextFeature() + if ogrtest.check_feature_geometry(f, 'POINT Z (0 0 0)') != 0: + gdaltest.post_reason( 'Wrong geometry for first insertion point' ) + f.DumpReadable() + return 'fail' + + f = lyr.GetNextFeature() + if ogrtest.check_feature_geometry(f, 'POINT Z (-1 -2 -3)') != 0: + gdaltest.post_reason( 'Wrong geometry for second insertion point' ) + f.DumpReadable() + return 'fail' + + lyr = ds.GetLayerByName('blocks') + if lyr.GetFeatureCount() != 6: + gdaltest.post_reason( 'No inlining: Expected 6 feature on blocks, found %d' % lyr.GetFeatureCount() ) + return 'fail' + + f = lyr.GetFeature(3) + if ogrtest.check_feature_geometry(f, 'POINT Z (5 5 0)') != 0: + gdaltest.post_reason( 'Wrong geometry for second insertion of BLOCK4 on BLOCK3' ) + f.DumpReadable() + return 'fail' + + f = lyr.GetFeature(4) + if ogrtest.check_feature_geometry(f, 'POINT Z (-5.48795472456028 1.69774937525433 4.12310562561766)') != 0: + gdaltest.post_reason( 'Wrong geometry for third insertion of BLOCK4 on BLOCK3' ) + f.DumpReadable() + return 'fail' + + if f.GetField('BlockName') != 'BLOCK4': + gdaltest.post_reason( 'Wrong BlockName' ) + return 'fail' + if f.GetField('BlockScale') != [0.4,1.0,1.5]: + gdaltest.post_reason( 'Wrong BlockScale' ) + return 'fail' + if f.GetField('BlockAngle') != 40: + gdaltest.post_reason( 'Wrong BlockAngle' ) + return 'fail' + if f.GetField('BlockOCSNormal') != [0.6,0.565685424949238,0.565685424949238]: + gdaltest.post_reason( 'Wrong BlockOCSNormal' ) + return 'fail' + if f.GetField('BlockOCSCoords') != [5,5,0]: + gdaltest.post_reason( 'Wrong BlockOCSCoords' ) + return 'fail' + if f.GetField('Block') != 'BLOCK3': + gdaltest.post_reason( 'Wrong Block' ) + return 'fail' + + # Inlining, no merging + gdal.SetConfigOption('DXF_MERGE_BLOCK_GEOMETRIES', 'FALSE') + ds = ogr.Open('data/block-insert-order.dxf') + gdal.SetConfigOption('DXF_MERGE_BLOCK_GEOMETRIES', None) + + lyr = ds.GetLayer(0) + if lyr.GetFeatureCount() != 4: + gdaltest.post_reason( 'Merging: Expected 4 features, found %d' % lyr.GetFeatureCount() ) + return 'fail' + + return 'success' + ############################################################################### # cleanup @@ -2770,6 +2852,7 @@ def ogr_dxf_cleanup(): ogr_dxf_39, ogr_dxf_40, ogr_dxf_41, + ogr_dxf_42, ogr_dxf_cleanup ] if __name__ == '__main__': diff --git a/gdal/ogr/ogr_feature.h b/gdal/ogr/ogr_feature.h index f5fb9016fafa..af4df91b801a 100644 --- a/gdal/ogr/ogr_feature.h +++ b/gdal/ogr/ogr_feature.h @@ -297,6 +297,8 @@ class CPL_DLL OGRFeature char *m_pszTmpFieldValue; //! @endcond + bool CopySelfTo( OGRFeature *poNew ); + public: explicit OGRFeature( OGRFeatureDefn * ); virtual ~OGRFeature(); diff --git a/gdal/ogr/ogrfeature.cpp b/gdal/ogr/ogrfeature.cpp index 410cc84a6832..6d242fb8a799 100644 --- a/gdal/ogr/ogrfeature.cpp +++ b/gdal/ogr/ogrfeature.cpp @@ -880,12 +880,61 @@ OGRFeature *OGRFeature::Clone() if( poNew == NULL ) return NULL; + if( !CopySelfTo( poNew ) ) + { + delete poNew; + return NULL; + } + + return poNew; +} + +/************************************************************************/ +/* OGR_F_Clone() */ +/************************************************************************/ + +/** + * \brief Duplicate feature. + * + * The newly created feature is owned by the caller, and will have it's own + * reference to the OGRFeatureDefn. + * + * This function is the same as the C++ method OGRFeature::Clone(). + * + * @param hFeat handle to the feature to clone. + * @return an handle to the new feature, exactly matching this feature. + */ + +OGRFeatureH OGR_F_Clone( OGRFeatureH hFeat ) + +{ + VALIDATE_POINTER1( hFeat, "OGR_F_Clone", NULL ); + + return reinterpret_cast( + reinterpret_cast(hFeat)->Clone()); +} + +/************************************************************************/ +/* CopySelfTo() */ +/************************************************************************/ + +/** +* \brief Copies the innards of this OGRFeature into the supplied object. +* +* This is mainly intended to allow derived classes to implement their own +* Clone functions. +* +* @param poNew The object into which to copy the data of this object. +* @return True if successful, false if the copy failed. +*/ + +bool OGRFeature::CopySelfTo( OGRFeature* poNew ) +{ for( int i = 0; i < poDefn->GetFieldCount(); i++ ) { if( !poNew->SetFieldInternal( i, pauFields + i ) ) { - delete poNew; - return NULL; + return false; } } if( poNew->papoGeometries ) @@ -897,8 +946,7 @@ OGRFeature *OGRFeature::Clone() poNew->papoGeometries[i] = papoGeometries[i]->clone(); if( poNew->papoGeometries[i] == NULL ) { - delete poNew; - return NULL; + return false; } } } @@ -909,8 +957,7 @@ OGRFeature *OGRFeature::Clone() poNew->m_pszStyleString = VSI_STRDUP_VERBOSE(m_pszStyleString); if( poNew->m_pszStyleString == NULL ) { - delete poNew; - return NULL; + return false; } } @@ -921,8 +968,7 @@ OGRFeature *OGRFeature::Clone() poNew->m_pszNativeData = VSI_STRDUP_VERBOSE(m_pszNativeData); if( poNew->m_pszNativeData == NULL ) { - delete poNew; - return NULL; + return false; } } @@ -931,37 +977,11 @@ OGRFeature *OGRFeature::Clone() poNew->m_pszNativeMediaType = VSI_STRDUP_VERBOSE(m_pszNativeMediaType); if( poNew->m_pszNativeMediaType == NULL ) { - delete poNew; - return NULL; + return false; } } - return poNew; -} - -/************************************************************************/ -/* OGR_F_Clone() */ -/************************************************************************/ - -/** - * \brief Duplicate feature. - * - * The newly created feature is owned by the caller, and will have it's own - * reference to the OGRFeatureDefn. - * - * This function is the same as the C++ method OGRFeature::Clone(). - * - * @param hFeat handle to the feature to clone. - * @return an handle to the new feature, exactly matching this feature. - */ - -OGRFeatureH OGR_F_Clone( OGRFeatureH hFeat ) - -{ - VALIDATE_POINTER1( hFeat, "OGR_F_Clone", NULL ); - - return reinterpret_cast( - reinterpret_cast(hFeat)->Clone()); + return true; } /************************************************************************/ diff --git a/gdal/ogr/ogrsf_frmts/dxf/GNUmakefile b/gdal/ogr/ogrsf_frmts/dxf/GNUmakefile index ff505e8c2bcd..5e2719a5bebc 100644 --- a/gdal/ogr/ogrsf_frmts/dxf/GNUmakefile +++ b/gdal/ogr/ogrsf_frmts/dxf/GNUmakefile @@ -6,7 +6,7 @@ OBJ = ogrdxfdriver.o ogrdxfdatasource.o ogrdxflayer.o \ ogrdxfwriterds.o ogrdxfwriterlayer.o intronurbs.o \ ogrdxf_polyline_smooth.o ogrdxfblockslayer.o \ ogrdxfblockswriterlayer.o ogrdxf_hatch.o \ - ogr_autocad_services.o + ogr_autocad_services.o ogrdxf_feature.o CPPFLAGS := -I.. -I../.. $(CPPFLAGS) diff --git a/gdal/ogr/ogrsf_frmts/dxf/drv_dxf.html b/gdal/ogr/ogrsf_frmts/dxf/drv_dxf.html index 644c7fb73890..1f2ca57a4931 100644 --- a/gdal/ogr/ogrsf_frmts/dxf/drv_dxf.html +++ b/gdal/ogr/ogrsf_frmts/dxf/drv_dxf.html @@ -18,31 +18,40 @@

AutoCAD DXF

  • Layer: The name of the DXF layer. The default layer is "0". -
  • SubClasses: Where available, a list of classes to which an element belongs. +
  • SubClasses: Where available, a list of classes to which an entity belongs.
  • ExtendedEntity: Where available, extended entity attributes all appended to form a single text attribute.
  • Linetype: Where available, the line type used for this entity.
  • EntityHandle: The hexadecimal entity handle. A sort of feature id.
  • Text: The text of labels.
-

Supported Elements

+

Supported Entities

-The following element types are supported:

+The following entity types are supported:

    -
  • POINT: Produces a simple point geometry feature. -
  • MTEXT, TEXT: Produces a point feature with LABEL style information. -
  • LINE, POLYLINE, LWPOLYLINE: translated as a LINESTRING. Rounded +
  • POINT: Produces a simple POINT geometry feature. +
  • MTEXT, TEXT: Produces a POINT feature with LABEL style information. +
  • LINE, POLYLINE, LWPOLYLINE: Translated as a LINESTRING. Rounded polylines (those with their vertices' budge attributes set) will be tessellated. Single-vertex polylines are translated to POINT.
  • CIRCLE, ELLIPSE, ARC: Translated as a LINESTRING, tessellating the arc into line segments. -
  • INSERT: An attempt is made to insert the block definition as defined -in the insert. Linework blocks are aggregated into a single feature with -a geometry collection for the geometry. Text blocks are returned as one or -more text features. To avoid merging blocks into a geometry collection the -DXF_MERGE_BLOCK_GEOMETRIES config option may be set to FALSE. -
  • DIMENSION: This element is exploded into a feature with arrows and +
  • INSERT: By default, the block definition referenced by the INSERT will +be inserted as a compound geometry (for example, a MULTILINESTRING for a block +containing many lines, or a GEOMETRYCOLLECTION for block that contains points +and lines). If the block contains TEXT or MTEXT entities, they are not merged +into the compound geometry and are instead returned as separate features.
    +Two configuration options are available to control the behavior of INSERT +entities: +
      +
    • DXF_MERGE_BLOCK_GEOMETRIES: To avoid merging blocks into a compound +geometry the DXF_MERGE_BLOCK_GEOMETRIES config option may be set to FALSE. +Use this option if you need to preserve the styling (such as colors) of +individual linework entities within the block. +
    • DXF_INLINE_BLOCKS: See below. +
    +
  • DIMENSION: This entity is exploded into a feature with arrows and leaders, and a feature with the dimension label.
  • HATCH: Line and arc boundaries are collected as a polygon geometry, but no effort is currently made to represent the fill style of HATCH entities. @@ -54,7 +63,7 @@

    Supported Elements

A reasonable attempt is made to preserve line color, line width, text size -and orientation via OGR feature styling information when translating elements. +and orientation via OGR feature styling information when translating entities. Currently no effort is made to preserve fill styles or complex line style attributes.

@@ -72,16 +81,20 @@

DXF_INLINE_BLOCKS

as described here.
    -
  • A new layer will be available called blocks. It will contain one or +
  • A new layer will be available called "blocks". It will contain one or more features for each BLOCK defined in the file. In addition to the usual -attributes, they will also have a BlockName attribute indicate what block -they are part of. +attributes, they will also have a Block attribute indicating what block +they are part of. (Note, in GDAL 2.2.x and earlier this attribute was called +BlockName.)
  • The entities layer will have new attributes BlockName, BlockScale, -and BlockAngle. +BlockAngle, BlockOCSNormal and BlockOCSCoords. BlockScale gives the X, Y, +and Z scale factors; BlockOCSNormal contains the unit normal vector of the +object coordinate system (OCS) of the INSERT entity; BlockOCSCoords gives +the OCS coordinates of the insertion point.
  • INSERT entities will populate these new fields with the corresponding information (they are null for all other entities).
  • INSERT entities will not have block geometry inlined - instead they will -have a point geometry for the insertion point. +have a POINT geometry for the insertion point.
The intention is that with DXF_INLINE_BLOCKS disabled, the block references @@ -148,21 +161,26 @@

Block References

It is possible to export a "blocks" layer to DXF in addition to the "entities" layer in order to produce actual DXF BLOCKs definitions in the output file. It is also possible to write INSERT entities if -a block name is provided for an entity. To make this work the follow -conditions apply. +a block name is provided for an entity. To make this work the following +conditions apply:
  • A "blocks" layer may be created, and it must be created before the entities layer. -
  • The entities in the blocks layer should have the BlockName field -populated. +
  • The entities in the blocks layer should have the Block field +populated. (Note, in GDAL 2.2.x and earlier this attribute was called +BlockName.)
  • Objects to be written as INSERTs in the entities layer should have a -POINT geometry, and the BlockName field set. +POINT geometry, and the BlockName field set. You may also set BlockAngle, +BlockScale, BlockOCSNormal and BlockOCSCoords (see above under DXF_INLINE_BLOCKS +for details). If BlockOCSCoords is set to a list of 3 real numbers, it is used +as the location of the block; in this situation the position of the POINT +geometry is ignored.
  • If a block (name) is already defined in the template header, that will be used regardless of whether a new definition was provided in the blocks layer.
-The intention is that a simple translation from DXF to with DXF_INLINE_BLOCKS +The intention is that a simple translation from DXF to DXF with DXF_INLINE_BLOCKS set to FALSE will approximately reproduce the original blocks and keep INSERT entities as INSERT entities rather than exploding them.

diff --git a/gdal/ogr/ogrsf_frmts/dxf/makefile.vc b/gdal/ogr/ogrsf_frmts/dxf/makefile.vc index 4ea75c6cd5de..953b4738cfe3 100644 --- a/gdal/ogr/ogrsf_frmts/dxf/makefile.vc +++ b/gdal/ogr/ogrsf_frmts/dxf/makefile.vc @@ -3,7 +3,7 @@ OBJ = ogrdxfdriver.obj ogrdxfdatasource.obj ogrdxflayer.obj \ ogrdxfwriterds.obj ogrdxfwriterlayer.obj intronurbs.obj \ ogrdxf_polyline_smooth.obj ogrdxfblockslayer.obj \ ogrdxfblockswriterlayer.obj ogrdxf_hatch.obj \ - ogr_autocad_services.obj + ogr_autocad_services.obj ogrdxf_feature.obj EXTRAFLAGS = -I.. -I..\.. diff --git a/gdal/ogr/ogrsf_frmts/dxf/ogr_dxf.h b/gdal/ogr/ogrsf_frmts/dxf/ogr_dxf.h index f1cd9c27c8aa..bd214c3dee4c 100644 --- a/gdal/ogr/ogrsf_frmts/dxf/ogr_dxf.h +++ b/gdal/ogr/ogrsf_frmts/dxf/ogr_dxf.h @@ -40,6 +40,7 @@ #include class OGRDXFDataSource; +class OGRDXFFeature; /************************************************************************/ /* DXFBlockDefinition */ @@ -50,15 +51,14 @@ class OGRDXFDataSource; class DXFBlockDefinition { public: - DXFBlockDefinition() : poGeometry(NULL) {} + DXFBlockDefinition() {} ~DXFBlockDefinition(); - OGRGeometry *poGeometry; - std::vector apoFeatures; + std::vector apoFeatures; }; /************************************************************************/ -/* OGRDXFBlocksLayer() */ +/* OGRDXFBlocksLayer */ /************************************************************************/ class OGRDXFBlocksLayer : public OGRLayer @@ -68,9 +68,11 @@ class OGRDXFBlocksLayer : public OGRLayer OGRFeatureDefn *poFeatureDefn; GIntBig iNextFID; - size_t iNextSubFeature; std::map::iterator oIt; + CPLString osBlockName; + + std::queue apoPendingFeatures; public: explicit OGRDXFBlocksLayer( OGRDXFDataSource *poDS ); @@ -83,7 +85,7 @@ class OGRDXFBlocksLayer : public OGRLayer int TestCapability( const char * ) override; - OGRFeature * GetNextUnfilteredFeature(); + OGRDXFFeature * GetNextUnfilteredFeature(); }; /************************************************************************/ @@ -161,11 +163,61 @@ class OGRDXFInsertTransformer : public OGRCoordinateTransformation } }; +/************************************************************************/ +/* OGRDXFFeature */ +/* */ +/* Extends OGRFeature with some DXF-specific members. */ +/************************************************************************/ +class OGRDXFFeature : public OGRFeature +{ + friend class OGRDXFLayer; + + protected: + bool bIsBlockReference; + CPLString osBlockName; + double dfBlockAngle; + double adfBlockScale[3]; + double adfBlockOCS[3]; + + // Used for INSERT entities when DXF_INLINE_BLOCKS is false, to store + // the OCS insertion point + double adfOriginalCoords[3]; + + public: + explicit OGRDXFFeature( OGRFeatureDefn * poFeatureDefn ); + + OGRDXFFeature *CloneDXFFeature(); + + bool IsBlockReference() const { return bIsBlockReference; } + CPLString GetBlockName() const { return osBlockName; } + double GetBlockAngle() const { return dfBlockAngle; } + void GetBlockScale( double adfOut[3] ) const + { + adfOut[0] = adfBlockScale[0]; + adfOut[1] = adfBlockScale[1]; + adfOut[2] = adfBlockScale[2]; + } + void GetBlockOCS( double adfOut[3] ) const + { + adfOut[0] = adfBlockOCS[0]; + adfOut[1] = adfBlockOCS[1]; + adfOut[2] = adfBlockOCS[2]; + } + void GetInsertOCSCoords( double adfOut[3] ) const + { + adfOut[0] = adfOriginalCoords[0]; + adfOut[1] = adfOriginalCoords[1]; + adfOut[2] = adfOriginalCoords[2]; + } +}; + /************************************************************************/ /* OGRDXFLayer */ /************************************************************************/ class OGRDXFLayer : public OGRLayer { + friend class OGRDXFBlocksLayer; + OGRDXFDataSource *poDS; OGRFeatureDefn *poFeatureDefn; @@ -173,7 +225,7 @@ class OGRDXFLayer : public OGRLayer std::set oIgnoredEntities; - std::queue apoPendingFeatures; + std::queue apoPendingFeatures; void ClearPendingFeatures(); std::map oStyleProperties; @@ -182,27 +234,35 @@ class OGRDXFLayer : public OGRLayer int nCode, char *pszValue ); void PrepareLineStyle( OGRFeature *poFeature ); void ApplyOCSTransformer( OGRGeometry * ); - - OGRFeature * TranslatePOINT(); - OGRFeature * TranslateLINE(); - OGRFeature * TranslatePOLYLINE(); - OGRFeature * TranslateLWPOLYLINE(); - OGRFeature * TranslateCIRCLE(); - OGRFeature * TranslateELLIPSE(); - OGRFeature * TranslateARC(); - OGRFeature * TranslateSPLINE(); - OGRFeature * Translate3DFACE(); - OGRFeature * TranslateINSERT(); - OGRFeature * TranslateMTEXT(); - OGRFeature * TranslateTEXT(); - OGRFeature * TranslateDIMENSION(); - OGRFeature * TranslateHATCH(); - OGRFeature * TranslateSOLID(); - - OGRFeature * InsertBlock( const CPLString& osBlockName, - OGRDXFInsertTransformer oTransformer, - OGRFeature* const poFeature, - const bool bInline ); + static void ApplyOCSTransformer( OGRGeometry *, double[3] ); + + OGRDXFFeature * TranslatePOINT(); + OGRDXFFeature * TranslateLINE(); + OGRDXFFeature * TranslatePOLYLINE(); + OGRDXFFeature * TranslateLWPOLYLINE(); + OGRDXFFeature * TranslateCIRCLE(); + OGRDXFFeature * TranslateELLIPSE(); + OGRDXFFeature * TranslateARC(); + OGRDXFFeature * TranslateSPLINE(); + OGRDXFFeature * Translate3DFACE(); + OGRDXFFeature * TranslateINSERT(); + OGRDXFFeature * TranslateMTEXT(); + OGRDXFFeature * TranslateTEXT(); + OGRDXFFeature * TranslateDIMENSION(); + OGRDXFFeature * TranslateHATCH(); + OGRDXFFeature * TranslateSOLID(); + + static OGRGeometry *SimplifyBlockGeometry( OGRGeometryCollection * ); + OGRDXFFeature * InsertBlockInline( const CPLString& osBlockName, + OGRDXFInsertTransformer oTransformer, + double adfOCS[3], + OGRDXFFeature* const poFeature, + std::queue& apoExtraFeatures, + const bool bInlineNestedBlocks, + const bool bMergeGeometry ); + OGRDXFFeature * InsertBlockReference( const CPLString& osBlockName, + const OGRDXFInsertTransformer& oTransformer, + OGRDXFFeature* const poFeature ); void FormatDimension( CPLString &osText, double dfValue ); OGRErr CollectBoundaryPath( OGRGeometryCollection *poGC, const double dfElevation ); @@ -223,7 +283,7 @@ class OGRDXFLayer : public OGRLayer int TestCapability( const char * ) override; - OGRFeature * GetNextUnfilteredFeature(); + OGRDXFFeature * GetNextUnfilteredFeature(); }; /************************************************************************/ @@ -289,6 +349,7 @@ class OGRDXFDataSource : public OGRDataSource std::map oLineTypeTable; bool bInlineBlocks; + bool bMergeBlockGeometries; OGRDXFReader oReader; @@ -307,12 +368,12 @@ class OGRDXFDataSource : public OGRDataSource // The following is only used by OGRDXFLayer - bool InlineBlocks() { return bInlineBlocks; } + bool InlineBlocks() const { return bInlineBlocks; } + bool ShouldMergeBlockGeometries() const { return bMergeBlockGeometries; } void AddStandardFields( OGRFeatureDefn *poDef ); // Implemented in ogrdxf_blockmap.cpp bool ReadBlocksSection(); - OGRGeometry *SimplifyBlockGeometry( OGRGeometryCollection * ); DXFBlockDefinition *LookupBlock( const char *pszName ); std::map &GetBlockMap() { return oBlockMap; } diff --git a/gdal/ogr/ogrsf_frmts/dxf/ogrdxf_blockmap.cpp b/gdal/ogr/ogrsf_frmts/dxf/ogrdxf_blockmap.cpp index d4e7e013342d..e32f4710321d 100644 --- a/gdal/ogr/ogrsf_frmts/dxf/ogrdxf_blockmap.cpp +++ b/gdal/ogr/ogrsf_frmts/dxf/ogrdxf_blockmap.cpp @@ -41,10 +41,13 @@ CPL_CVSID("$Id$") bool OGRDXFDataSource::ReadBlocksSection() { + // Force inlining of blocks to false, for when OGRDXFLayer processes + // INSERT entities + const bool bOldInlineBlocks = bInlineBlocks; + bInlineBlocks = false; + OGRDXFLayer *poReaderLayer = static_cast( GetLayerByName( "Entities" )); - const bool bMergeBlockGeometries = CPLTestBool( - CPLGetConfigOption( "DXF_MERGE_BLOCK_GEOMETRIES", "TRUE" ) ); iEntitiesSectionOffset = oReader.iSrcBufferFileOffset + oReader.iSrcBufferOffset; @@ -70,6 +73,7 @@ bool OGRDXFDataSource::ReadBlocksSection() } if( nCode < 0 ) { + bInlineBlocks = bOldInlineBlocks; DXF_READER_ERROR(); return false; } @@ -82,123 +86,31 @@ bool OGRDXFDataSource::ReadBlocksSection() if( oBlockMap.find(osBlockName) != oBlockMap.end() ) { + bInlineBlocks = bOldInlineBlocks; DXF_READER_ERROR(); return false; } // Now we will process entities till we run out at the ENDBLK code. - // we aggregate the geometries of the features into a multi-geometry, - // but throw away other stuff attached to the features. - - OGRFeature *poFeature = NULL; - OGRGeometryCollection *poColl = new OGRGeometryCollection(); - std::vector apoFeatures; + OGRDXFFeature *poFeature = NULL; while( (poFeature = poReaderLayer->GetNextUnfilteredFeature()) != NULL ) - { - if( (poFeature->GetStyleString() != NULL - && strstr(poFeature->GetStyleString(),"LABEL") != NULL) - || !bMergeBlockGeometries ) - { - apoFeatures.push_back( poFeature ); - } - else - { - OGRGeometry* poSubGeom = poFeature->StealGeometry(); - if( poSubGeom ) - poColl->addGeometryDirectly( poSubGeom ); - delete poFeature; - } - } - - if( poColl->getNumGeometries() == 0 ) - delete poColl; - else - oBlockMap[osBlockName].poGeometry = SimplifyBlockGeometry(poColl); - - if( !apoFeatures.empty() ) - oBlockMap[osBlockName].apoFeatures = apoFeatures; + oBlockMap[osBlockName].apoFeatures.push_back( poFeature ); } if( nCode < 0 ) { + bInlineBlocks = bOldInlineBlocks; DXF_READER_ERROR(); return false; } CPLDebug( "DXF", "Read %d blocks with meaningful geometry.", (int) oBlockMap.size() ); - return true; -} - -/************************************************************************/ -/* SimplifyBlockGeometry() */ -/************************************************************************/ - -OGRGeometry *OGRDXFDataSource::SimplifyBlockGeometry( - OGRGeometryCollection *poCollection ) - -{ -/* -------------------------------------------------------------------- */ -/* If there is only one geometry in the collection, just return */ -/* it. */ -/* -------------------------------------------------------------------- */ - if( poCollection->getNumGeometries() == 1 ) - { - OGRGeometry *poReturn = poCollection->getGeometryRef(0); - poCollection->removeGeometry(0, FALSE); - delete poCollection; - return poReturn; - } -/* -------------------------------------------------------------------- */ -/* Convert to polygon, multipolygon, multilinestring or multipoint */ -/* -------------------------------------------------------------------- */ + // Restore old inline blocks setting + bInlineBlocks = bOldInlineBlocks; - OGRwkbGeometryType eType = - wkbFlatten(poCollection->getGeometryRef(0)->getGeometryType()); - int i; - for(i=1;igetNumGeometries();i++) - { - if (wkbFlatten(poCollection->getGeometryRef(i)->getGeometryType()) - != eType) - { - eType = wkbUnknown; - break; - } - } - if (eType == wkbPoint || eType == wkbLineString) - { - OGRGeometryCollection* poNewColl; - if (eType == wkbPoint) - poNewColl = new OGRMultiPoint(); - else - poNewColl = new OGRMultiLineString(); - while(poCollection->getNumGeometries() > 0) - { - OGRGeometry *poGeom = poCollection->getGeometryRef(0); - poCollection->removeGeometry(0,FALSE); - poNewColl->addGeometryDirectly(poGeom); - } - delete poCollection; - return poNewColl; - } - else if (eType == wkbPolygon) - { - std::vector aosPolygons; - while(poCollection->getNumGeometries() > 0) - { - OGRGeometry *poGeom = poCollection->getGeometryRef(0); - poCollection->removeGeometry(0,FALSE); - aosPolygons.push_back(poGeom); - } - delete poCollection; - int bIsValidGeometry; - return OGRGeometryFactory::organizePolygons( - &aosPolygons[0], (int)aosPolygons.size(), - &bIsValidGeometry, NULL); - } - - return poCollection; + return true; } /************************************************************************/ @@ -228,10 +140,7 @@ DXFBlockDefinition *OGRDXFDataSource::LookupBlock( const char *pszName ) /************************************************************************/ DXFBlockDefinition::~DXFBlockDefinition() - { - delete poGeometry; - while( !apoFeatures.empty() ) { delete apoFeatures.back(); diff --git a/gdal/ogr/ogrsf_frmts/dxf/ogrdxf_dimension.cpp b/gdal/ogr/ogrsf_frmts/dxf/ogrdxf_dimension.cpp index b2cb31cab45c..3c69d1f62487 100644 --- a/gdal/ogr/ogrsf_frmts/dxf/ogrdxf_dimension.cpp +++ b/gdal/ogr/ogrsf_frmts/dxf/ogrdxf_dimension.cpp @@ -37,13 +37,13 @@ CPL_CVSID("$Id$") /* TranslateDIMENSION() */ /************************************************************************/ -OGRFeature *OGRDXFLayer::TranslateDIMENSION() +OGRDXFFeature *OGRDXFLayer::TranslateDIMENSION() { char szLineBuf[257]; int nCode = 0; // int nDimType = 0; - OGRFeature *poFeature = new OGRFeature( poFeatureDefn ); + OGRDXFFeature *poFeature = new OGRDXFFeature( poFeatureDefn ); double dfArrowX1 = 0.0; double dfArrowY1 = 0.0; // double dfArrowZ1 = 0.0; @@ -318,7 +318,7 @@ the approach is as above in all these cases. if( osText == " " ) return poFeature; - OGRFeature *poLabelFeature = poFeature->Clone(); + OGRDXFFeature *poLabelFeature = poFeature->CloneDXFFeature(); poLabelFeature->SetGeometryDirectly( new OGRPoint( dfTextX, dfTextY ) ); diff --git a/gdal/ogr/ogrsf_frmts/dxf/ogrdxf_feature.cpp b/gdal/ogr/ogrsf_frmts/dxf/ogrdxf_feature.cpp new file mode 100644 index 000000000000..c8f44c2e067c --- /dev/null +++ b/gdal/ogr/ogrsf_frmts/dxf/ogrdxf_feature.cpp @@ -0,0 +1,83 @@ +/****************************************************************************** + * + * Project: DXF Translator + * Purpose: Provides additional functionality for DXF features + * Author: Alan Thomas, alant@outlook.com.au + * + ****************************************************************************** + * Copyright (c) 2017, Alan Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "ogr_dxf.h" +#include "cpl_string.h" + +CPL_CVSID("$Id$") + +/************************************************************************/ +/* OGRDXFFeature() */ +/************************************************************************/ + +OGRDXFFeature::OGRDXFFeature( OGRFeatureDefn * poFeatureDefn ): + OGRFeature( poFeatureDefn ), + bIsBlockReference(false), + dfBlockAngle(0.0) +{ + adfBlockScale[0] = adfBlockScale[1] = adfBlockScale[2] = 1.0; + + adfBlockOCS[0] = adfBlockOCS[1] = 0.0; + adfBlockOCS[2] = 1.0; + + adfOriginalCoords[0] = adfOriginalCoords[1] = adfOriginalCoords[2] = 0.0; +} + +/************************************************************************/ +/* CloneDXFFeature() */ +/* */ +/* Replacement for OGRFeature::Clone() for DXF features. */ +/************************************************************************/ + +OGRDXFFeature *OGRDXFFeature::CloneDXFFeature() +{ + OGRDXFFeature *poNew = new OGRDXFFeature( GetDefnRef() ); + if( poNew == NULL ) + return NULL; + + if( !CopySelfTo( poNew ) ) + { + delete poNew; + return NULL; + } + + poNew->bIsBlockReference = bIsBlockReference; + poNew->osBlockName = osBlockName; + poNew->dfBlockAngle = dfBlockAngle; + poNew->adfBlockScale[0] = adfBlockScale[0]; + poNew->adfBlockScale[1] = adfBlockScale[1]; + poNew->adfBlockScale[2] = adfBlockScale[2]; + poNew->adfBlockOCS[0] = adfBlockOCS[0]; + poNew->adfBlockOCS[1] = adfBlockOCS[1]; + poNew->adfBlockOCS[2] = adfBlockOCS[2]; + poNew->adfOriginalCoords[0] = adfOriginalCoords[0]; + poNew->adfOriginalCoords[1] = adfOriginalCoords[1]; + poNew->adfOriginalCoords[2] = adfOriginalCoords[2]; + + return poNew; +} diff --git a/gdal/ogr/ogrsf_frmts/dxf/ogrdxf_hatch.cpp b/gdal/ogr/ogrsf_frmts/dxf/ogrdxf_hatch.cpp index 178d8049a3fd..673056a0d253 100644 --- a/gdal/ogr/ogrsf_frmts/dxf/ogrdxf_hatch.cpp +++ b/gdal/ogr/ogrsf_frmts/dxf/ogrdxf_hatch.cpp @@ -45,12 +45,12 @@ CPL_CVSID("$Id$") /* preserve the actual details of the hatching. */ /************************************************************************/ -OGRFeature *OGRDXFLayer::TranslateHATCH() +OGRDXFFeature *OGRDXFLayer::TranslateHATCH() { char szLineBuf[257]; int nCode = 0; - OGRFeature *poFeature = new OGRFeature( poFeatureDefn ); + OGRDXFFeature *poFeature = new OGRDXFFeature( poFeatureDefn ); CPLString osHatchPattern; double dfElevation = 0.0; // Z value to be used for EVERY point diff --git a/gdal/ogr/ogrsf_frmts/dxf/ogrdxfblockslayer.cpp b/gdal/ogr/ogrsf_frmts/dxf/ogrdxfblockslayer.cpp index 7b66494a638d..fb324308ff4f 100644 --- a/gdal/ogr/ogrsf_frmts/dxf/ogrdxfblockslayer.cpp +++ b/gdal/ogr/ogrsf_frmts/dxf/ogrdxfblockslayer.cpp @@ -38,8 +38,7 @@ CPL_CVSID("$Id$") OGRDXFBlocksLayer::OGRDXFBlocksLayer( OGRDXFDataSource *poDSIn ) : poDS(poDSIn), poFeatureDefn(new OGRFeatureDefn( "blocks" )), - iNextFID(0), - iNextSubFeature(0) + iNextFID(0) { ResetReading(); @@ -64,6 +63,12 @@ OGRDXFBlocksLayer::~OGRDXFBlocksLayer() if( poFeatureDefn ) poFeatureDefn->Release(); + + while (!apoPendingFeatures.empty()) + { + delete apoPendingFeatures.front(); + apoPendingFeatures.pop(); + } } /************************************************************************/ @@ -74,7 +79,11 @@ void OGRDXFBlocksLayer::ResetReading() { iNextFID = 0; - iNextSubFeature = 0; + while (!apoPendingFeatures.empty()) + { + delete apoPendingFeatures.front(); + apoPendingFeatures.pop(); + } oIt = poDS->GetBlockMap().begin(); } @@ -82,69 +91,64 @@ void OGRDXFBlocksLayer::ResetReading() /* GetNextUnfilteredFeature() */ /************************************************************************/ -OGRFeature *OGRDXFBlocksLayer::GetNextUnfilteredFeature() +OGRDXFFeature *OGRDXFBlocksLayer::GetNextUnfilteredFeature() { - OGRFeature *poFeature = NULL; - + OGRDXFFeature *poFeature = NULL; + /* -------------------------------------------------------------------- */ -/* Are we out of features? */ +/* If we have pending features, return one of them. */ /* -------------------------------------------------------------------- */ - if( oIt == poDS->GetBlockMap().end() ) - return NULL; - -/* -------------------------------------------------------------------- */ -/* Are we done reading the current blocks features? */ -/* -------------------------------------------------------------------- */ - DXFBlockDefinition *psBlock = &(oIt->second); - size_t nSubFeatureCount = psBlock->apoFeatures.size(); - - if( psBlock->poGeometry != NULL ) - nSubFeatureCount++; - - if( iNextSubFeature >= nSubFeatureCount ) + if( !apoPendingFeatures.empty() ) { - ++oIt; - - iNextSubFeature = 0; + poFeature = apoPendingFeatures.front(); + apoPendingFeatures.pop(); - if( oIt == poDS->GetBlockMap().end() ) - return NULL; - - psBlock = &(oIt->second); + poFeature->SetFID( iNextFID++ ); + poFeature->SetField( "Block", osBlockName.c_str() ); + m_nFeaturesRead++; + return poFeature; } /* -------------------------------------------------------------------- */ -/* Is this a geometry based block? */ +/* Are we out of features? */ /* -------------------------------------------------------------------- */ - if( psBlock->poGeometry != NULL - && iNextSubFeature == psBlock->apoFeatures.size() ) + while( oIt != poDS->GetBlockMap().end() ) { - poFeature = new OGRFeature( poFeatureDefn ); - poFeature->SetGeometry( psBlock->poGeometry ); - iNextSubFeature++; - } + poFeature = new OGRDXFFeature( poFeatureDefn ); -/* -------------------------------------------------------------------- */ -/* Otherwise duplicate the next sub-feature. */ -/* -------------------------------------------------------------------- */ - else - { - poFeature = new OGRFeature( poFeatureDefn ); - poFeature->SetFrom( psBlock->apoFeatures[iNextSubFeature] ); - iNextSubFeature++; - } + // Let's insert this block at the origin with no rotation and scale. + OGRDXFLayer oTempLayer(poDS); + poFeature = oTempLayer.InsertBlockInline( oIt->first, + OGRDXFInsertTransformer(), NULL, + poFeature, apoPendingFeatures, + false, poDS->ShouldMergeBlockGeometries() ); -/* -------------------------------------------------------------------- */ -/* Set FID and block name. */ -/* -------------------------------------------------------------------- */ - poFeature->SetFID( iNextFID++ ); + osBlockName = oIt->first; + oIt++; - poFeature->SetField( "BlockName", oIt->first.c_str() ); + if( !poFeature ) + { + if ( apoPendingFeatures.empty() ) + { + // This block must have been empty. Move onto the next block + continue; + } + else + { + poFeature = apoPendingFeatures.front(); + apoPendingFeatures.pop(); + } + } - m_nFeaturesRead++; + poFeature->SetFID( iNextFID++ ); + poFeature->SetField( "Block", osBlockName.c_str() ); + m_nFeaturesRead++; + return poFeature; + } - return poFeature; + // No more blocks left. + return NULL; } /************************************************************************/ diff --git a/gdal/ogr/ogrsf_frmts/dxf/ogrdxfblockswriterlayer.cpp b/gdal/ogr/ogrsf_frmts/dxf/ogrdxfblockswriterlayer.cpp index 7082f69d63a1..4d27fe4edf36 100644 --- a/gdal/ogr/ogrsf_frmts/dxf/ogrdxfblockswriterlayer.cpp +++ b/gdal/ogr/ogrsf_frmts/dxf/ogrdxfblockswriterlayer.cpp @@ -62,7 +62,22 @@ OGRDXFBlocksWriterLayer::OGRDXFBlocksWriterLayer( OGRFieldDefn oTextField( "Text", OFTString ); poFeatureDefn->AddFieldDefn( &oTextField ); - OGRFieldDefn oBlockField( "BlockName", OFTString ); + OGRFieldDefn oBlockNameField( "BlockName", OFTString ); + poFeatureDefn->AddFieldDefn( &oBlockNameField ); + + OGRFieldDefn oScaleField( "BlockScale", OFTRealList ); + poFeatureDefn->AddFieldDefn( &oScaleField ); + + OGRFieldDefn oBlockAngleField( "BlockAngle", OFTReal ); + poFeatureDefn->AddFieldDefn( &oBlockAngleField ); + + OGRFieldDefn oBlockOCSNormalField( "BlockOCSNormal", OFTRealList ); + poFeatureDefn->AddFieldDefn( &oBlockOCSNormalField ); + + OGRFieldDefn oBlockOCSCoordsField( "BlockOCSCoords", OFTRealList ); + poFeatureDefn->AddFieldDefn( &oBlockOCSCoordsField ); + + OGRFieldDefn oBlockField( "Block", OFTString ); poFeatureDefn->AddFieldDefn( &oBlockField ); } @@ -135,7 +150,7 @@ OGRFeature *OGRDXFBlocksWriterLayer::FindBlock( const char *pszBlockName ) { for( size_t i=0; i < apoBlocks.size(); i++ ) { - const char *pszThisName = apoBlocks[i]->GetFieldAsString("BlockName"); + const char *pszThisName = apoBlocks[i]->GetFieldAsString("Block"); if( pszThisName != NULL && strcmp(pszBlockName,pszThisName) == 0 ) return apoBlocks[i]; diff --git a/gdal/ogr/ogrsf_frmts/dxf/ogrdxfdatasource.cpp b/gdal/ogr/ogrsf_frmts/dxf/ogrdxfdatasource.cpp index 4c86a3544ce0..fd3d2e7e05a7 100644 --- a/gdal/ogr/ogrsf_frmts/dxf/ogrdxfdatasource.cpp +++ b/gdal/ogr/ogrsf_frmts/dxf/ogrdxfdatasource.cpp @@ -40,7 +40,8 @@ CPL_CVSID("$Id$") OGRDXFDataSource::OGRDXFDataSource() : fp(NULL), iEntitiesSectionOffset(0), - bInlineBlocks(false) + bInlineBlocks(false), + bMergeBlockGeometries(false) {} /************************************************************************/ @@ -104,6 +105,8 @@ int OGRDXFDataSource::Open( const char * pszFilename, int bHeaderOnly ) bInlineBlocks = CPLTestBool( CPLGetConfigOption( "DXF_INLINE_BLOCKS", "TRUE" ) ); + bMergeBlockGeometries = CPLTestBool( + CPLGetConfigOption( "DXF_MERGE_BLOCK_GEOMETRIES", "TRUE" ) ); if( CPLTestBool( CPLGetConfigOption( "DXF_HEADER_ONLY", "FALSE" ) ) ) @@ -654,5 +657,24 @@ void OGRDXFDataSource::AddStandardFields( OGRFeatureDefn *poFeatureDefn ) { OGRFieldDefn oBlockNameField( "BlockName", OFTString ); poFeatureDefn->AddFieldDefn( &oBlockNameField ); + + OGRFieldDefn oScaleField( "BlockScale", OFTRealList ); + poFeatureDefn->AddFieldDefn( &oScaleField ); + + OGRFieldDefn oBlockAngleField( "BlockAngle", OFTReal ); + poFeatureDefn->AddFieldDefn( &oBlockAngleField ); + + OGRFieldDefn oBlockOCSNormalField( "BlockOCSNormal", OFTRealList ); + poFeatureDefn->AddFieldDefn( &oBlockOCSNormalField ); + + OGRFieldDefn oBlockOCSCoordsField( "BlockOCSCoords", OFTRealList ); + poFeatureDefn->AddFieldDefn( &oBlockOCSCoordsField ); + + // This field holds the name of the block on which the entity lies. + // The BlockName field was previously used for this purpose; this + // was changed because of the ambiguity with the BlockName field + // used by INSERT entities. + OGRFieldDefn oBlockField( "Block", OFTString ); + poFeatureDefn->AddFieldDefn( &oBlockField ); } } diff --git a/gdal/ogr/ogrsf_frmts/dxf/ogrdxflayer.cpp b/gdal/ogr/ogrsf_frmts/dxf/ogrdxflayer.cpp index 178af676be4c..b95aedc09f3c 100644 --- a/gdal/ogr/ogrsf_frmts/dxf/ogrdxflayer.cpp +++ b/gdal/ogr/ogrsf_frmts/dxf/ogrdxflayer.cpp @@ -51,15 +51,6 @@ OGRDXFLayer::OGRDXFLayer( OGRDXFDataSource *poDSIn ) : poDS->AddStandardFields( poFeatureDefn ); - if( !poDS->InlineBlocks() ) - { - OGRFieldDefn oScaleField( "BlockScale", OFTRealList ); - poFeatureDefn->AddFieldDefn( &oScaleField ); - - OGRFieldDefn oBlockAngleField( "BlockAngle", OFTReal ); - poFeatureDefn->AddFieldDefn( &oBlockAngleField ); - } - SetDescription( poFeatureDefn->GetName() ); } @@ -433,15 +424,29 @@ void OGRDXFLayer::ApplyOCSTransformer( OGRGeometry *poGeometry ) || oStyleProperties.count("230_N.dZ") == 0 ) return; - if( poGeometry == NULL ) - return; - double adfN[3]; adfN[0] = CPLAtof(oStyleProperties["210_N.dX"]); adfN[1] = CPLAtof(oStyleProperties["220_N.dY"]); adfN[2] = CPLAtof(oStyleProperties["230_N.dZ"]); + ApplyOCSTransformer( poGeometry, adfN ); +} + +/************************************************************************/ +/* ApplyOCSTransformer() */ +/* */ +/* Apply a transformation from the given OCS to world */ +/* coordinates. */ +/************************************************************************/ + +void OGRDXFLayer::ApplyOCSTransformer( OGRGeometry *poGeometry, + double adfN[3] ) + +{ + if( poGeometry == NULL || adfN == NULL ) + return; + OCSTransformer oTransformer( adfN ); // Promote to 3D, in case the OCS transformation introduces a @@ -490,12 +495,12 @@ CPLString OGRDXFLayer::TextUnescape( const char *pszInput, bool bIsMText ) /* TranslateMTEXT() */ /************************************************************************/ -OGRFeature *OGRDXFLayer::TranslateMTEXT() +OGRDXFFeature *OGRDXFLayer::TranslateMTEXT() { char szLineBuf[257]; int nCode = 0; - OGRFeature *poFeature = new OGRFeature( poFeatureDefn ); + OGRDXFFeature *poFeature = new OGRDXFFeature( poFeatureDefn ); double dfX = 0.0; double dfY = 0.0; double dfZ = 0.0; @@ -688,12 +693,12 @@ OGRFeature *OGRDXFLayer::TranslateMTEXT() /* TranslateTEXT() */ /************************************************************************/ -OGRFeature *OGRDXFLayer::TranslateTEXT() +OGRDXFFeature *OGRDXFLayer::TranslateTEXT() { char szLineBuf[257]; int nCode = 0; - OGRFeature *poFeature = new OGRFeature( poFeatureDefn ); + OGRDXFFeature *poFeature = new OGRDXFFeature( poFeatureDefn ); double dfX = 0.0; double dfY = 0.0; double dfZ = 0.0; @@ -917,12 +922,12 @@ OGRFeature *OGRDXFLayer::TranslateTEXT() /* TranslatePOINT() */ /************************************************************************/ -OGRFeature *OGRDXFLayer::TranslatePOINT() +OGRDXFFeature *OGRDXFLayer::TranslatePOINT() { char szLineBuf[257]; int nCode = 0; - OGRFeature *poFeature = new OGRFeature( poFeatureDefn ); + OGRDXFFeature *poFeature = new OGRDXFFeature( poFeatureDefn ); double dfX = 0.0; double dfY = 0.0; double dfZ = 0.0; @@ -978,12 +983,12 @@ OGRFeature *OGRDXFLayer::TranslatePOINT() /* TranslateLINE() */ /************************************************************************/ -OGRFeature *OGRDXFLayer::TranslateLINE() +OGRDXFFeature *OGRDXFLayer::TranslateLINE() { char szLineBuf[257]; int nCode = 0; - OGRFeature *poFeature = new OGRFeature( poFeatureDefn ); + OGRDXFFeature *poFeature = new OGRDXFFeature( poFeatureDefn ); double dfX1 = 0.0; double dfY1 = 0.0; double dfZ1 = 0.0; @@ -1065,7 +1070,7 @@ OGRFeature *OGRDXFLayer::TranslateLINE() /************************************************************************/ /* TranslateLWPOLYLINE() */ /************************************************************************/ -OGRFeature *OGRDXFLayer::TranslateLWPOLYLINE() +OGRDXFFeature *OGRDXFLayer::TranslateLWPOLYLINE() { // Collect vertices and attributes into a smooth polyline. @@ -1076,7 +1081,7 @@ OGRFeature *OGRDXFLayer::TranslateLWPOLYLINE() int nCode = 0; int nPolylineFlag = 0; - OGRFeature *poFeature = new OGRFeature( poFeatureDefn ); + OGRDXFFeature *poFeature = new OGRDXFFeature( poFeatureDefn ); double dfX = 0.0; double dfY = 0.0; double dfZ = 0.0; @@ -1192,13 +1197,13 @@ OGRFeature *OGRDXFLayer::TranslateLWPOLYLINE() /* We also capture the following VERTEXes. */ /************************************************************************/ -OGRFeature *OGRDXFLayer::TranslatePOLYLINE() +OGRDXFFeature *OGRDXFLayer::TranslatePOLYLINE() { char szLineBuf[257]; int nCode = 0; int nPolylineFlag = 0; - OGRFeature *poFeature = new OGRFeature( poFeatureDefn ); + OGRDXFFeature *poFeature = new OGRDXFFeature( poFeatureDefn ); /* -------------------------------------------------------------------- */ /* Collect information from the POLYLINE object itself. */ @@ -1447,12 +1452,12 @@ OGRFeature *OGRDXFLayer::TranslatePOLYLINE() /* TranslateCIRCLE() */ /************************************************************************/ -OGRFeature *OGRDXFLayer::TranslateCIRCLE() +OGRDXFFeature *OGRDXFLayer::TranslateCIRCLE() { char szLineBuf[257]; int nCode = 0; - OGRFeature *poFeature = new OGRFeature( poFeatureDefn ); + OGRDXFFeature *poFeature = new OGRDXFFeature( poFeatureDefn ); double dfX1 = 0.0; double dfY1 = 0.0; double dfZ1 = 0.0; @@ -1521,12 +1526,12 @@ OGRFeature *OGRDXFLayer::TranslateCIRCLE() /* TranslateELLIPSE() */ /************************************************************************/ -OGRFeature *OGRDXFLayer::TranslateELLIPSE() +OGRDXFFeature *OGRDXFLayer::TranslateELLIPSE() { char szLineBuf[257]; int nCode = 0; - OGRFeature *poFeature = new OGRFeature( poFeatureDefn ); + OGRDXFFeature *poFeature = new OGRDXFFeature( poFeatureDefn ); double dfX1 = 0.0; double dfY1 = 0.0; double dfZ1 = 0.0; @@ -1680,12 +1685,12 @@ OGRFeature *OGRDXFLayer::TranslateELLIPSE() /* TranslateARC() */ /************************************************************************/ -OGRFeature *OGRDXFLayer::TranslateARC() +OGRDXFFeature *OGRDXFLayer::TranslateARC() { char szLineBuf[257]; int nCode = 0; - OGRFeature *poFeature = new OGRFeature( poFeatureDefn ); + OGRDXFFeature *poFeature = new OGRDXFFeature( poFeatureDefn ); double dfX1 = 0.0; double dfY1 = 0.0; double dfZ1 = 0.0; @@ -1779,7 +1784,7 @@ OGRFeature *OGRDXFLayer::TranslateARC() void rbspline2(int npts,int k,int p1,double b[],double h[], bool bCalculateKnots, double knots[], double p[]); -OGRFeature *OGRDXFLayer::TranslateSPLINE() +OGRDXFFeature *OGRDXFLayer::TranslateSPLINE() { char szLineBuf[257]; @@ -1791,7 +1796,7 @@ OGRFeature *OGRDXFLayer::TranslateSPLINE() int nKnots = -1; bool bResult = false; bool bCalculateKnots = false; - OGRFeature *poFeature = new OGRFeature( poFeatureDefn ); + OGRDXFFeature *poFeature = new OGRDXFFeature( poFeatureDefn ); std::vector adfControlPoints; std::vector adfKnots; std::vector adfWeights; @@ -1976,12 +1981,12 @@ OGRFeature *OGRDXFLayer::TranslateSPLINE() /* Translate3DFACE() */ /************************************************************************/ -OGRFeature *OGRDXFLayer::Translate3DFACE() +OGRDXFFeature *OGRDXFLayer::Translate3DFACE() { char szLineBuf[257]; int nCode = 0; - OGRFeature *poFeature = new OGRFeature( poFeatureDefn ); + OGRDXFFeature *poFeature = new OGRDXFFeature( poFeatureDefn ); double dfX1 = 0.0; double dfY1 = 0.0; double dfZ1 = 0.0; @@ -2116,13 +2121,13 @@ static bool PointXYZEqualityComparer(const OGRPoint& oP1, const OGRPoint& oP2) /* TranslateSOLID() */ /************************************************************************/ -OGRFeature *OGRDXFLayer::TranslateSOLID() +OGRDXFFeature *OGRDXFLayer::TranslateSOLID() { CPLDebug("SOLID", "translating solid"); char szLineBuf[257]; int nCode = 0; - OGRFeature *poFeature = new OGRFeature(poFeatureDefn); + OGRDXFFeature *poFeature = new OGRDXFFeature(poFeatureDefn); double dfX1 = 0.0; double dfY1 = 0.0; double dfZ1 = 0.0; @@ -2285,36 +2290,179 @@ OGRFeature *OGRDXFLayer::TranslateSOLID() } /************************************************************************/ -/* InsertBlock() */ -/* */ -/* Inserts the given block at the location specified by the given */ -/* transformer. Returns poFeature, or NULL if bInline is true */ -/* and all block features have been pushed to the pending feature */ -/* stack. Throws std::invalid_argument if the requested block */ -/* doesn't exist. */ +/* SimplifyBlockGeometry() */ /************************************************************************/ -OGRFeature *OGRDXFLayer::InsertBlock( const CPLString& osBlockName, - OGRDXFInsertTransformer oTransformer, OGRFeature* const poFeature, - const bool bInline ) +OGRGeometry *OGRDXFLayer::SimplifyBlockGeometry( + OGRGeometryCollection *poCollection ) { /* -------------------------------------------------------------------- */ -/* In the case where we do not inline blocks, we just capture */ -/* info on a point feature. */ +/* If there is only one geometry in the collection, just return */ +/* it. */ +/* -------------------------------------------------------------------- */ + if( poCollection->getNumGeometries() == 1 ) + { + OGRGeometry *poReturn = poCollection->getGeometryRef(0); + poCollection->removeGeometry(0, FALSE); + delete poCollection; + return poReturn; + } + +/* -------------------------------------------------------------------- */ +/* Convert to polygon, multipolygon, multilinestring or multipoint */ /* -------------------------------------------------------------------- */ - if( !bInline ) + + OGRwkbGeometryType eType = + wkbFlatten(poCollection->getGeometryRef(0)->getGeometryType()); + int i; + for(i=1;igetNumGeometries();i++) + { + if (wkbFlatten(poCollection->getGeometryRef(i)->getGeometryType()) + != eType) + { + eType = wkbUnknown; + break; + } + } + if (eType == wkbPoint || eType == wkbLineString) + { + OGRGeometryCollection* poNewColl; + if (eType == wkbPoint) + poNewColl = new OGRMultiPoint(); + else + poNewColl = new OGRMultiLineString(); + while(poCollection->getNumGeometries() > 0) + { + OGRGeometry *poGeom = poCollection->getGeometryRef(0); + poCollection->removeGeometry(0,FALSE); + poNewColl->addGeometryDirectly(poGeom); + } + delete poCollection; + return poNewColl; + } + else if (eType == wkbPolygon) { - poFeature->SetGeometryDirectly( new OGRPoint( oTransformer.dfXOffset, - oTransformer.dfYOffset, - oTransformer.dfZOffset ) ); + std::vector aosPolygons; + while(poCollection->getNumGeometries() > 0) + { + OGRGeometry *poGeom = poCollection->getGeometryRef(0); + poCollection->removeGeometry(0,FALSE); + aosPolygons.push_back(poGeom); + } + delete poCollection; + int bIsValidGeometry; + return OGRGeometryFactory::organizePolygons( + &aosPolygons[0], (int)aosPolygons.size(), + &bIsValidGeometry, NULL); + } - poFeature->SetField( "BlockName", osBlockName ); + return poCollection; +} - poFeature->SetField( "BlockAngle", oTransformer.dfAngle * 180 / M_PI ); - poFeature->SetField( "BlockScale", 3, &(oTransformer.dfXScale) ); +/************************************************************************/ +/* InsertBlockReference() */ +/* */ +/* Returns a point geometry located at the block's insertion */ +/* point. */ +/************************************************************************/ +OGRDXFFeature *OGRDXFLayer::InsertBlockReference( + const CPLString& osBlockName, + const OGRDXFInsertTransformer& oTransformer, + OGRDXFFeature* const poFeature ) +{ + // Store the block's properties in the special DXF-specific members + // on the feature object + poFeature->bIsBlockReference = true; + poFeature->osBlockName = osBlockName; + poFeature->dfBlockAngle = oTransformer.dfAngle * 180 / M_PI; + poFeature->adfBlockScale[0] = oTransformer.dfXScale; + poFeature->adfBlockScale[1] = oTransformer.dfYScale; + poFeature->adfBlockScale[2] = oTransformer.dfZScale; - return poFeature; + if( oStyleProperties.count("210_N.dX") != 0 + && oStyleProperties.count("220_N.dY") != 0 + && oStyleProperties.count("230_N.dZ") != 0 ) + { + poFeature->adfBlockOCS[0] = CPLAtof(oStyleProperties["210_N.dX"]); + poFeature->adfBlockOCS[1] = CPLAtof(oStyleProperties["220_N.dY"]); + poFeature->adfBlockOCS[2] = CPLAtof(oStyleProperties["230_N.dZ"]); } + else + { + poFeature->adfBlockOCS[0] = 0.0; + poFeature->adfBlockOCS[1] = 0.0; + poFeature->adfBlockOCS[2] = 1.0; + } + + poFeature->adfOriginalCoords[0] = oTransformer.dfXOffset; + poFeature->adfOriginalCoords[1] = oTransformer.dfYOffset; + poFeature->adfOriginalCoords[2] = oTransformer.dfZOffset; + + // Only if DXF_INLINE_BLOCKS is false should we ever need to expose these + // to the end user as fields. + if( poFeature->GetFieldIndex( "BlockName" ) != -1 ) + { + poFeature->SetField( "BlockName", poFeature->osBlockName ); + poFeature->SetField( "BlockAngle", poFeature->dfBlockAngle ); + poFeature->SetField( "BlockScale", 3, poFeature->adfBlockScale ); + poFeature->SetField( "BlockOCSNormal", 3, poFeature->adfBlockOCS ); + poFeature->SetField( "BlockOCSCoords", 3, poFeature->adfOriginalCoords ); + } + + // For convenience to the end user, the point geometry will be located + // at the WCS coordinates of the insertion point. + OGRPoint* poInsertionPoint = new OGRPoint( oTransformer.dfXOffset, + oTransformer.dfYOffset, oTransformer.dfZOffset ); + + ApplyOCSTransformer( poInsertionPoint ); + poFeature->SetGeometryDirectly( poInsertionPoint ); + + return poFeature; +} + +/************************************************************************/ +/* InsertBlockInline() */ +/* */ +/* Inserts the given block at the location specified by the given */ +/* transformer. Returns poFeature, or NULL if all features on */ +/* the block have been pushed to the extra feature queue. */ +/* If poFeature is not returned, it is deleted. */ +/* Throws std::invalid_argument if the requested block */ +/* doesn't exist. */ +/* */ +/* - adfOCS: The OCS to apply to this block, or NULL if we */ +/* should use this layer's current OCS. */ +/* - bInlineRecursively: If true, INSERTs within this block */ +/* will be recursively inserted. Otherwise, they will be */ +/* represented as a point geometry using InsertInlineBlock. */ +/* - bMergeGeometry: If true, all features in the block, */ +/* apart from text features, are merged into a */ +/* GeometryCollection which is returned by the function. */ +/************************************************************************/ + +OGRDXFFeature *OGRDXFLayer::InsertBlockInline( const CPLString& osBlockName, + OGRDXFInsertTransformer oTransformer, + double adfOCS[3], + OGRDXFFeature* const poFeature, + std::queue& apoExtraFeatures, + const bool bInlineRecursively, + const bool bMergeGeometry ) +{ +/* -------------------------------------------------------------------- */ +/* Transform the insertion point from OCS into */ +/* world coordinates. */ +/* -------------------------------------------------------------------- */ + OGRPoint oInsertionPoint( oTransformer.dfXOffset, oTransformer.dfYOffset, + oTransformer.dfZOffset ); + + if( adfOCS ) + ApplyOCSTransformer( &oInsertionPoint, adfOCS ); + else + ApplyOCSTransformer( &oInsertionPoint ); + + oTransformer.dfXOffset = oInsertionPoint.getX(); + oTransformer.dfYOffset = oInsertionPoint.getY(); + oTransformer.dfZOffset = oInsertionPoint.getZ(); /* -------------------------------------------------------------------- */ /* Lookup the block. */ @@ -2327,115 +2475,193 @@ OGRFeature *OGRDXFLayer::InsertBlock( const CPLString& osBlockName, throw std::invalid_argument("osBlockName"); } -/* -------------------------------------------------------------------- */ -/* Transform the geometry. */ -/* -------------------------------------------------------------------- */ - if( poBlock->poGeometry != NULL ) - { - OGRGeometry *poGeometry = poBlock->poGeometry->clone(); - - { - OGRDXFInsertTransformer oSubTransformer( - oTransformer.GetRotateScaleTransformer() ); - poGeometry->transform( &oSubTransformer ); - } - ApplyOCSTransformer( poGeometry ); - { - OGRDXFInsertTransformer oSubTransformer( - oTransformer.GetOffsetTransformer() ); - poGeometry->transform( &oSubTransformer ); - } - - poFeature->SetGeometryDirectly( poGeometry ); - } - /* -------------------------------------------------------------------- */ /* If we have complete features associated with the block, push */ /* them on the pending feature stack copying over key override */ /* information. */ /* */ -/* Note that while we transform the geometry of the features we */ -/* don't adjust subtle things like text angle. */ +/* If bMergeGeometry is true, we merge the features */ +/* (except text) into a single GeometryCollection. */ /* -------------------------------------------------------------------- */ + OGRGeometryCollection *poMergedGeometry = NULL; + if( bMergeGeometry ) + poMergedGeometry = new OGRGeometryCollection(); + + std::queue apoInnerExtraFeatures; + for( unsigned int iSubFeat = 0; - iSubFeat < poBlock->apoFeatures.size(); - iSubFeat++ ) + iSubFeat < poBlock->apoFeatures.size(); + iSubFeat++ ) { - OGRFeature *poSubFeature = poBlock->apoFeatures[iSubFeat]->Clone(); - CPLString osCompEntityId; + OGRDXFFeature *poSubFeature = + poBlock->apoFeatures[iSubFeat]->CloneDXFFeature(); - OGRGeometry *poSubFeatGeom = poSubFeature->GetGeometryRef(); - if( poSubFeatGeom != NULL ) + // Does this feature represent a block that we inlined? If so, + // insert that block + if( bInlineRecursively && poSubFeature->IsBlockReference() ) { + // Unpack the transformation data stored in fields of this + // feature + OGRDXFInsertTransformer oInnerTransformer; + oInnerTransformer.dfXOffset = poSubFeature->adfOriginalCoords[0]; + oInnerTransformer.dfYOffset = poSubFeature->adfOriginalCoords[1]; + oInnerTransformer.dfZOffset = poSubFeature->adfOriginalCoords[2]; + oInnerTransformer.dfAngle = poSubFeature->dfBlockAngle * M_PI / 180; + oInnerTransformer.dfXScale = poSubFeature->adfBlockScale[0]; + oInnerTransformer.dfYScale = poSubFeature->adfBlockScale[1]; + oInnerTransformer.dfZScale = poSubFeature->adfBlockScale[2]; + + poSubFeature->bIsBlockReference = false; + + // Insert this block recursively + try + { + poSubFeature = InsertBlockInline( poSubFeature->osBlockName, + oInnerTransformer, poSubFeature->adfBlockOCS, + poSubFeature, apoInnerExtraFeatures, + true, bMergeGeometry ); + } + catch( const std::invalid_argument& ) { - OGRDXFInsertTransformer oSubTransformer( - oTransformer.GetRotateScaleTransformer() ); - poSubFeatGeom->transform( &oSubTransformer ); + // Block doesn't exist. Skip it and keep going + delete poSubFeature; + continue; } - ApplyOCSTransformer( poSubFeatGeom ); + + if( !poSubFeature ) { - OGRDXFInsertTransformer oSubTransformer( - oTransformer.GetOffsetTransformer() ); - poSubFeatGeom->transform( &oSubTransformer ); + if ( apoInnerExtraFeatures.empty() ) + { + // Block is empty. Skip it and keep going + continue; + } + else + { + // Load up the first extra feature ready for + // transformation + poSubFeature = apoInnerExtraFeatures.front(); + apoInnerExtraFeatures.pop(); + } } } - // If the subfeature is on layer 0, this is a special case: the - // subfeature should take on the style properties of the layer - // the block is being inserted onto - if( EQUAL( poSubFeature->GetFieldAsString( "Layer" ), "0" ) ) + // Go through the current feature and any extra features generated + // by the recursive insert, and apply transformations + while( true ) { - poSubFeature->SetField( "Layer", - poFeature->GetFieldAsString( "Layer" ) ); + OGRGeometry *poSubFeatGeom = poSubFeature->GetGeometryRef(); + if( poSubFeatGeom != NULL ) + { + // Rotation and scaling first + OGRDXFInsertTransformer oInnerTrans = + oTransformer.GetRotateScaleTransformer(); + poSubFeatGeom->transform( &oInnerTrans ); + + // Then the OCS to WCS transformation + if( adfOCS ) + ApplyOCSTransformer( poSubFeatGeom, adfOCS ); + else + ApplyOCSTransformer( poSubFeatGeom ); + + // Offset translation last + oInnerTrans = oTransformer.GetOffsetTransformer(); + poSubFeatGeom->transform( &oInnerTrans ); + } - // If it's a pen, then replace the style string - const char* pszSubFeatureStyle = poSubFeature->GetStyleString(); - if( pszSubFeatureStyle != NULL && - STARTS_WITH_CI(pszSubFeatureStyle, "PEN") ) + // If we are merging features, and this is not text or a block + // reference, merge it into the GeometryCollection + if( bMergeGeometry && + (poSubFeature->GetStyleString() == NULL || + strstr(poSubFeature->GetStyleString(),"LABEL") == NULL) && + !poSubFeature->IsBlockReference() && + poSubFeature->GetGeometryRef() ) + { + poMergedGeometry->addGeometry( poSubFeature->GetGeometryRef() ); + } + else { - PrepareLineStyle( poSubFeature ); + // If the subfeature is on layer 0, this is a special case: the + // subfeature should take on the style properties of the layer + // the block is being inserted onto. + // But don't do this if we are inserting onto a Blocks layer + // (that is, the owning feature has no layer). + if( EQUAL( poSubFeature->GetFieldAsString( "Layer" ), "0" ) && + !EQUAL( poFeature->GetFieldAsString( "Layer" ), "" ) ) + { + poSubFeature->SetField( "Layer", + poFeature->GetFieldAsString( "Layer" ) ); + + // If it's a pen, then replace the style string + const char* pszSubFeatureStyle = + poSubFeature->GetStyleString(); + if( pszSubFeatureStyle != NULL && + STARTS_WITH_CI(pszSubFeatureStyle, "PEN") ) + { + PrepareLineStyle( poSubFeature ); + } + + // TODO Do this for other style types (trac ticket #7099) + } + + ACAdjustText( oTransformer.dfAngle * 180 / M_PI, + oTransformer.dfXScale, poSubFeature ); + + if ( !EQUAL( poFeature->GetFieldAsString( "EntityHandle" ), "" ) ) + { + poSubFeature->SetField( "EntityHandle", + poFeature->GetFieldAsString( "EntityHandle" ) ); + } + + apoExtraFeatures.push( poSubFeature ); } - // TODO Do this for other style types (trac ticket #7099) + if( apoInnerExtraFeatures.empty() ) + { + break; + } + else + { + poSubFeature = apoInnerExtraFeatures.front(); + apoInnerExtraFeatures.pop(); + } } - - ACAdjustText( oTransformer.dfAngle * 180 / M_PI, - oTransformer.dfXScale, poSubFeature ); - - osCompEntityId += poFeature->GetFieldAsString( "EntityHandle" ); - poSubFeature->SetField( "EntityHandle", osCompEntityId ); - - apoPendingFeatures.push( poSubFeature ); } /* -------------------------------------------------------------------- */ -/* Return the working feature if we had geometry, otherwise */ +/* Return the merged geometry if applicable. Otherwise */ /* return NULL and let the machinery find the rest of the */ /* features in the pending feature stack. */ /* -------------------------------------------------------------------- */ - if( poBlock->poGeometry == NULL ) - { - delete poFeature; - return NULL; - } - else + if( bMergeGeometry ) { - // Set style pen color - PrepareLineStyle( poFeature ); - return poFeature; + if( poMergedGeometry->getNumGeometries() == 0 ) + { + delete poMergedGeometry; + } + else + { + poFeature->SetGeometryDirectly( + SimplifyBlockGeometry( poMergedGeometry ) ); + + PrepareLineStyle( poFeature ); + return poFeature; + } } + + delete poFeature; + return NULL; } /************************************************************************/ /* TranslateINSERT() */ /************************************************************************/ -OGRFeature *OGRDXFLayer::TranslateINSERT() +OGRDXFFeature *OGRDXFLayer::TranslateINSERT() { char szLineBuf[257]; int nCode = 0; - OGRFeature* poFeature = new OGRFeature( poFeatureDefn ); + OGRDXFFeature* poFeature = new OGRDXFFeature( poFeatureDefn ); OGRDXFInsertTransformer oTransformer; CPLString osBlockName; @@ -2495,18 +2721,19 @@ OGRFeature *OGRDXFLayer::TranslateINSERT() if( nCode == 0 ) poDS->UnreadValue(); - // Transform the insertion point into world coordinates - OGRPoint oInsertionPoint( oTransformer.dfXOffset, oTransformer.dfYOffset, - oTransformer.dfZOffset ); - ApplyOCSTransformer( &oInsertionPoint ); - oTransformer.dfXOffset = oInsertionPoint.getX(); - oTransformer.dfYOffset = oInsertionPoint.getY(); - oTransformer.dfZOffset = oInsertionPoint.getZ(); + // If we are not inlining blocks, just insert a point that refers + // to this block + if( !poDS->InlineBlocks() ) + { + return InsertBlockReference( osBlockName, oTransformer, poFeature ); + } + // Try inlining the contents of this block try { - poFeature = InsertBlock( osBlockName, oTransformer, poFeature, - poDS->InlineBlocks() ); + poFeature = InsertBlockInline( osBlockName, oTransformer, NULL, + poFeature, apoPendingFeatures, + true, poDS->ShouldMergeBlockGeometries() ); } catch( const std::invalid_argument& ) { @@ -2528,10 +2755,10 @@ OGRFeature *OGRDXFLayer::TranslateINSERT() /* GetNextUnfilteredFeature() */ /************************************************************************/ -OGRFeature *OGRDXFLayer::GetNextUnfilteredFeature() +OGRDXFFeature *OGRDXFLayer::GetNextUnfilteredFeature() { - OGRFeature *poFeature = NULL; + OGRDXFFeature *poFeature = NULL; /* -------------------------------------------------------------------- */ /* If we have pending features, return one of them. */ diff --git a/gdal/ogr/ogrsf_frmts/dxf/ogrdxfwriterds.cpp b/gdal/ogr/ogrsf_frmts/dxf/ogrdxfwriterds.cpp index b22681907a08..b20c635cc109 100644 --- a/gdal/ogr/ogrsf_frmts/dxf/ogrdxfwriterds.cpp +++ b/gdal/ogr/ogrsf_frmts/dxf/ogrdxfwriterds.cpp @@ -729,7 +729,7 @@ bool OGRDXFWriterDS::WriteNewBlockRecords( VSILFILE * fpIn ) /* -------------------------------------------------------------------- */ /* Is this block already defined in the template header? */ /* -------------------------------------------------------------------- */ - CPLString osBlockName = poThisBlockFeat->GetFieldAsString("BlockName"); + CPLString osBlockName = poThisBlockFeat->GetFieldAsString("Block"); if( oHeaderDS.LookupBlock( osBlockName ) != NULL ) continue; @@ -749,7 +749,7 @@ bool OGRDXFWriterDS::WriteNewBlockRecords( VSILFILE * fpIn ) WriteEntityID( fpIn ); WriteValue( fpIn, 100, "AcDbSymbolTableRecord" ); WriteValue( fpIn, 100, "AcDbBlockTableRecord" ); - WriteValue( fpIn, 2, poThisBlockFeat->GetFieldAsString("BlockName") ); + WriteValue( fpIn, 2, poThisBlockFeat->GetFieldAsString("Block") ); if( !WriteValue( fpIn, 340, "0" ) ) return false; } @@ -778,7 +778,7 @@ bool OGRDXFWriterDS::WriteNewBlockDefinitions( VSILFILE * fpIn ) /* -------------------------------------------------------------------- */ /* Is this block already defined in the template header? */ /* -------------------------------------------------------------------- */ - CPLString osBlockName = poThisBlockFeat->GetFieldAsString("BlockName"); + CPLString osBlockName = poThisBlockFeat->GetFieldAsString("Block"); if( oHeaderDS.LookupBlock( osBlockName ) != NULL ) continue; @@ -787,7 +787,7 @@ bool OGRDXFWriterDS::WriteNewBlockDefinitions( VSILFILE * fpIn ) /* Write the block definition preamble. */ /* -------------------------------------------------------------------- */ CPLDebug( "DXF", "Writing BLOCK definition for '%s'.", - poThisBlockFeat->GetFieldAsString("BlockName") ); + poThisBlockFeat->GetFieldAsString("Block") ); WriteValue( fpIn, 0, "BLOCK" ); WriteEntityID( fpIn ); @@ -797,7 +797,7 @@ bool OGRDXFWriterDS::WriteNewBlockDefinitions( VSILFILE * fpIn ) else WriteValue( fpIn, 8, "0" ); WriteValue( fpIn, 100, "AcDbBlockBegin" ); - WriteValue( fpIn, 2, poThisBlockFeat->GetFieldAsString("BlockName") ); + WriteValue( fpIn, 2, poThisBlockFeat->GetFieldAsString("Block") ); WriteValue( fpIn, 70, "0" ); // Origin @@ -805,7 +805,7 @@ bool OGRDXFWriterDS::WriteNewBlockDefinitions( VSILFILE * fpIn ) WriteValue( fpIn, 20, "0.0" ); WriteValue( fpIn, 30, "0.0" ); - WriteValue( fpIn, 3, poThisBlockFeat->GetFieldAsString("BlockName") ); + WriteValue( fpIn, 3, poThisBlockFeat->GetFieldAsString("Block") ); WriteValue( fpIn, 1, "" ); /* -------------------------------------------------------------------- */ @@ -818,7 +818,7 @@ bool OGRDXFWriterDS::WriteNewBlockDefinitions( VSILFILE * fpIn ) /* Write out following features if they are the same block. */ /* -------------------------------------------------------------------- */ while( iBlock < poBlocksLayer->apoBlocks.size()-1 - && EQUAL(poBlocksLayer->apoBlocks[iBlock+1]->GetFieldAsString("BlockName"), + && EQUAL(poBlocksLayer->apoBlocks[iBlock+1]->GetFieldAsString("Block"), osBlockName) ) { iBlock++; diff --git a/gdal/ogr/ogrsf_frmts/dxf/ogrdxfwriterlayer.cpp b/gdal/ogr/ogrsf_frmts/dxf/ogrdxfwriterlayer.cpp index a3788ea51b93..99bfc3f2a0c4 100644 --- a/gdal/ogr/ogrsf_frmts/dxf/ogrdxfwriterlayer.cpp +++ b/gdal/ogr/ogrsf_frmts/dxf/ogrdxfwriterlayer.cpp @@ -70,14 +70,23 @@ OGRDXFWriterLayer::OGRDXFWriterLayer( OGRDXFWriterDS *poDSIn, VSILFILE *fpIn ) : OGRFieldDefn oTextField( "Text", OFTString ); poFeatureDefn->AddFieldDefn( &oTextField ); - OGRFieldDefn oBlockField( "BlockName", OFTString ); - poFeatureDefn->AddFieldDefn( &oBlockField ); + OGRFieldDefn oBlockNameField( "BlockName", OFTString ); + poFeatureDefn->AddFieldDefn( &oBlockNameField ); OGRFieldDefn oScaleField( "BlockScale", OFTRealList ); poFeatureDefn->AddFieldDefn( &oScaleField ); OGRFieldDefn oBlockAngleField( "BlockAngle", OFTReal ); poFeatureDefn->AddFieldDefn( &oBlockAngleField ); + + OGRFieldDefn oBlockOCSNormalField( "BlockOCSNormal", OFTRealList ); + poFeatureDefn->AddFieldDefn( &oBlockOCSNormalField ); + + OGRFieldDefn oBlockOCSCoordsField( "BlockOCSCoords", OFTRealList ); + poFeatureDefn->AddFieldDefn( &oBlockOCSCoordsField ); + + OGRFieldDefn oBlockField( "Block", OFTString ); + poFeatureDefn->AddFieldDefn( &oBlockField ); } /************************************************************************/ @@ -285,18 +294,34 @@ OGRErr OGRDXFWriterLayer::WriteINSERT( OGRFeature *poFeature ) delete poTool; /* -------------------------------------------------------------------- */ -/* Write location. */ +/* Write location in OCS. */ /* -------------------------------------------------------------------- */ - OGRPoint *poPoint = (OGRPoint *) poFeature->GetGeometryRef(); - - WriteValue( 10, poPoint->getX() ); - if( !WriteValue( 20, poPoint->getY() ) ) - return OGRERR_FAILURE; + int nCoordCount = 0; + const double *padfCoords = + poFeature->GetFieldAsDoubleList( "BlockOCSCoords", &nCoordCount ); - if( poPoint->getGeometryType() == wkbPoint25D ) + if( nCoordCount == 3 ) { - if( !WriteValue( 30, poPoint->getZ() ) ) + WriteValue( 10, padfCoords[0] ); + WriteValue( 20, padfCoords[1] ); + if( !WriteValue( 30, padfCoords[2] ) ) + return OGRERR_FAILURE; + } + else + { + // We don't have an OCS; we will just assume that the location of + // the geometry (in WCS) is the correct insertion point. + OGRPoint *poPoint = (OGRPoint *) poFeature->GetGeometryRef(); + + WriteValue( 10, poPoint->getX() ); + if( !WriteValue( 20, poPoint->getY() ) ) return OGRERR_FAILURE; + + if( poPoint->getGeometryType() == wkbPoint25D ) + { + if( !WriteValue( 30, poPoint->getZ() ) ) + return OGRERR_FAILURE; + } } /* -------------------------------------------------------------------- */ @@ -323,6 +348,20 @@ OGRErr OGRDXFWriterLayer::WriteINSERT( OGRFeature *poFeature ) WriteValue( 50, dfAngle ); // degrees } +/* -------------------------------------------------------------------- */ +/* Write OCS normal vector. */ +/* -------------------------------------------------------------------- */ + int nOCSCount = 0; + const double *padfOCS = + poFeature->GetFieldAsDoubleList( "BlockOCSNormal", &nOCSCount ); + + if( nOCSCount == 3 ) + { + WriteValue( 210, padfOCS[0] ); + WriteValue( 220, padfOCS[1] ); + WriteValue( 230, padfOCS[2] ); + } + return OGRERR_NONE; } @@ -1109,12 +1148,6 @@ OGRErr OGRDXFWriterLayer::ICreateFeature( OGRFeature *poFeature ) { const char *pszBlockName = poFeature->GetFieldAsString("BlockName"); - // we don't want to treat as a block ref if we are writing blocks layer - if( pszBlockName != NULL - && poDS->poBlocksLayer != NULL - && poFeature->GetDefnRef() == poDS->poBlocksLayer->GetLayerDefn()) - pszBlockName = NULL; - // We don't want to treat as a blocks ref if the block is not defined if( pszBlockName && poDS->oHeaderDS.LookupBlock(pszBlockName) == NULL )