1 /*******************************************************************************
2 * Project: libopencad
3 * Purpose: OpenSource CAD formats support library
4 * Author: Alexandr Borzykh, mush3d at gmail.com
5 * Author: Dmitry Baryshnikov, bishop.dev@gmail.com
6 * Language: C++
7 *******************************************************************************
8 * The MIT License (MIT)
9 *
10 * Copyright (c) 2016 Alexandr Borzykh
11 * Copyright (c) 2016-2018 NextGIS, <info@nextgis.com>
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining a copy
14 * of this software and associated documentation files (the "Software"), to deal
15 * in the Software without restriction, including without limitation the rights
16 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 * copies of the Software, and to permit persons to whom the Software is
18 * furnished to do so, subject to the following conditions:
19 *
20 * The above copyright notice and this permission notice shall be included in all
21 * copies or substantial portions of the Software.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 * SOFTWARE.
30 *******************************************************************************/
31 #include "cadtables.h"
32 #include "opencad_api.h"
33
34 #include <cassert>
35 #include <iostream>
36 #include <memory>
37 #include <set>
38
39 using namespace std;
40
CADTables()41 CADTables::CADTables()
42 {
43 }
44
AddTable(TableType eType,const CADHandle & hHandle)45 void CADTables::AddTable( TableType eType, const CADHandle& hHandle )
46 {
47 mapTables[eType] = hHandle;
48 }
49
ReadTable(CADFile * const pCADFile,CADTables::TableType eType)50 int CADTables::ReadTable( CADFile * const pCADFile, CADTables::TableType eType )
51 {
52 auto iterAskedTable = mapTables.find( eType );
53 if( iterAskedTable == mapTables.end() )
54 return CADErrorCodes::TABLE_READ_FAILED;
55
56 // TODO: read different tables
57 switch( eType )
58 {
59 case LayersTable:
60 return ReadLayersTable( pCADFile, iterAskedTable->second.getAsLong() );
61 default:
62 std::cerr << "Unsupported table.";
63 break;
64 }
65
66 return CADErrorCodes::SUCCESS;
67 }
68
GetLayerCount() const69 size_t CADTables::GetLayerCount() const
70 {
71 return aLayers.size();
72 }
73
GetLayer(size_t iIndex)74 CADLayer& CADTables::GetLayer( size_t iIndex )
75 {
76 return aLayers[iIndex];
77 }
78
GetTableHandle(enum TableType eType)79 CADHandle CADTables::GetTableHandle( enum TableType eType )
80 {
81 // FIXME: need to add try/catch to prevent crashes on not found elem.
82 return mapTables[eType];
83 }
84
ReadLayersTable(CADFile * const pCADFile,long dLayerControlHandle)85 int CADTables::ReadLayersTable( CADFile * const pCADFile, long dLayerControlHandle )
86 {
87 // Reading Layer Control obj, and aLayers.
88 unique_ptr<CADObject> pCADObject( pCADFile->GetObject( dLayerControlHandle ) );
89
90 CADLayerControlObject* spLayerControl =
91 dynamic_cast<CADLayerControlObject *>(pCADObject.get());
92 if( !spLayerControl )
93 {
94 return CADErrorCodes::TABLE_READ_FAILED;
95 }
96
97 for( size_t i = 0; i < spLayerControl->hLayers.size(); ++i )
98 {
99 if( !spLayerControl->hLayers[i].isNull() )
100 {
101 CADLayer oCADLayer( pCADFile );
102
103 // Init CADLayer from CADLayerObject properties
104 CADObject* pCADLayerObject = pCADFile->GetObject(
105 spLayerControl->hLayers[i].getAsLong() );
106 unique_ptr<CADLayerObject> oCADLayerObj(
107 dynamic_cast<CADLayerObject *>( pCADLayerObject ) );
108
109 if(oCADLayerObj)
110 {
111 oCADLayer.setName( oCADLayerObj->sLayerName );
112 oCADLayer.setFrozen( oCADLayerObj->bFrozen );
113 oCADLayer.setOn( oCADLayerObj->bOn );
114 oCADLayer.setFrozenByDefault( oCADLayerObj->bFrozenInNewVPORT );
115 oCADLayer.setLocked( oCADLayerObj->bLocked );
116 oCADLayer.setLineWeight( oCADLayerObj->dLineWeight );
117 oCADLayer.setColor( oCADLayerObj->dCMColor );
118 oCADLayer.setId( aLayers.size() + 1 );
119 oCADLayer.setHandle( oCADLayerObj->hObjectHandle.getAsLong() );
120
121 aLayers.push_back( oCADLayer );
122 }
123 else
124 {
125 delete pCADLayerObject;
126 }
127 }
128 }
129
130 auto iterBlockMS = mapTables.find( BlockRecordModelSpace );
131 if( iterBlockMS == mapTables.end() )
132 return CADErrorCodes::TABLE_READ_FAILED;
133
134 CADObject* pCADBlockObject = pCADFile->GetObject(
135 iterBlockMS->second.getAsLong() );
136 unique_ptr<CADBlockHeaderObject> spModelSpace(
137 dynamic_cast<CADBlockHeaderObject *>( pCADBlockObject ) );
138 if(!spModelSpace)
139 {
140 delete pCADBlockObject;
141 return CADErrorCodes::TABLE_READ_FAILED;
142 }
143
144 if(spModelSpace->hEntities.size() < 2)
145 {
146 return CADErrorCodes::TABLE_READ_FAILED;
147 }
148
149 auto dCurrentEntHandle = spModelSpace->hEntities[0].getAsLong();
150 auto dLastEntHandle = spModelSpace->hEntities[1].getAsLong();
151 // To avoid infinite loops
152 std::set<long> oVisitedHandles;
153 while( dCurrentEntHandle != 0 &&
154 oVisitedHandles.find(dCurrentEntHandle) == oVisitedHandles.end() )
155 {
156 oVisitedHandles.insert(dCurrentEntHandle);
157
158 CADObject* pCADEntityObject = pCADFile->GetObject( dCurrentEntHandle, true );
159 unique_ptr<CADEntityObject> spEntityObj(
160 dynamic_cast<CADEntityObject *>( pCADEntityObject ) );
161
162 if( !spEntityObj )
163 {
164 delete pCADEntityObject;
165 DebugMsg( "Entity object is null\n" );
166 break;
167 }
168 else if ( dCurrentEntHandle == dLastEntHandle )
169 {
170 FillLayer( spEntityObj.get() );
171 break;
172 }
173
174 FillLayer( spEntityObj.get() );
175
176 if( spEntityObj->stCed.bNoLinks )
177 {
178 ++dCurrentEntHandle;
179 }
180 else
181 {
182 dCurrentEntHandle = spEntityObj->stChed.hNextEntity.getAsLong( spEntityObj->stCed.hObjectHandle );
183 }
184 }
185
186 DebugMsg( "Read aLayers using LayerControl object count: %d\n",
187 static_cast<int>(aLayers.size()) );
188
189 return CADErrorCodes::SUCCESS;
190 }
191
FillLayer(const CADEntityObject * pEntityObject)192 void CADTables::FillLayer( const CADEntityObject * pEntityObject )
193 {
194 if(nullptr == pEntityObject)
195 {
196 return;
197 }
198
199 for( CADLayer& oLayer : aLayers )
200 {
201 if( pEntityObject->stChed.hLayer.getAsLong(
202 pEntityObject->stCed.hObjectHandle ) == oLayer.getHandle() )
203 {
204 DebugMsg( "Object with type: %s is attached to layer named: %s\n",
205 getNameByType( pEntityObject->getType() ).c_str(),
206 oLayer.getName().c_str() );
207
208 oLayer.addHandle( pEntityObject->stCed.hObjectHandle.getAsLong(),
209 pEntityObject->getType() );
210 break;
211 }
212 }
213 }
214