1 /******************************************************************************
2  *
3  * Project:  DWG Translator
4  * Purpose:  Implements BlockMap reading and management portion of
5  *           OGRDWGDataSource class
6  * Author:   Frank Warmerdam, warmerdam@pobox.com
7  *
8  ******************************************************************************
9  * Copyright (c) 2009, Frank Warmerdam <warmerdam@pobox.com>
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included
19  * in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  ****************************************************************************/
29 
30 #include "ogr_dwg.h"
31 #include "cpl_conv.h"
32 #include "cpl_string.h"
33 #include "cpl_csv.h"
34 
35 CPL_CVSID("$Id: ogrdwg_blockmap.cpp 7e07230bbff24eb333608de4dbd460b7312839d0 2017-12-11 19:08:47Z Even Rouault $")
36 
37 /************************************************************************/
38 /*                          ReadBlockSection()                          */
39 /************************************************************************/
40 
ReadBlocksSection()41 void OGRDWGDataSource::ReadBlocksSection()
42 
43 {
44     OGRDWGLayer *poReaderLayer = (OGRDWGLayer *) GetLayerByName( "Entities" );
45     int bMergeBlockGeometries = CPLTestBool(
46         CPLGetConfigOption( "DWG_MERGE_BLOCK_GEOMETRIES", "TRUE" ) );
47 
48 /* -------------------------------------------------------------------- */
49 /*      Loop over all the block tables, skipping *Model_Space which     */
50 /*      we assume is primary entities.                                  */
51 /* -------------------------------------------------------------------- */
52     OdDbBlockTableRecordPtr  poModelSpace, poBlock;
53     OdDbBlockTablePtr pTable = GetDB()->getBlockTableId().safeOpenObject();
54     OdDbSymbolTableIteratorPtr pBlkIter = pTable->newIterator();
55 
56     for (pBlkIter->start(); ! pBlkIter->done(); pBlkIter->step())
57     {
58         poBlock = pBlkIter->getRecordId().safeOpenObject();
59         CPLString osBlockName = (const char *) poBlock->getName();
60 
61         if( EQUAL(osBlockName,"*Model_Space") )
62         {
63             poModelSpace = poBlock;
64             continue;
65         }
66 
67         poReaderLayer->SetBlockTable( poBlock );
68 
69         // Now we will process entities till we run out.
70         // We aggregate the geometries of the features into a multi-geometry,
71         // but throw away other stuff attached to the features.
72 
73         OGRFeature *poFeature = nullptr;
74         OGRGeometryCollection *poColl = new OGRGeometryCollection();
75         std::vector<OGRFeature*> apoFeatures;
76 
77         while( (poFeature = poReaderLayer->GetNextUnfilteredFeature()) != nullptr )
78         {
79             if( (poFeature->GetStyleString() != nullptr
80                  && strstr(poFeature->GetStyleString(),"LABEL") != nullptr)
81                 || !bMergeBlockGeometries )
82             {
83                 apoFeatures.push_back( poFeature );
84             }
85             else
86             {
87                 poColl->addGeometryDirectly( poFeature->StealGeometry() );
88                 delete poFeature;
89             }
90         }
91 
92         if( poColl->getNumGeometries() == 0 )
93             delete poColl;
94         else
95             oBlockMap[osBlockName].poGeometry = SimplifyBlockGeometry(poColl);
96 
97         if( !apoFeatures.empty() )
98             oBlockMap[osBlockName].apoFeatures = apoFeatures;
99     }
100 
101     CPLDebug( "DWG", "Read %d blocks with meaningful geometry.",
102               (int) oBlockMap.size() );
103 
104     poReaderLayer->SetBlockTable( poModelSpace );
105 }
106 
107 /************************************************************************/
108 /*                       SimplifyBlockGeometry()                        */
109 /************************************************************************/
110 
SimplifyBlockGeometry(OGRGeometryCollection * poCollection)111 OGRGeometry *OGRDWGDataSource::SimplifyBlockGeometry(
112     OGRGeometryCollection *poCollection )
113 
114 {
115 /* -------------------------------------------------------------------- */
116 /*      If there is only one geometry in the collection, just return    */
117 /*      it.                                                             */
118 /* -------------------------------------------------------------------- */
119     if( poCollection->getNumGeometries() == 1 )
120     {
121         OGRGeometry *poReturn = poCollection->getGeometryRef(0);
122         poCollection->removeGeometry(0,FALSE);
123         delete poCollection;
124         return poReturn;
125     }
126 
127 /* -------------------------------------------------------------------- */
128 /*      Eventually we likely ought to have logic to convert to          */
129 /*      polygon, multipolygon, multilinestring or multipoint but        */
130 /*      I'll put that off till it would be meaningful.                  */
131 /* -------------------------------------------------------------------- */
132 
133     return poCollection;
134 }
135 
136 /************************************************************************/
137 /*                            LookupBlock()                             */
138 /*                                                                      */
139 /*      Find the geometry collection corresponding to a name if it      */
140 /*      exists.  Note that the returned geometry pointer is to a        */
141 /*      geometry that continues to be owned by the datasource.  It      */
142 /*      should be cloned for use.                                       */
143 /************************************************************************/
144 
LookupBlock(const char * pszName)145 DWGBlockDefinition *OGRDWGDataSource::LookupBlock( const char *pszName )
146 
147 {
148     CPLString osName = pszName;
149 
150     if( oBlockMap.count( osName ) == 0 )
151         return nullptr;
152     else
153         return &(oBlockMap[osName]);
154 }
155 
156 /************************************************************************/
157 /*                        ~DWGBlockDefinition()                         */
158 /*                                                                      */
159 /*      Safe cleanup of a block definition.                             */
160 /************************************************************************/
161 
~DWGBlockDefinition()162 DWGBlockDefinition::~DWGBlockDefinition()
163 
164 {
165     delete poGeometry;
166 
167     while( !apoFeatures.empty() )
168     {
169         delete apoFeatures.back();
170         apoFeatures.pop_back();
171     }
172 }
173