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 "cadlayer.h"
32 #include "cadfile.h"
33
34 #include <cassert>
35 #include <iostream>
36 #include <algorithm>
37
CADLayer(CADFile * file)38 CADLayer::CADLayer( CADFile * file ) :
39 frozen( false ),
40 on( true ),
41 frozenByDefault( false ),
42 locked( false ),
43 plotting( false ),
44 lineWeight( 1 ),
45 color( 0 ),
46 layerId( 0 ),
47 layer_handle( 0 ),
48 pCADFile( file )
49 {
50 }
51
getName() const52 std::string CADLayer::getName() const
53 {
54 return layerName;
55 }
56
setName(const std::string & value)57 void CADLayer::setName( const std::string& value )
58 {
59 layerName = value;
60 }
61
getFrozen() const62 bool CADLayer::getFrozen() const
63 {
64 return frozen;
65 }
66
setFrozen(bool value)67 void CADLayer::setFrozen( bool value )
68 {
69 frozen = value;
70 }
71
getOn() const72 bool CADLayer::getOn() const
73 {
74 return on;
75 }
76
setOn(bool value)77 void CADLayer::setOn( bool value )
78 {
79 on = value;
80 }
81
getFrozenByDefault() const82 bool CADLayer::getFrozenByDefault() const
83 {
84 return frozenByDefault;
85 }
86
setFrozenByDefault(bool value)87 void CADLayer::setFrozenByDefault( bool value )
88 {
89 frozenByDefault = value;
90 }
91
getLocked() const92 bool CADLayer::getLocked() const
93 {
94 return locked;
95 }
96
setLocked(bool value)97 void CADLayer::setLocked( bool value )
98 {
99 locked = value;
100 }
101
getPlotting() const102 bool CADLayer::getPlotting() const
103 {
104 return plotting;
105 }
106
setPlotting(bool value)107 void CADLayer::setPlotting( bool value )
108 {
109 plotting = value;
110 }
111
getLineWeight() const112 short CADLayer::getLineWeight() const
113 {
114 return lineWeight;
115 }
116
setLineWeight(short value)117 void CADLayer::setLineWeight( short value )
118 {
119 lineWeight = value;
120 }
121
getColor() const122 short CADLayer::getColor() const
123 {
124 return color;
125 }
126
setColor(short value)127 void CADLayer::setColor( short value )
128 {
129 color = value;
130 }
131
getId() const132 size_t CADLayer::getId() const
133 {
134 return layerId;
135 }
136
setId(const size_t & value)137 void CADLayer::setId( const size_t& value )
138 {
139 layerId = value;
140 }
141
getHandle() const142 long CADLayer::getHandle() const
143 {
144 return layer_handle;
145 }
146
setHandle(long value)147 void CADLayer::setHandle( long value )
148 {
149 layer_handle = value;
150 }
151
addHandle(long handle,CADObject::ObjectType type,long cadinserthandle)152 void CADLayer::addHandle( long handle, CADObject::ObjectType type, long cadinserthandle )
153 {
154 #ifdef _DEBUG
155 std::cout << "addHandle: " << handle << " type: " << type << "\n";
156 #endif //_DEBUG
157 if( type == CADObject::ATTRIB || type == CADObject::ATTDEF )
158 {
159 auto pCADGeometryPtr = pCADFile->GetGeometry( getId() - 1, handle );
160 std::unique_ptr<CADGeometry> pCADGeometry( pCADGeometryPtr );
161 CADAttdef* attdef = dynamic_cast<CADAttdef*>(pCADGeometry.get());
162 if(attdef)
163 {
164 attributesNames.insert( attdef->getTag() );
165 }
166 }
167
168 if( type == CADObject::INSERT )
169 {
170 // TODO: transform insert to block of objects (do we need to transform
171 // coordinates according to insert point)?
172 auto insertPtr = pCADFile->GetObject( handle, false );
173 std::unique_ptr<CADObject> insert( insertPtr );
174 CADInsertObject * pInsert = dynamic_cast<CADInsertObject *>(insert.get());
175 if( nullptr != pInsert )
176 {
177 std::unique_ptr<CADObject> blockHeader( pCADFile->GetObject(
178 pInsert->hBlockHeader.getAsLong(), false ) );
179 CADBlockHeaderObject * pBlockHeader =
180 dynamic_cast<CADBlockHeaderObject *>(blockHeader.get());
181 if( nullptr != pBlockHeader )
182 {
183 #ifdef _DEBUG
184 if( pBlockHeader->bBlkisXRef )
185 {
186 assert( 0 );
187 }
188 #endif //_DEBUG
189 auto dCurrentEntHandle = pBlockHeader->hEntities[0].getAsLong();
190 auto dLastEntHandle = pBlockHeader->hEntities.back().getAsLong(); // FIXME: in 2000+ entities probably has no links to each other.
191
192 if( dCurrentEntHandle == dLastEntHandle ) // Blocks can be empty (contain no objects)
193 {
194 return;
195 }
196
197 while( true )
198 {
199 std::unique_ptr<CADObject> entity(pCADFile->GetObject(
200 dCurrentEntHandle, true ));
201 CADEntityObject* pEntity =
202 dynamic_cast<CADEntityObject *>( entity.get() );
203
204 if( dCurrentEntHandle == dLastEntHandle )
205 {
206 if( nullptr != pEntity )
207 {
208 addHandle( dCurrentEntHandle, pEntity->getType(), handle );
209 Matrix mat;
210 mat.translate( pInsert->vertInsertionPoint );
211 mat.scale( pInsert->vertScales );
212 mat.rotate( pInsert->dfRotation );
213 transformations[dCurrentEntHandle] = mat;
214 break;
215 }
216 else
217 {
218 assert( 0 );
219 }
220 }
221
222 if( nullptr != pEntity )
223 {
224 addHandle( dCurrentEntHandle, pEntity->getType(), handle );
225 Matrix mat;
226 mat.translate( pInsert->vertInsertionPoint );
227 mat.scale( pInsert->vertScales );
228 mat.rotate( pInsert->dfRotation );
229 transformations[dCurrentEntHandle] = mat;
230
231 if( pEntity->stCed.bNoLinks )
232 {
233 ++dCurrentEntHandle;
234 }
235 else
236 {
237 dCurrentEntHandle =
238 pEntity->stChed.hNextEntity.getAsLong(
239 pEntity->stCed.hObjectHandle );
240 }
241 }
242 else
243 {
244 assert ( 0 );
245 }
246 }
247 }
248 }
249 return;
250 }
251
252 if( isCommonEntityType( type ) )
253 {
254 if( type == CADObject::IMAGE )
255 {
256 imageHandles.push_back( handle );
257 }
258 else
259 {
260 if( pCADFile->isReadingUnsupportedGeometries() == false )
261 {
262 if( isSupportedGeometryType( type ) )
263 {
264 if( geometryTypes.empty() )
265 {
266 geometryTypes.push_back( type );
267 }
268
269 if( find( geometryTypes.begin(), geometryTypes.end(), type ) ==
270 geometryTypes.end() )
271 {
272 geometryTypes.push_back( type );
273 }
274 geometryHandles.push_back(
275 std::make_pair( handle, cadinserthandle ) );
276 }
277 }
278 else
279 {
280 if( geometryTypes.empty() )
281 {
282 geometryTypes.push_back( type );
283 }
284
285 if( find( geometryTypes.begin(), geometryTypes.end(), type ) ==
286 geometryTypes.end() )
287 {
288 geometryTypes.push_back( type );
289 }
290 geometryHandles.push_back(
291 std::make_pair( handle, cadinserthandle ) );
292 }
293 }
294 }
295 }
296
getGeometryCount() const297 size_t CADLayer::getGeometryCount() const
298 {
299 return geometryHandles.size();
300 }
301
getGeometry(size_t index)302 CADGeometry * CADLayer::getGeometry( size_t index )
303 {
304 auto handleBlockRefPair = geometryHandles[index];
305 CADGeometry * pGeom = pCADFile->GetGeometry( this->getId() - 1,
306 handleBlockRefPair.first, handleBlockRefPair.second );
307 if( nullptr == pGeom )
308 return nullptr;
309 auto iter = transformations.find( handleBlockRefPair.first );
310 if( iter != transformations.end() )
311 {
312 // transform geometry if nHandle is in transformations
313 pGeom->transform( iter->second );
314 }
315 return pGeom;
316 }
317
getImageCount() const318 size_t CADLayer::getImageCount() const
319 {
320 return imageHandles.size();
321 }
322
getImage(size_t index)323 CADImage * CADLayer::getImage( size_t index )
324 {
325 return static_cast<CADImage *>(pCADFile->GetGeometry( this->getId() - 1,
326 imageHandles[index] ));
327 }
328
addAttribute(const CADObject * pObject)329 bool CADLayer::addAttribute( const CADObject * pObject )
330 {
331 if( nullptr == pObject )
332 return true;
333
334 auto attrib = static_cast<const CADAttribObject *>(pObject);
335 for( auto i = geometryAttributes.begin(); i != geometryAttributes.end(); ++i )
336 {
337 if( i->first == attrib->stChed.hOwner.getAsLong() )
338 {
339 i->second.insert( make_pair( attrib->sTag, layer_handle ) );
340 return true;
341 }
342 }
343
344 return false;
345 }
346
getGeometryTypes()347 std::vector<CADObject::ObjectType> CADLayer::getGeometryTypes()
348 {
349 return geometryTypes;
350 }
351
getAttributesTags()352 std::unordered_set<std::string> CADLayer::getAttributesTags()
353 {
354 return attributesNames;
355 }
356